Source: layout/InfiniteScrollArea.js

/**
 * Copyright (C) 2005-2016 Alfresco Software Limited.
 *
 * This file is part of Alfresco
 *
 * Alfresco is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Alfresco is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * This layout widget can be wrapped around any [paginated list]{@link module:alfresco/lists/AlfSortablePaginatedList}
 * configured to use [infinite scrolling]{@link module:alfresco/lists/AlfList#useInfiniteScroll] 
 * that is expected to grow taller than the height of its containing widget. It will automatically update its parent
 * widget to publish events as the bottom of the scrolling area is reached which will in turn cause the list to request
 * the next page of data. If the list is only constrained by the height of the browser then the
 * [InfiniteScrollService]{@link module:alfresco/services/InfiniteScrollService} should be used instead.
 *
 * @example <caption>List inside a [FixedHeaderFooter]{@link module:alfresco/layout/FixedHeaderFooter} widget</caption>
 * {
 *   name: "alfresco/layout/FixedHeaderFooter",
 *   config: {
 *     height: "200px",
 *     widgets: [
 *       {
 *         name: "alfresco/layout/InfiniteScrollArea",
 *         config: {
 *           widgets: [
 *             {
 *               name: "alfresco/lists/AlfSortablePaginatedList"
 *               config: {
 *                 useInfiniteScroll: true,
 *                 widgets: [
 *                   // Declare view here
 *                 ]
 *               }
 *             }
 *           ]
 *         }
 *       }
 *     ]
 *   }
 * }
 * 
 * @module alfresco/layout/InfiniteScrollArea
 * @extends module:alfresco/core/ProcessWidgets
 * @mixes module:alfresco/services/InfiniteScrollService
 * @author Dave Draper
 */
define(["dojo/_base/declare",
        "alfresco/core/ProcessWidgets",
        "alfresco/services/InfiniteScrollService",
        "alfresco/core/topics",
        "dojo/_base/lang"], 
        function(declare, ProcessWidgets, InfiniteScrollService, topics, lang) {
   
   return declare([ProcessWidgets, InfiniteScrollService], {
      
      /**
       * The CSS class (or a space separated list of classes) to include in the DOM node.
       * 
       * @instance
       * @type {string}
       * @default
       */
      baseClass: "alfresco-layout-InfiniteScrollArea",

      /**
       * This overrides the [inherited default]{@link module:alfresco/services/InfiniteScrollService#_registerScrollListenerImmediately}
       * to ensure that the [publishScrollEvents function]{@link module:alfresco/core/_EventsMixin#publishScrollEvents} is NOT called
       * automatically in the constructor.
       *
       * @instance
       * @override
       * @type {boolean}
       * @default
       */
      _registerScrollListenerImmediately: false,

      /**
       * <p>The primary purpose of this widget is to support infinite scrolling of [lists]{@link module:alfresco/lists/AlfList} within a fixed 
       * height area. Loadingmore data requires that either a scroll bar is present or the area is resized. However there may be circumstances
       * where the area is too tall, and the initial [page size]{@link module:alfresco/lists/AlfSortablePaginatedList#currentPageSize} to small
       * for list data to fill. If this attribute is configured to be true then the height of the parent element will be compared against the
       * height of this widget each time list data is loaded, and if the height of this widget is not as big as that of its parent element
       * then a request for more data will be made.</p>
       *
       * <p>However, in order for this to work it is important that both the [list]{@link module:alfresco/lists/AlfList} and this
       * widget share the same pubSubScope, the same 
       * [requestFinishedTopic]{@link module:alfresco/documentlibrary/_AlfDocumentListTopicMixin#requestFinishedTopic} topic and the same
       * [scrollNearBottom]{@link module:alfresco/documentlibrary/_AlfDocumentListTopicMixin#scrollNearBottom} topic. Each time the
       * [requestFinishedTopic]{@link module:alfresco/documentlibrary/_AlfDocumentListTopicMixin#requestFinishedTopic} is published the
       * [onDataLoaded]{@link module:alfresco/layout/InfiniteScrollArea#onDataLoaded} function will be called to compare heights and
       * request more data by publishing the [scrollNearBottom]{@link module:alfresco/documentlibrary/_AlfDocumentListTopicMixin#scrollNearBottom}
       * topic if necessary</p>
       * 
       * @instance
       * @type {boolean}
       * @default
       */
      fillAvailableHeight: true,

      /**
       * The constructor
       *
       * @instance
       */
      constructor: function() {
         this.alfSubscribe(this.eventsResizeTopic, lang.hitch(this, this.onEventsResize));
      },

      /**
       * Extends the [inherited function]{@link module:alfresco/core/ProcessWidgets#postCreate} to
       * set the mixed in [element]{@link module:alfresco/core/_EventsMixin#scrollElement}
       * to detect scroll position on
       *
       * @instance
       * @listens module:alfresco/core/topics#VIEW_RENDERING_COMPLETE
       */
      postCreate: function alfresco_layout_InfiniteScrollArea__postCreate() {
         this.inherited(arguments);
         this.publishScrollEvents(this.domNode.parentNode);
         this.publishResizeEvents(this.domNode.parentNode);

         if (this.fillAvailableHeight)
         {
            this.alfSubscribe(topics.VIEW_RENDERING_COMPLETE, lang.hitch(this, this.onDataLoaded));
         }
      },

      /**
       * This function is called when data is successfully loaded by a [list]{@link module:alfresco/lists/AlfList} 
       * contained within this widget and it compares the height of the widget with that of its parent to determine
       * whether or not to make a request for more data.
       *
       * @instance
       */
      onDataLoaded: function alfresco_layout_InfiniteScrollArea__onDataLoaded() {
         if (this.domNode.clientHeight < this.domNode.parentNode.clientHeight)
         {
            this.alfPublish(this.scrollNearBottom);
         }
      },

      /**
       * Handle resize events on the parent node
       *
       * @instance
       * @param {Object} payload The payload from the resize
       */
      onEventsResize: function alfresco_layout_InfiniteScrollArea__onEventsResize(payload) {
         if (payload.node === this.domNode.parentNode) {
            this.alfPublish("ALF_EVENTS_SCROLL", {
               node: payload.node
            });
         }
      }
   });
});