/** * @file * Infinite Scroll JS. */ (function ($, Drupal, debounce) { "use strict"; // Cached reference to $(window). var $window = $(window); // The threshold for how far to the bottom you should reach before reloading. var scrollThreshold = 200; // The selector for the automatic pager. var automaticPagerSelector = '[data-drupal-views-infinite-scroll-pager="automatic"]'; // The selector for both manual load and automatic pager. var pagerSelector = '[data-drupal-views-infinite-scroll-pager]'; // The selector for the automatic pager. var contentWrapperSelector = '[data-drupal-views-infinite-scroll-content-wrapper]'; // The event and namespace that is bound to window for automatic scrolling. var scrollEvent = 'scroll.views_infinite_scroll'; /** * Insert a views infinite scroll view into the document. * * @param {jQuery} $newView * New content detached from the DOM. */ $.fn.infiniteScrollInsertView = function ($newView) { // Extract the view DOM ID from the view classes. var matches = /(js-view-dom-id-\w+)/.exec(this.attr('class')); if (!matches) { return; } var currentViewId = matches[1].replace('js-view-dom-id-', 'views_dom_id:'); // Get the existing ajaxViews object. var view = Drupal.views.instances[currentViewId]; // Remove once so that the exposed form and pager are processed on // behavior attach. view.$view.removeOnce('ajax-pager'); view.$exposed_form.removeOnce('exposed-form'); // Make sure infinite scroll can be reinitialized. var $existingPager = view.$view.find(pagerSelector); $existingPager.removeOnce('infinite-scroll'); var $newRows = $newView.find(contentWrapperSelector).children(); var $newPager = $newView.find(pagerSelector); view.$view.find(contentWrapperSelector) // Trigger a jQuery event on the wrapper to inform that new content was // loaded and allow other scripts to respond to the event. .trigger('views_infinite_scroll.new_content', $newRows.clone()) // Add the new rows to existing view. .append($newRows); // Replace the pager link with the new link and ajaxPageState values. $existingPager.replaceWith($newPager); // Run views and VIS behaviors. Drupal.attachBehaviors(view.$view[0]); }; /** * Handle the automatic paging based on the scroll amount. * * @type {Drupal~behavior} * * @prop {Drupal~behaviorAttach} attach * Initialize infinite scroll pagers and bind the scroll event. * @prop {Drupal~behaviorDetach} detach * During `unload` remove the scroll event binding. */ Drupal.behaviors.views_infinite_scroll_automatic = { attach : function (context, settings) { $(context).find(automaticPagerSelector).once('infinite-scroll').each(function () { var $pager = $(this); $pager.addClass('visually-hidden'); var isLoadNeeded = function () { return window.innerHeight + window.pageYOffset > $pager.offset().top - scrollThreshold; }; $window.on(scrollEvent, debounce(function () { if (isLoadNeeded()) { $pager.find('[rel=next]').click(); $window.off(scrollEvent); } }, 200)); if (isLoadNeeded()) { $window.trigger(scrollEvent); } }); }, detach: function (context, settings, trigger) { // In the case where the view is removed from the document, remove it's // events. This is important in the case a view being refreshed for a reason // other than a scroll. AJAX filters are a good example of the event needing // to be destroyed earlier than above. if (trigger === 'unload') { if ($(context).find(automaticPagerSelector).removeOnce('infinite-scroll').length) { $window.off(scrollEvent); } } } }; /** * Views AJAX pagination filter. * * In case the Entity View Attachment is rendered in a view context, * the default filter function prevents the required 'Use AJAX' setting * to work. * * @return {Boolean} * Whether to apply the Views AJAX paginator. VIS requires this setting * for pagination. */ Drupal.views.ajaxView.prototype.filterNestedViews = function () { return this.$view.hasClass('view-eva') || !this.$view.parents('.view').length; }; })(jQuery, Drupal, Drupal.debounce);