1/** 2 * @file 3 * Handles AJAX fetching of views, including filter submission and response. 4 */ 5 6(function ($, Drupal, drupalSettings) { 7 /** 8 * Attaches the AJAX behavior to exposed filters forms and key View links. 9 * 10 * @type {Drupal~behavior} 11 * 12 * @prop {Drupal~behaviorAttach} attach 13 * Attaches ajaxView functionality to relevant elements. 14 */ 15 Drupal.behaviors.ViewsAjaxView = {}; 16 Drupal.behaviors.ViewsAjaxView.attach = function (context, settings) { 17 if (settings && settings.views && settings.views.ajaxViews) { 18 const { 19 views: { ajaxViews }, 20 } = settings; 21 Object.keys(ajaxViews || {}).forEach((i) => { 22 Drupal.views.instances[i] = new Drupal.views.ajaxView(ajaxViews[i]); 23 }); 24 } 25 }; 26 Drupal.behaviors.ViewsAjaxView.detach = (context, settings, trigger) => { 27 if (trigger === 'unload') { 28 if (settings && settings.views && settings.views.ajaxViews) { 29 const { 30 views: { ajaxViews }, 31 } = settings; 32 Object.keys(ajaxViews || {}).forEach((i) => { 33 const selector = `.js-view-dom-id-${ajaxViews[i].view_dom_id}`; 34 if ($(selector, context).length) { 35 delete Drupal.views.instances[i]; 36 delete settings.views.ajaxViews[i]; 37 } 38 }); 39 } 40 } 41 }; 42 43 /** 44 * @namespace 45 */ 46 Drupal.views = {}; 47 48 /** 49 * @type {object.<string, Drupal.views.ajaxView>} 50 */ 51 Drupal.views.instances = {}; 52 53 /** 54 * JavaScript object for a certain view. 55 * 56 * @constructor 57 * 58 * @param {object} settings 59 * Settings object for the ajax view. 60 * @param {string} settings.view_dom_id 61 * The DOM id of the view. 62 */ 63 Drupal.views.ajaxView = function (settings) { 64 const selector = `.js-view-dom-id-${settings.view_dom_id}`; 65 this.$view = $(selector); 66 67 // Retrieve the path to use for views' ajax. 68 let ajaxPath = drupalSettings.views.ajax_path; 69 70 // If there are multiple views this might've ended up showing up multiple 71 // times. 72 if (ajaxPath.constructor.toString().includes('Array')) { 73 ajaxPath = ajaxPath[0]; 74 } 75 76 // Check if there are any GET parameters to send to views. 77 let queryString = window.location.search || ''; 78 if (queryString !== '') { 79 // Remove the question mark and Drupal path component if any. 80 queryString = queryString 81 .slice(1) 82 .replace(/q=[^&]+&?|page=[^&]+&?|&?render=[^&]+/, ''); 83 if (queryString !== '') { 84 // If there is a '?' in ajaxPath, clean URL are on and & should be 85 // used to add parameters. 86 queryString = (/\?/.test(ajaxPath) ? '&' : '?') + queryString; 87 } 88 } 89 90 this.element_settings = { 91 url: ajaxPath + queryString, 92 submit: settings, 93 httpMethod: 'GET', 94 setClick: true, 95 event: 'click', 96 selector, 97 progress: { type: 'fullscreen' }, 98 }; 99 100 this.settings = settings; 101 102 // Add the ajax to exposed forms. 103 this.$exposed_form = $( 104 `form#views-exposed-form-${settings.view_name.replace( 105 /_/g,
106 '-', 107 )}-${settings.view_display_id.replace(/_/g, '-')}`, 108 ); 109 once('exposed-form', this.$exposed_form).forEach( 110 this.attachExposedFormAjax.bind(this), 111 ); 112 113 // Add the ajax to pagers. 114 once( 115 'ajax-pager', 116 this.$view 117 // Don't attach to nested views. Doing so would attach multiple behaviors 118 // to a given element. 119 .filter(this.filterNestedViews.bind(this)), 120 ).forEach(this.attachPagerAjax.bind(this)); 121 122 // Add a trigger to update this view specifically. In order to trigger a 123 // refresh use the following code. 124 // 125 // @code 126 // $('.view-name').trigger('RefreshView'); 127 // @endcode 128 const selfSettings = $.extend({}, this.element_settings, { 129 event: 'RefreshView', 130 base: this.selector, 131 httpMethod: 'GET', 132 element: this.$view.get(0), 133 }); 134 this.refreshViewAjax = Drupal.ajax(selfSettings); 135 }; 136 137 /** 138 * @method 139 */ 140 Drupal.views.ajaxView.prototype.attachExposedFormAjax = function () { 141 const that = this; 142 this.exposedFormAjax = []; 143 // Exclude the reset buttons so no AJAX behaviors are bound. Many things 144 // break during the form reset phase if using AJAX. 145 $( 146 'input[type=submit], button[type=submit], input[type=image]', 147 this.$exposed_form, 148 ) 149 .not('[data-drupal-selector=edit-reset]') 150 .each(function (index) { 151 const selfSettings = $.extend({}, that.element_settings, { 152 base: $(this).attr('id'), 153 element: this, 154 }); 155 that.exposedFormAjax[index] = Drupal.ajax(selfSettings); 156 }); 157 }; 158 159 /** 160 * @return {boolean} 161 * If there is at least one parent with a view class return false. 162 */ 163 Drupal.views.ajaxView.prototype.filterNestedViews = function () { 164 // If there is at least one parent with a view class, this view 165 // is nested (e.g., an attachment). Bail. 166 return !this.$view.parents('.view').length; 167 }; 168 169 /** 170 * Attach the ajax behavior to each link. 171 */ 172 Drupal.views.ajaxView.prototype.attachPagerAjax = function () { 173 this.$view 174 .find( 175 '.js-pager__items a, th.views-field a, .attachment .views-summary a', 176 ) 177 .each(this.attachPagerLinkAjax.bind(this)); 178 }; 179 180 /** 181 * Attach the ajax behavior to a singe link. 182 * 183 * @param {string} [id] 184 * The ID of the link. 185 * @param {HTMLElement} link 186 * The link element. 187 */ 188 Drupal.views.ajaxView.prototype.attachPagerLinkAjax = function (id, link) { 189 const $link = $(link); 190 const viewData = {}; 191 const href = $link.attr('href'); 192 // Construct an object using the settings defaults and then overriding 193 // with data specific to the link. 194 $.extend( 195 viewData, 196 this.settings, 197 Drupal.Views.parseQueryString(href), 198 // Extract argument data from the URL. 199 Drupal.Views.parseViewArgs(href, this.settings.view_base_path), 200 ); 201 202 const selfSettings = $.extend({}, this.element_settings, {
203 submit: viewData, 204 base: false, 205 element: link, 206 httpMethod: 'GET', 207 }); 208 this.pagerAjax = Drupal.ajax(selfSettings); 209 }; 210 211 /** 212 * Views scroll to top ajax command. 213 * 214 * @param {Drupal.Ajax} [ajax] 215 * A {@link Drupal.ajax} object. 216 * @param {object} response 217 * Ajax response. 218 * @param {string} response.selector 219 * Selector to use. 220 * 221 * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. 222 * Use Drupal.AjaxCommands.prototype.scrollTop(). 223 * 224 * @see https://www.drupal.org/node/3344141 225 */ 226 Drupal.AjaxCommands.prototype.viewsScrollTop = function (ajax, response) { 227 Drupal.AjaxCommands.prototype.scrollTop(ajax, response); 228 }; 229})(jQuery, Drupal, drupalSettings);
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.