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 `.view-media-library form#views-exposed-form-${settings.view_name.replace( 105 /_/g,
106 '-', 107 )}-${settings.view_display_id.replace( 108 /_/g, 109 '-', 110 )}, form.views-exposed-form[data-drupal-target-view="${ 111 settings.view_dom_id 112 }"], form.views-exposed-form[data-drupal-target-view="${ 113 settings.view_name 114 }-${settings.view_display_id}"]`, 115 ); 116 once('exposed-form', this.$exposed_form).forEach( 117 this.attachExposedFormAjax.bind(this), 118 ); 119 120 // Add the ajax to pagers. 121 once( 122 'ajax-pager', 123 this.$view 124 // Don't attach to nested views. Doing so would attach multiple behaviors 125 // to a given element. 126 .filter(this.filterNestedViews.bind(this)), 127 ).forEach(this.attachPagerAjax.bind(this)); 128 129 // Add a trigger to update this view specifically. In order to trigger a 130 // refresh use the following code. 131 // 132 // @code 133 // $('.view-name').trigger('RefreshView'); 134 // @endcode 135 const selfSettings = $.extend({}, this.element_settings, { 136 event: 'RefreshView', 137 base: this.selector, 138 httpMethod: 'GET', 139 element: this.$view.get(0), 140 }); 141 this.refreshViewAjax = Drupal.ajax(selfSettings); 142 }; 143 144 /** 145 * @method 146 */ 147 Drupal.views.ajaxView.prototype.attachExposedFormAjax = function () { 148 const that = this; 149 this.exposedFormAjax = []; 150 // Exclude the reset buttons so no AJAX behaviors are bound. Many things 151 // break during the form reset phase if using AJAX. 152 once( 153 'attach-ajax', 154 $( 155 'input[type=submit], button[type=submit], input[type=image]', 156 this.$exposed_form, 157 ).not('[data-drupal-selector=edit-reset]'), 158 ).forEach(function (button, index) { 159 const selfSettings = $.extend({}, that.element_settings, { 160 base: $(button).attr('id'), 161 element: button, 162 }); 163 that.exposedFormAjax[index] = Drupal.ajax(selfSettings); 164 }); 165 }; 166 167 /** 168 * @return {boolean} 169 * If there is at least one parent with a view class return false. 170 */ 171 Drupal.views.ajaxView.prototype.filterNestedViews = function () { 172 // If there is at least one parent with a view class, this view 173 // is nested (e.g., an attachment). Bail. 174 return !this.$view.parents('.view').length; 175 }; 176 177 /** 178 * Attach the ajax behavior to each link. 179 */ 180 Drupal.views.ajaxView.prototype.attachPagerAjax = function () { 181 this.$view 182 .find( 183 '.js-pager__items a, th.views-field a, .attachment .views-summary a', 184 ) 185 .each(this.attachPagerLinkAjax.bind(this)); 186 }; 187 188 /** 189 * Attach the ajax behavior to a singe link. 190 * 191 * @param {string} [id] 192 * The ID of the link. 193 * @param {HTMLElement} link 194 * The link element. 195 */ 196 Drupal.views.ajaxView.prototype.attachPagerLinkAjax = function (id, link) { 197 const $link = $(link); 198 const viewData = {}; 199 const href = $link.attr('href'); 200 // Construct an object using the settings defaults and then overriding 201 // with data specific to the link. 202 $.extend( 203 viewData, 204 this.settings, 205 Drupal.Views.parseQueryString(href), 206 // Extract argument data from the URL. 207 Drupal.Views.parseViewArgs(href, this.settings.view_base_path), 208 ); 209 210 const selfSettings = $.extend({}, this.element_settings, {
211 submit: viewData, 212 base: false, 213 element: link, 214 httpMethod: 'GET', 215 }); 216 this.pagerAjax = Drupal.ajax(selfSettings); 217 }; 218 219 /** 220 * Views scroll to top ajax command. 221 * 222 * @param {Drupal.Ajax} [ajax] 223 * A {@link Drupal.ajax} object. 224 * @param {object} response 225 * Ajax response. 226 * @param {string} response.selector 227 * Selector to use. 228 * 229 * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. 230 * Use Drupal.AjaxCommands.prototype.scrollTop(). 231 * 232 * @see https://www.drupal.org/node/3344141 233 */ 234 Drupal.AjaxCommands.prototype.viewsScrollTop = function (ajax, response) { 235 Drupal.AjaxCommands.prototype.scrollTop(ajax, response); 236 }; 237})(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.