documentScroller = function(el) {

    // Dimensions of the selection container
    var containerDimensions = $(el).data(pluginName).containerDimensions;

    // Browser window viewport dimensions
    var width = typeof(window.innerWidth) == 'number' ?
        window.innerWidth : document.documentElement.clientWidth;
    var height = typeof(window.innerHeight) == 'number' ?
        window.innerHeight : document.documentElement.clientHeight;

    // Browser document length
    var documentWidth = document.documentElement.scrollWidth,
        documentHeight = document.documentElement.scrollHeight;

    /**
     * @return {!Element} The DOM element which is scrolled when this scroller
     *     operates. For this scroller it's the documentElement or body.
     */
    function getScrollableElement() {
      return document.documentElement;
    }

    /**
     * Returns the top, right, bottom and left positions of the viewport
     * borders that should trigger scrolling when the selection box is dragged
     * close to them.
     *
     * @return {!Array.<number>} Positions of the scrolling viewport borders,
     *     respectively in the following order: top, right, bottom, left. All
     *     positions are relative to the top-left corner of the document.
     */
    function getScrollBorders() {
      var scrollTop = typeof(window.pageYOffset) == 'number' ?
          window.pageYOffset : document.documentElement.scrollTop;
      var scrollLeft = typeof(window.pageXOffset) == 'number' ?
          window.pageXOffset : document.documentElement.scrollLeft;

      return [scrollTop, scrollLeft + width, scrollTop + height, scrollLeft];
    }

    /**
     * Returns the available distance the scrolling viewport can still be
     * scrolled before reaching the selection container margins: even if the
     * document could scroll further past the selection container margins,
     * dragging the selection box does not cause further scrolling once the
     * selection container margins are in view.
     *
     * @return {!Array.<number>} Available scrolling distances (in px),
     *     respectively from the following margins: top, right, bottom, left.
     */
    function getScrollableDistances() {
      var scrollTop = typeof(window.pageYOffset) == 'number' ?
          window.pageYOffset : document.documentElement.scrollTop;
      var scrollLeft = typeof(window.pageXOffset) == 'number' ?
          window.pageXOffset : document.documentElement.scrollLeft;
      return [
          Math.max(scrollTop - containerDimensions.top, 0), 
          Math.max(
              containerDimensions.left + containerDimensions.width
              - scrollLeft - width, 0),
          Math.max(
              containerDimensions.top + containerDimensions.height
              - scrollTop - height, 0),
          Math.max(scrollLeft - containerDimensions.left, 0)];
    }

    /**
     * Scrolls the browser window viewport by the required amount.
     *
     * @param {string} scrollAxis The scrolling axis, either 'vertical' or
     *     'horizontal'.
     * @param {number} shift The scrolling amount, in pixels. If positive the
     *     scrolling direction should be downward / rightward. If negative,
     *     upward / leftward.
     */
    function scroll(scrollAxis, shift) {
      if (scrollAxis == 'vertical') {
        window.scrollBy(0, shift);
      } else {
        window.scrollBy(shift, 0);
      }
    }

    /**
     * Returns the offset, in pixels, that should be added to selectable
     * elements' positions (as computed by the plugin 'positioner'), to take
     * into account scrolling. This is not relevant when native browser
     * scrolling is used.
     *
     * @return {!Object.<string, number>} An object containing the 'top' and
     *     'left' properties, pointing respectively to the top and left offset
     *     to add.
     */
    function getScrollOffset() {
      return {top: 0, left: 0};
    }

    return {
      getScrollableElement: getScrollableElement,
      getScrollBorders: getScrollBorders,
      getScrollableDistances: getScrollableDistances,
      scroll: scroll,
      getScrollOffset: getScrollOffset,

      // Chain this scroller to the contentScroller, so that it starts
      // triggering as soon as document scrolling terminates.
      next: contentScroller(el)
    };
  }
A scroller to handle native document (browser window) scrolling when the
selection container overflows the window viewport. It triggers when the
selection box comes close to the browser window borders.

@param {!Element} el The selection container, i.e. the element to which the
    plugin is applied to.