1/** 2 * @file 3 * Infinite Scroll JS. 4 */ 5 6(function ($, Drupal, debounce) { 7 "use strict"; 8 9 // Cached reference to $(window). 10 var $window = $(window); 11 12 // The threshold for how far to the bottom you should reach before reloading. 13 var scrollThreshold = 200; 14 15 // The selector for the automatic pager. 16 var automaticPagerSelector = '[data-drupal-views-infinite-scroll-pager="automatic"]'; 17 18 // The selector for both manual load and automatic pager. 19 var pagerSelector = '[data-drupal-views-infinite-scroll-pager]'; 20 21 // The selector for the automatic pager. 22 var contentWrapperSelector = '[data-drupal-views-infinite-scroll-content-wrapper]'; 23 24 // The event and namespace that is bound to window for automatic scrolling. 25 var scrollEvent = 'scroll.views_infinite_scroll'; 26 27 /** 28 * Insert a views infinite scroll view into the document. 29 * 30 * @param {jQuery} $newView 31 * New content detached from the DOM. 32 */ 33 $.fn.infiniteScrollInsertView = function ($newView) { 34 // Extract the view DOM ID from the view classes. 35 var matches = /(js-view-dom-id-\w+)/.exec(this.attr('class')); 36 37 if (!matches) { 38 return; 39 } 40 41 var currentViewId = matches[1].replace('js-view-dom-id-', 'views_dom_id:'); 42 43 // Get the existing ajaxViews object. 44 var view = Drupal.views.instances[currentViewId]; 45 // Remove once so that the exposed form and pager are processed on 46 // behavior attach. 47 once.remove('ajax-pager', view.$view); 48 once.remove('exposed-form', view.$exposed_form); 49 // Make sure infinite scroll can be reinitialized. 50 var $existingPager = view.$view.find(pagerSelector); 51 once.remove('infinite-scroll', $existingPager); 52 53 var $newRows = $newView.find(contentWrapperSelector).children(); 54 var $newPager = $newView.find(pagerSelector); 55 56 view.$view.find(contentWrapperSelector) 57 // Trigger a jQuery event on the wrapper to inform that new content was 58 // loaded and allow other scripts to respond to the event. 59 .trigger('views_infinite_scroll.new_content', $newRows.clone()) 60 // Add the new rows to existing view. 61 .append($newRows); 62 63 var $contentWrapper = view.$view.find(contentWrapperSelector); 64 $contentWrapper.append($newRows); 65 66 var uniqueQueue = {}; 67 $contentWrapper.find('> :not(.view-row)').each(function (n, item) { 68 var $item = $(item); 69 var uniqueId = $item.text().trim(); 70 if (typeof uniqueQueue[uniqueId] === "undefined") { 71 uniqueQueue[uniqueId] = $item; 72 } else { 73 $item.remove(); 74 } 75 }); 76 77 // Replace the pager link with the new link and ajaxPageState values. 78 $existingPager.replaceWith($newPager); 79 80 // Run views and VIS behaviors. 81 Drupal.attachBehaviors(view.$view[0]); 82 }; 83 84 /** 85 * Handle the automatic paging based on the scroll amount. 86 * 87 * @type {Drupal~behavior} 88 * 89 * @prop {Drupal~behaviorAttach} attach 90 * Initialize infinite scroll pagers and bind the scroll event. 91 * @prop {Drupal~behaviorDetach} detach 92 * During `unload` remove the scroll event binding. 93 */ 94 var $quicktabs_tabs = $('.quicktabs-tabs').find('[role="tab"]') 95 var $quicktabs_open = $('.quicktabs-tabs').find('[aria-selected="true"]').attr('aria-controls') 96 var $quicktabs_id = $('#' + $quicktabs_open); 97 var $pager = $($quicktabs_tabs).length > 0 ? $quicktabs_id.find('.js-pager__items') : undefined; 98 99 $($quicktabs_tabs).find('a').on('click', function() { 100 $quicktabs_open = $(this).parent().attr('aria-controls') 101 $quicktabs_id = $('#' + $quicktabs_open); 102 $pager = $quicktabs_id.find('.js-pager__items') 103 $pager.addClass('visually-hidden'); 104 }); 105 106 Drupal.behaviors.views_infinite_scroll_automatic = { 107 attach : function (context, settings) { 108 once('infinite-scroll', automaticPagerSelector, context).forEach(function (elem) { 109 110 $pager = $($quicktabs_tabs).length > 0 ? $quicktabs_id.find('.js-pager__items') : $(elem); 111 $pager.addClass('visually-hidden'); 112 var isLoadNeeded = function () { 113 return window.innerHeight + window.pageYOffset > $pager.offset().top - scrollThreshold; 114 }; 115 $window.on(scrollEvent, debounce(function () { 116 if (isLoadNeeded()) { 117 $pager.find('[rel=next]').click(); 118 $window.off(scrollEvent); 119 } 120 }, 200)); 121 if (isLoadNeeded()) { 122 $window.trigger(scrollEvent); 123 } 124 }); 125 }, 126 detach: function (context, settings, trigger) { 127 // In the case where the view is removed from the document, remove it's 128 // events. This is important in the case a view being refreshed for a reason 129 // other than a scroll. AJAX filters are a good example of the event needing 130 // to be destroyed earlier than above. 131 if (trigger === 'unload') { 132 if (once.remove('infinite-scroll', automaticPagerSelector, context).length) { 133 $window.off(scrollEvent); 134 } 135 } 136 } 137 }; 138 139 /** 140 * Views AJAX pagination filter. 141 * 142 * In case the Entity View Attachment is rendered in a view context, 143 * the default filter function prevents the required 'Use AJAX' setting 144 * to work. 145 * 146 * @return {Boolean} 147 * Whether to apply the Views AJAX paginator. VIS requires this setting 148 * for pagination. 149 */ 150 Drupal.views.ajaxView.prototype.filterNestedViews = function () { 151 return this.$view.hasClass('view-eva') || !this.$view.parents('.view').length; 152 }; 153 154})(jQuery, Drupal, Drupal.debounce);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.