diff options
Diffstat (limited to 'core')
178 files changed, 2008 insertions, 1937 deletions
diff --git a/core/core.libraries.yml b/core/core.libraries.yml index 94dfb2ebc5a..07952b56337 100644 --- a/core/core.libraries.yml +++ b/core/core.libraries.yml @@ -84,7 +84,7 @@ drupal.ajax: - core/drupal - core/drupalSettings - core/drupal.progress - - core/jquery.once + - core/once - core/tabbable drupal.announce: @@ -154,7 +154,7 @@ drupal.batch: - core/drupalSettings - core/drupal.ajax - core/drupal.progress - - core/jquery.once + - core/once drupal.checkbox: version: VERSION @@ -174,7 +174,7 @@ drupal.collapse: - core/modernizr - core/drupal - core/drupal.form - - core/jquery.once + - core/once drupal.date: version: VERSION @@ -280,7 +280,7 @@ drupal.dropbutton: - core/jquery - core/drupal - core/drupalSettings - - core/jquery.once + - core/once drupal.element.closest: version: VERSION @@ -309,7 +309,7 @@ drupal.form: - core/jquery - core/drupal - core/drupal.debounce - - core/jquery.once + - core/once drupal.machine-name: version: VERSION @@ -317,7 +317,7 @@ drupal.machine-name: misc/machine-name.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal - core/drupalSettings - core/drupal.form @@ -357,7 +357,7 @@ drupal.states: - core/jquery - core/drupal - core/drupalSettings - - core/jquery.once + - core/once drupal.tabbingmanager: version: VERSION @@ -376,7 +376,7 @@ drupal.tabledrag: - core/jquery - core/drupal - core/drupalSettings - - core/jquery.once + - core/once drupal.tableheader: version: VERSION @@ -386,7 +386,7 @@ drupal.tableheader: - core/jquery - core/drupal - core/drupalSettings - - core/jquery.once + - core/once - core/drupal.displace drupal.tableresponsive: @@ -396,7 +396,7 @@ drupal.tableresponsive: dependencies: - core/jquery - core/drupal - - core/jquery.once + - core/once drupal.tableselect: version: VERSION @@ -406,7 +406,7 @@ drupal.tableselect: - core/drupal - core/drupal.checkbox - core/jquery - - core/jquery.once + - core/once drupal.timezone: version: VERSION @@ -414,7 +414,7 @@ drupal.timezone: misc/timezone.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal drupal.vertical-tabs: @@ -427,7 +427,7 @@ drupal.vertical-tabs: misc/vertical-tabs.css: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal - core/drupalSettings - core/drupal.form @@ -529,6 +529,7 @@ jquery.once: dependencies: - core/jquery - core/jquery.once.bc + deprecated: The %library_id% asset library is deprecated in Drupal 9.3.0 and will be removed in Drupal 10.0.0. Use the core/once library instead. See https://www.drupal.org/node/3158256 jquery.once.bc: version: VERSION @@ -849,6 +850,7 @@ drupal.dialog.off_canvas: misc/dialog/off-canvas.layout.css: {} dependencies: - core/jquery + - core/once - core/drupal - core/drupal.ajax - core/drupal.announce diff --git a/core/misc/ajax.es6.js b/core/misc/ajax.es6.js index c1d9d6bdf3a..4603b819541 100644 --- a/core/misc/ajax.es6.js +++ b/core/misc/ajax.es6.js @@ -32,13 +32,13 @@ if (typeof elementSettings.selector === 'undefined') { elementSettings.selector = `#${base}`; } - $(elementSettings.selector) - .once('drupal-ajax') - .each(function () { - elementSettings.element = this; - elementSettings.base = base; - Drupal.ajax(elementSettings); - }); + // Use jQuery selector instead of a native selector for + // backwards compatibility. + once('drupal-ajax', $(elementSettings.selector)).forEach((el) => { + elementSettings.element = el; + elementSettings.base = base; + Drupal.ajax(elementSettings); + }); } // Load all Ajax behaviors specified in the settings. @@ -49,27 +49,25 @@ Drupal.ajax.bindAjaxLinks(document.body); // This class means to submit the form to the action using Ajax. - $('.use-ajax-submit') - .once('ajax') - .each(function () { - const elementSettings = {}; - - // Ajax submits specified in this manner automatically submit to the - // normal form action. - elementSettings.url = $(this.form).attr('action'); - // Form submit button clicks need to tell the form what was clicked so - // it gets passed in the POST request. - elementSettings.setClick = true; - // Form buttons use the 'click' event rather than mousedown. - elementSettings.event = 'click'; - // Clicked form buttons look better with the throbber than the progress - // bar. - elementSettings.progress = { type: 'throbber' }; - elementSettings.base = $(this).attr('id'); - elementSettings.element = this; + once('ajax', '.use-ajax-submit').forEach((el) => { + const elementSettings = {}; + + // Ajax submits specified in this manner automatically submit to the + // normal form action. + elementSettings.url = $(el.form).attr('action'); + // Form submit button clicks need to tell the form what was clicked so + // it gets passed in the POST request. + elementSettings.setClick = true; + // Form buttons use the 'click' event rather than mousedown. + elementSettings.event = 'click'; + // Clicked form buttons look better with the throbber than the progress + // bar. + elementSettings.progress = { type: 'throbber' }; + elementSettings.base = el.id; + elementSettings.element = el; - Drupal.ajax(elementSettings); - }); + Drupal.ajax(elementSettings); + }); }, detach(context, settings, trigger) { @@ -289,32 +287,29 @@ */ Drupal.ajax.bindAjaxLinks = (element) => { // Bind Ajax behaviors to all items showing the class. - $(element) - .find('.use-ajax') - .once('ajax') - .each((i, ajaxLink) => { - const $linkElement = $(ajaxLink); - - const elementSettings = { - // Clicked links look better with the throbber than the progress bar. - progress: { type: 'throbber' }, - dialogType: $linkElement.data('dialog-type'), - dialog: $linkElement.data('dialog-options'), - dialogRenderer: $linkElement.data('dialog-renderer'), - base: $linkElement.attr('id'), - element: ajaxLink, - }; - const href = $linkElement.attr('href'); - /** - * For anchor tags, these will go to the target of the anchor rather - * than the usual location. - */ - if (href) { - elementSettings.url = href; - elementSettings.event = 'click'; - } - Drupal.ajax(elementSettings); - }); + once('ajax', '.use-ajax', element).forEach((ajaxLink) => { + const $linkElement = $(ajaxLink); + + const elementSettings = { + // Clicked links look better with the throbber than the progress bar. + progress: { type: 'throbber' }, + dialogType: $linkElement.data('dialog-type'), + dialog: $linkElement.data('dialog-options'), + dialogRenderer: $linkElement.data('dialog-renderer'), + base: $linkElement.attr('id'), + element: ajaxLink, + }; + const href = $linkElement.attr('href'); + /** + * For anchor tags, these will go to the target of the anchor rather than + * the usual location. + */ + if (href) { + elementSettings.url = href; + elementSettings.event = 'click'; + } + Drupal.ajax(elementSettings); + }); }; /** diff --git a/core/misc/ajax.js b/core/misc/ajax.js index 3cc757ca007..621866e7c4a 100644 --- a/core/misc/ajax.js +++ b/core/misc/ajax.js @@ -29,8 +29,8 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len elementSettings.selector = "#".concat(base); } - $(elementSettings.selector).once('drupal-ajax').each(function () { - elementSettings.element = this; + once('drupal-ajax', $(elementSettings.selector)).forEach(function (el) { + elementSettings.element = el; elementSettings.base = base; Drupal.ajax(elementSettings); }); @@ -40,16 +40,16 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len return loadAjaxBehavior(base); }); Drupal.ajax.bindAjaxLinks(document.body); - $('.use-ajax-submit').once('ajax').each(function () { + once('ajax', '.use-ajax-submit').forEach(function (el) { var elementSettings = {}; - elementSettings.url = $(this.form).attr('action'); + elementSettings.url = $(el.form).attr('action'); elementSettings.setClick = true; elementSettings.event = 'click'; elementSettings.progress = { type: 'throbber' }; - elementSettings.base = $(this).attr('id'); - elementSettings.element = this; + elementSettings.base = el.id; + elementSettings.element = el; Drupal.ajax(elementSettings); }); }, @@ -139,7 +139,7 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len }; Drupal.ajax.bindAjaxLinks = function (element) { - $(element).find('.use-ajax').once('ajax').each(function (i, ajaxLink) { + once('ajax', '.use-ajax', element).forEach(function (ajaxLink) { var $linkElement = $(ajaxLink); var elementSettings = { progress: { diff --git a/core/misc/autocomplete.es6.js b/core/misc/autocomplete.es6.js index c747986d141..bdfd774aa90 100644 --- a/core/misc/autocomplete.es6.js +++ b/core/misc/autocomplete.es6.js @@ -212,9 +212,9 @@ Drupal.behaviors.autocomplete = { attach(context) { // Act on textfields with the "form-autocomplete" class. - const $autocomplete = $(context) - .find('input.form-autocomplete') - .once('autocomplete'); + const $autocomplete = $( + once('autocomplete', 'input.form-autocomplete', context), + ); if ($autocomplete.length) { // Allow options to be overridden per instance. const blacklist = $autocomplete.attr( @@ -240,10 +240,9 @@ }, detach(context, settings, trigger) { if (trigger === 'unload') { - $(context) - .find('input.form-autocomplete') - .removeOnce('autocomplete') - .autocomplete('destroy'); + $( + once.remove('autocomplete', 'input.form-autocomplete', context), + ).autocomplete('destroy'); } }, }; diff --git a/core/misc/autocomplete.js b/core/misc/autocomplete.js index acfaf7c787e..8b083683837 100644 --- a/core/misc/autocomplete.js +++ b/core/misc/autocomplete.js @@ -116,7 +116,7 @@ Drupal.behaviors.autocomplete = { attach: function attach(context) { - var $autocomplete = $(context).find('input.form-autocomplete').once('autocomplete'); + var $autocomplete = $(once('autocomplete', 'input.form-autocomplete', context)); if ($autocomplete.length) { var blacklist = $autocomplete.attr('data-autocomplete-first-character-blacklist'); @@ -136,7 +136,7 @@ }, detach: function detach(context, settings, trigger) { if (trigger === 'unload') { - $(context).find('input.form-autocomplete').removeOnce('autocomplete').autocomplete('destroy'); + $(once.remove('autocomplete', 'input.form-autocomplete', context)).autocomplete('destroy'); } } }; diff --git a/core/misc/batch.es6.js b/core/misc/batch.es6.js index 6d11f250841..2a055157da7 100644 --- a/core/misc/batch.es6.js +++ b/core/misc/batch.es6.js @@ -12,7 +12,7 @@ Drupal.behaviors.batch = { attach(context, settings) { const batch = settings.batch; - const $progress = $('[data-drupal-progress]').once('batch'); + const $progress = $(once('batch', '[data-drupal-progress]')); let progressBar; // Success: redirect to the summary. diff --git a/core/misc/batch.js b/core/misc/batch.js index 402b2ea9add..2511bdbb756 100644 --- a/core/misc/batch.js +++ b/core/misc/batch.js @@ -9,7 +9,7 @@ Drupal.behaviors.batch = { attach: function attach(context, settings) { var batch = settings.batch; - var $progress = $('[data-drupal-progress]').once('batch'); + var $progress = $(once('batch', '[data-drupal-progress]')); var progressBar; function updateCallback(progress, status, pb) { diff --git a/core/misc/collapse.es6.js b/core/misc/collapse.es6.js index 8f0722d64e4..f2e07b65329 100644 --- a/core/misc/collapse.es6.js +++ b/core/misc/collapse.es6.js @@ -117,17 +117,11 @@ if (Modernizr.details) { return; } - const $collapsibleDetails = $(context) - .find('details') - .once('collapse') - .addClass('collapse-processed'); - if ($collapsibleDetails.length) { - for (let i = 0; i < $collapsibleDetails.length; i++) { - CollapsibleDetails.instances.push( - new CollapsibleDetails($collapsibleDetails[i]), - ); - } - } + once('collapse', 'details', context).forEach((detail) => { + // This class is used for styling purpose only. + detail.classList.add('collapse-processed'); + CollapsibleDetails.instances.push(new CollapsibleDetails(detail)); + }); }, }; diff --git a/core/misc/collapse.js b/core/misc/collapse.js index 2a503e92f16..60bd05a067f 100644 --- a/core/misc/collapse.js +++ b/core/misc/collapse.js @@ -56,13 +56,10 @@ return; } - var $collapsibleDetails = $(context).find('details').once('collapse').addClass('collapse-processed'); - - if ($collapsibleDetails.length) { - for (var i = 0; i < $collapsibleDetails.length; i++) { - CollapsibleDetails.instances.push(new CollapsibleDetails($collapsibleDetails[i])); - } - } + once('collapse', 'details', context).forEach(function (detail) { + detail.classList.add('collapse-processed'); + CollapsibleDetails.instances.push(new CollapsibleDetails(detail)); + }); } }; diff --git a/core/misc/details-aria.es6.js b/core/misc/details-aria.es6.js index d1ed12508fa..1d0ef555586 100644 --- a/core/misc/details-aria.es6.js +++ b/core/misc/details-aria.es6.js @@ -11,9 +11,10 @@ */ Drupal.behaviors.detailsAria = { attach() { - $('body') - .once('detailsAria') - .on('click.detailsAria', 'summary', (event) => { + $(once('detailsAria', 'body')).on( + 'click.detailsAria', + 'summary', + (event) => { const $summary = $(event.currentTarget); const open = $(event.currentTarget.parentNode).attr('open') === 'open' @@ -24,7 +25,8 @@ 'aria-expanded': open, 'aria-pressed': open, }); - }); + }, + ); }, }; })(jQuery, Drupal); diff --git a/core/misc/details-aria.js b/core/misc/details-aria.js index 85ed38651df..d80f3dcb64f 100644 --- a/core/misc/details-aria.js +++ b/core/misc/details-aria.js @@ -8,7 +8,7 @@ (function ($, Drupal) { Drupal.behaviors.detailsAria = { attach: function attach() { - $('body').once('detailsAria').on('click.detailsAria', 'summary', function (event) { + $(once('detailsAria', 'body')).on('click.detailsAria', 'summary', function (event) { var $summary = $(event.currentTarget); var open = $(event.currentTarget.parentNode).attr('open') === 'open' ? 'false' : 'true'; $summary.attr({ diff --git a/core/misc/details-summarized-content.es6.js b/core/misc/details-summarized-content.es6.js index 2ed9f9ae6c4..30b67af8b44 100644 --- a/core/misc/details-summarized-content.es6.js +++ b/core/misc/details-summarized-content.es6.js @@ -72,13 +72,11 @@ */ Drupal.behaviors.detailsSummary = { attach(context) { - const $detailsElements = $(context).find('details').once('details'); - DetailsSummarizedContent.instances = DetailsSummarizedContent.instances.concat( - $detailsElements - .map((index, details) => new DetailsSummarizedContent(details)) - .get(), + once('details', 'details', context).map( + (details) => new DetailsSummarizedContent(details), + ), ); }, }; diff --git a/core/misc/details-summarized-content.js b/core/misc/details-summarized-content.js index 2f67ef9c0f0..1080d7d6e07 100644 --- a/core/misc/details-summarized-content.js +++ b/core/misc/details-summarized-content.js @@ -26,10 +26,9 @@ }); Drupal.behaviors.detailsSummary = { attach: function attach(context) { - var $detailsElements = $(context).find('details').once('details'); - DetailsSummarizedContent.instances = DetailsSummarizedContent.instances.concat($detailsElements.map(function (index, details) { + DetailsSummarizedContent.instances = DetailsSummarizedContent.instances.concat(once('details', 'details', context).map(function (details) { return new DetailsSummarizedContent(details); - }).get()); + })); } }; Drupal.DetailsSummarizedContent = DetailsSummarizedContent; diff --git a/core/misc/dialog/off-canvas.es6.js b/core/misc/dialog/off-canvas.es6.js index adbce2ddf82..86986c5109a 100644 --- a/core/misc/dialog/off-canvas.es6.js +++ b/core/misc/dialog/off-canvas.es6.js @@ -334,26 +334,27 @@ */ Drupal.behaviors.offCanvasEvents = { attach: () => { - $(window) - .once('off-canvas') - .on({ - 'dialog:beforecreate': (event, dialog, $element, settings) => { - if (Drupal.offCanvas.isOffCanvas($element)) { - Drupal.offCanvas.beforeCreate({ dialog, $element, settings }); - } - }, - 'dialog:aftercreate': (event, dialog, $element, settings) => { - if (Drupal.offCanvas.isOffCanvas($element)) { - Drupal.offCanvas.render({ dialog, $element, settings }); - Drupal.offCanvas.afterCreate({ $element, settings }); - } - }, - 'dialog:beforeclose': (event, dialog, $element) => { - if (Drupal.offCanvas.isOffCanvas($element)) { - Drupal.offCanvas.beforeClose({ dialog, $element }); - } - }, - }); + if (!once('off-canvas', 'html').length) { + return; + } + $(window).on({ + 'dialog:beforecreate': (event, dialog, $element, settings) => { + if (Drupal.offCanvas.isOffCanvas($element)) { + Drupal.offCanvas.beforeCreate({ dialog, $element, settings }); + } + }, + 'dialog:aftercreate': (event, dialog, $element, settings) => { + if (Drupal.offCanvas.isOffCanvas($element)) { + Drupal.offCanvas.render({ dialog, $element, settings }); + Drupal.offCanvas.afterCreate({ $element, settings }); + } + }, + 'dialog:beforeclose': (event, dialog, $element) => { + if (Drupal.offCanvas.isOffCanvas($element)) { + Drupal.offCanvas.beforeClose({ dialog, $element }); + } + }, + }); }, }; })(jQuery, Drupal, Drupal.debounce, Drupal.displace); diff --git a/core/misc/dialog/off-canvas.js b/core/misc/dialog/off-canvas.js index b7be0171f0b..96369f40dc5 100644 --- a/core/misc/dialog/off-canvas.js +++ b/core/misc/dialog/off-canvas.js @@ -145,7 +145,11 @@ }; Drupal.behaviors.offCanvasEvents = { attach: function attach() { - $(window).once('off-canvas').on({ + if (!once('off-canvas', 'html').length) { + return; + } + + $(window).on({ 'dialog:beforecreate': function dialogBeforecreate(event, dialog, $element, settings) { if (Drupal.offCanvas.isOffCanvas($element)) { Drupal.offCanvas.beforeCreate({ diff --git a/core/misc/dropbutton/dropbutton.es6.js b/core/misc/dropbutton/dropbutton.es6.js index 66974c9da26..5339cb700f0 100644 --- a/core/misc/dropbutton/dropbutton.es6.js +++ b/core/misc/dropbutton/dropbutton.es6.js @@ -110,22 +110,19 @@ */ Drupal.behaviors.dropButton = { attach(context, settings) { - const $dropbuttons = $(context) - .find('.dropbutton-wrapper') - .once('dropbutton'); - if ($dropbuttons.length) { + const dropbuttons = once('dropbutton', '.dropbutton-wrapper', context); + if (dropbuttons.length) { // Adds the delegated handler that will toggle dropdowns on click. - const $body = $('body').once('dropbutton-click'); - if ($body.length) { - $body.on('click', '.dropbutton-toggle', dropbuttonClickHandler); + const body = once('dropbutton-click', 'body'); + if (body.length) { + $(body).on('click', '.dropbutton-toggle', dropbuttonClickHandler); } // Initialize all buttons. - const il = $dropbuttons.length; - for (let i = 0; i < il; i++) { + dropbuttons.forEach((dropbutton) => { DropButton.dropbuttons.push( - new DropButton($dropbuttons[i], settings.dropbutton), + new DropButton(dropbutton, settings.dropbutton), ); - } + }); } }, }; diff --git a/core/misc/dropbutton/dropbutton.js b/core/misc/dropbutton/dropbutton.js index 54b8a627605..f7787d51cb6 100644 --- a/core/misc/dropbutton/dropbutton.js +++ b/core/misc/dropbutton/dropbutton.js @@ -38,20 +38,18 @@ Drupal.behaviors.dropButton = { attach: function attach(context, settings) { - var $dropbuttons = $(context).find('.dropbutton-wrapper').once('dropbutton'); + var dropbuttons = once('dropbutton', '.dropbutton-wrapper', context); - if ($dropbuttons.length) { - var $body = $('body').once('dropbutton-click'); + if (dropbuttons.length) { + var body = once('dropbutton-click', 'body'); - if ($body.length) { - $body.on('click', '.dropbutton-toggle', dropbuttonClickHandler); + if (body.length) { + $(body).on('click', '.dropbutton-toggle', dropbuttonClickHandler); } - var il = $dropbuttons.length; - - for (var i = 0; i < il; i++) { - DropButton.dropbuttons.push(new DropButton($dropbuttons[i], settings.dropbutton)); - } + dropbuttons.forEach(function (dropbutton) { + DropButton.dropbuttons.push(new DropButton(dropbutton, settings.dropbutton)); + }); } } }; diff --git a/core/misc/drupal.es6.js b/core/misc/drupal.es6.js index f3e314db5dd..86359715dfd 100644 --- a/core/misc/drupal.es6.js +++ b/core/misc/drupal.es6.js @@ -128,7 +128,7 @@ window.Drupal = { behaviors: {}, locale: {} }; * behaviors to the new content. * * Behaviors should use `var elements = - * $(context).find(selector).once('behavior-name');` to ensure the behavior is + * once('behavior-name', selector, context);` to ensure the behavior is * attached only once to a given element. (Doing so enables the reprocessing * of given elements, which may be needed on occasion despite the ability to * limit behavior attachment to a particular element.) @@ -178,10 +178,10 @@ window.Drupal = { behaviors: {}, locale: {} }; * before page content is about to be removed, feeding in an element to be * processed, in order to allow special behaviors to detach from the content. * - * Such implementations should use `.findOnce()` and `.removeOnce()` to find + * Such implementations should use `once.filter()` and `once.remove()` to find * elements with their corresponding `Drupal.behaviors.behaviorName.attach` - * implementation, i.e. `.removeOnce('behaviorName')`, to ensure the behavior - * is detached only from previously processed elements. + * implementation, i.e. `once.remove('behaviorName', selector, context)`, + * to ensure the behavior is detached only from previously processed elements. * * @param {HTMLDocument|HTMLElement} [context=document] * An element to detach behaviors from. diff --git a/core/misc/form.es6.js b/core/misc/form.es6.js index 526f24d8b18..78eeccafccb 100644 --- a/core/misc/form.es6.js +++ b/core/misc/form.es6.js @@ -127,9 +127,11 @@ } } - $('body') - .once('form-single-submit') - .on('submit.singleSubmit', 'form:not([method~="GET"])', onFormSubmit); + $(once('form-single-submit', 'body')).on( + 'submit.singleSubmit', + 'form:not([method~="GET"])', + onFormSubmit, + ); }, }; @@ -182,8 +184,8 @@ attach(context) { const $context = $(context); const contextIsForm = $context.is('form'); - const $forms = (contextIsForm ? $context : $context.find('form')).once( - 'form-updated', + const $forms = $( + once('form-updated', contextIsForm ? $context : $context.find('form')), ); let formFields; @@ -218,15 +220,15 @@ const $context = $(context); const contextIsForm = $context.is('form'); if (trigger === 'unload') { - const $forms = ( - contextIsForm ? $context : $context.find('form') - ).removeOnce('form-updated'); - if ($forms.length) { - $.makeArray($forms).forEach((form) => { + once + .remove( + 'form-updated', + contextIsForm ? $context : $context.find('form'), + ) + .forEach((form) => { form.removeAttribute('data-drupal-form-fields'); $(form).off('.formUpdated'); }); - } } }, }; @@ -242,8 +244,8 @@ Drupal.behaviors.fillUserInfoFromBrowser = { attach(context, settings) { const userInfo = ['name', 'mail', 'homepage']; - const $forms = $('[data-user-info-from-browser]').once( - 'user-info-from-browser', + const $forms = $( + once('user-info-from-browser', '[data-user-info-from-browser]'), ); if ($forms.length) { userInfo.forEach((info) => { diff --git a/core/misc/form.js b/core/misc/form.js index d59bd0baeff..4064c1ddf6b 100644 --- a/core/misc/form.js +++ b/core/misc/form.js @@ -41,7 +41,7 @@ } } - $('body').once('form-single-submit').on('submit.singleSubmit', 'form:not([method~="GET"])', onFormSubmit); + $(once('form-single-submit', 'body')).on('submit.singleSubmit', 'form:not([method~="GET"])', onFormSubmit); } }; @@ -60,7 +60,7 @@ attach: function attach(context) { var $context = $(context); var contextIsForm = $context.is('form'); - var $forms = (contextIsForm ? $context : $context.find('form')).once('form-updated'); + var $forms = $(once('form-updated', contextIsForm ? $context : $context.find('form'))); var formFields; if ($forms.length) { @@ -89,21 +89,17 @@ var contextIsForm = $context.is('form'); if (trigger === 'unload') { - var $forms = (contextIsForm ? $context : $context.find('form')).removeOnce('form-updated'); - - if ($forms.length) { - $.makeArray($forms).forEach(function (form) { - form.removeAttribute('data-drupal-form-fields'); - $(form).off('.formUpdated'); - }); - } + once.remove('form-updated', contextIsForm ? $context : $context.find('form')).forEach(function (form) { + form.removeAttribute('data-drupal-form-fields'); + $(form).off('.formUpdated'); + }); } } }; Drupal.behaviors.fillUserInfoFromBrowser = { attach: function attach(context, settings) { var userInfo = ['name', 'mail', 'homepage']; - var $forms = $('[data-user-info-from-browser]').once('user-info-from-browser'); + var $forms = $(once('user-info-from-browser', '[data-user-info-from-browser]')); if ($forms.length) { userInfo.forEach(function (info) { diff --git a/core/misc/machine-name.es6.js b/core/misc/machine-name.es6.js index 88aaf96738b..a8f1f757242 100644 --- a/core/misc/machine-name.es6.js +++ b/core/misc/machine-name.es6.js @@ -90,10 +90,12 @@ Object.keys(settings.machineName).forEach((sourceId) => { const options = settings.machineName[sourceId]; - const $source = $context - .find(sourceId) - .addClass('machine-name-source') - .once('machine-name'); + const $source = $( + once( + 'machine-name', + $context.find(sourceId).addClass('machine-name-source'), + ), + ); const $target = $context .find(options.target) .addClass('machine-name-target'); diff --git a/core/misc/machine-name.js b/core/misc/machine-name.js index a711a88eefc..2e0e1614cff 100644 --- a/core/misc/machine-name.js +++ b/core/misc/machine-name.js @@ -51,7 +51,7 @@ Object.keys(settings.machineName).forEach(function (sourceId) { var options = settings.machineName[sourceId]; - var $source = $context.find(sourceId).addClass('machine-name-source').once('machine-name'); + var $source = $(once('machine-name', $context.find(sourceId).addClass('machine-name-source'))); var $target = $context.find(options.target).addClass('machine-name-target'); var $suffix = $context.find(options.suffix); var $wrapper = $target.closest('.js-form-item'); diff --git a/core/misc/tabledrag.es6.js b/core/misc/tabledrag.es6.js index 21a971d2b77..dd0010fafba 100644 --- a/core/misc/tabledrag.es6.js +++ b/core/misc/tabledrag.es6.js @@ -47,7 +47,7 @@ } Object.keys(settings.tableDrag || {}).forEach((base) => { - initTableDrag($(context).find(`#${base}`).once('tabledrag'), base); + initTableDrag($(once('tabledrag', `#${base}`, context)), base); }); }, }; @@ -370,7 +370,10 @@ // Trigger an event to allow other scripts to react to this display change. // Force the extra parameter as a bool. - $('table').findOnce('tabledrag').trigger('columnschange', !!displayWeight); + $(once.filter('tabledrag', 'table')).trigger( + 'columnschange', + !!displayWeight, + ); }; /** @@ -396,7 +399,7 @@ * Undo showColumns(). */ Drupal.tableDrag.prototype.hideColumns = function () { - const $tables = $('table').findOnce('tabledrag'); + const $tables = $(once.filter('tabledrag', 'table')); // Hide weight/parent cells and headers. $tables.find('.tabledrag-hide').css('display', 'none'); // Show TableDrag handles. @@ -413,7 +416,7 @@ * Undo hideColumns(). */ Drupal.tableDrag.prototype.showColumns = function () { - const $tables = $('table').findOnce('tabledrag'); + const $tables = $(once.filter('tabledrag', 'table')); // Show weight/parent cells and headers. $tables.find('.tabledrag-hide').css('display', ''); // Hide TableDrag handles. diff --git a/core/misc/tabledrag.js b/core/misc/tabledrag.js index fe76291e3ff..c4897e72446 100644 --- a/core/misc/tabledrag.js +++ b/core/misc/tabledrag.js @@ -18,7 +18,7 @@ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "functi } Object.keys(settings.tableDrag || {}).forEach(function (base) { - initTableDrag($(context).find("#".concat(base)).once('tabledrag'), base); + initTableDrag($(once('tabledrag', "#".concat(base), context)), base); }); } }; @@ -162,7 +162,7 @@ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "functi } this.$toggleWeightButton.html(Drupal.theme('toggleButtonContent', displayWeight)); - $('table').findOnce('tabledrag').trigger('columnschange', !!displayWeight); + $(once.filter('tabledrag', 'table')).trigger('columnschange', !!displayWeight); }; Drupal.tableDrag.prototype.toggleColumns = function () { @@ -177,7 +177,7 @@ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "functi }; Drupal.tableDrag.prototype.hideColumns = function () { - var $tables = $('table').findOnce('tabledrag'); + var $tables = $(once.filter('tabledrag', 'table')); $tables.find('.tabledrag-hide').css('display', 'none'); $tables.find('.tabledrag-handle').css('display', ''); $tables.find('.tabledrag-has-colspan').each(function () { @@ -186,7 +186,7 @@ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "functi }; Drupal.tableDrag.prototype.showColumns = function () { - var $tables = $('table').findOnce('tabledrag'); + var $tables = $(once.filter('tabledrag', 'table')); $tables.find('.tabledrag-hide').css('display', ''); $tables.find('.tabledrag-handle').css('display', 'none'); $tables.find('.tabledrag-has-colspan').each(function () { diff --git a/core/misc/tableheader.es6.js b/core/misc/tableheader.es6.js index f7fc2f200e9..1d4eca7e69e 100644 --- a/core/misc/tableheader.es6.js +++ b/core/misc/tableheader.es6.js @@ -76,13 +76,11 @@ // Select and initialize sticky table headers. function tableHeaderInitHandler(e) { - const $tables = $(e.data.context) - .find('table.sticky-enabled') - .once('tableheader'); - const il = $tables.length; - for (let i = 0; i < il; i++) { - TableHeader.tables.push(new TableHeader($tables[i])); - } + once('tableheader', $(e.data.context).find('table.sticky-enabled')).forEach( + (table) => { + TableHeader.tables.push(new TableHeader(table)); + }, + ); forTables('onScroll'); } diff --git a/core/misc/tableheader.js b/core/misc/tableheader.js index 149bd556037..110d30fee0e 100644 --- a/core/misc/tableheader.js +++ b/core/misc/tableheader.js @@ -39,13 +39,9 @@ } function tableHeaderInitHandler(e) { - var $tables = $(e.data.context).find('table.sticky-enabled').once('tableheader'); - var il = $tables.length; - - for (var i = 0; i < il; i++) { - TableHeader.tables.push(new TableHeader($tables[i])); - } - + once('tableheader', $(e.data.context).find('table.sticky-enabled')).forEach(function (table) { + TableHeader.tables.push(new TableHeader(table)); + }); forTables('onScroll'); } diff --git a/core/misc/tableresponsive.es6.js b/core/misc/tableresponsive.es6.js index 4e8af794b23..41f7d158b94 100644 --- a/core/misc/tableresponsive.es6.js +++ b/core/misc/tableresponsive.es6.js @@ -64,15 +64,11 @@ */ Drupal.behaviors.tableResponsive = { attach(context, settings) { - const $tables = $(context) - .find('table.responsive-enabled') - .once('tableresponsive'); - if ($tables.length) { - const il = $tables.length; - for (let i = 0; i < il; i++) { - TableResponsive.tables.push(new TableResponsive($tables[i])); - } - } + once('tableresponsive', 'table.responsive-enabled', context).forEach( + (table) => { + TableResponsive.tables.push(new TableResponsive(table)); + }, + ); }, }; diff --git a/core/misc/tableresponsive.js b/core/misc/tableresponsive.js index ffcb0a11a8e..fbc7e12adb9 100644 --- a/core/misc/tableresponsive.js +++ b/core/misc/tableresponsive.js @@ -19,15 +19,9 @@ Drupal.behaviors.tableResponsive = { attach: function attach(context, settings) { - var $tables = $(context).find('table.responsive-enabled').once('tableresponsive'); - - if ($tables.length) { - var il = $tables.length; - - for (var i = 0; i < il; i++) { - TableResponsive.tables.push(new TableResponsive($tables[i])); - } - } + once('tableresponsive', 'table.responsive-enabled', context).forEach(function (table) { + TableResponsive.tables.push(new TableResponsive(table)); + }); } }; $.extend(TableResponsive, { diff --git a/core/misc/tableselect.es6.js b/core/misc/tableselect.es6.js index aa0aa3484ed..785198a5d9b 100644 --- a/core/misc/tableselect.es6.js +++ b/core/misc/tableselect.es6.js @@ -15,11 +15,10 @@ Drupal.behaviors.tableSelect = { attach(context, settings) { // Select the inner-most table in case of nested tables. - $(context) - .find('th.select-all') - .closest('table') - .once('table-select') - .each(Drupal.tableSelect); + once( + 'table-select', + $(context).find('th.select-all').closest('table'), + ).forEach((table) => Drupal.tableSelect.call(table)); }, }; diff --git a/core/misc/tableselect.js b/core/misc/tableselect.js index cead6c01161..a90d8ca77a1 100644 --- a/core/misc/tableselect.js +++ b/core/misc/tableselect.js @@ -8,7 +8,9 @@ (function ($, Drupal) { Drupal.behaviors.tableSelect = { attach: function attach(context, settings) { - $(context).find('th.select-all').closest('table').once('table-select').each(Drupal.tableSelect); + once('table-select', $(context).find('th.select-all').closest('table')).forEach(function (table) { + return Drupal.tableSelect.call(table); + }); } }; diff --git a/core/misc/timezone.es6.js b/core/misc/timezone.es6.js index 7503c5f84bc..e6d79c88298 100644 --- a/core/misc/timezone.es6.js +++ b/core/misc/timezone.es6.js @@ -11,8 +11,9 @@ */ Drupal.behaviors.setTimezone = { attach(context, settings) { - const $timezone = $(context).find('.timezone-detect').once('timezone'); - if ($timezone.length) { + const timezone = once('timezone', '.timezone-detect', context); + if (timezone.length) { + const $timezone = $(timezone); const tz = new Intl.DateTimeFormat().resolvedOptions().timeZone; // Ensure that the timezone value returned by the browser is supported // by the server. diff --git a/core/misc/timezone.js b/core/misc/timezone.js index 94bb564acd8..5d27fcde3b4 100644 --- a/core/misc/timezone.js +++ b/core/misc/timezone.js @@ -8,9 +8,10 @@ (function ($, Drupal) { Drupal.behaviors.setTimezone = { attach: function attach(context, settings) { - var $timezone = $(context).find('.timezone-detect').once('timezone'); + var timezone = once('timezone', '.timezone-detect', context); - if ($timezone.length) { + if (timezone.length) { + var $timezone = $(timezone); var tz = new Intl.DateTimeFormat().resolvedOptions().timeZone; if (tz && $timezone.find("option[value=\"".concat(tz, "\"]")).length) { diff --git a/core/misc/vertical-tabs.es6.js b/core/misc/vertical-tabs.es6.js index fea9ffc835c..5a55d880b21 100644 --- a/core/misc/vertical-tabs.es6.js +++ b/core/misc/vertical-tabs.es6.js @@ -56,18 +56,14 @@ /** * Binds a listener to handle fragment link clicks and URL hash changes. */ - $('body') - .once('vertical-tabs-fragments') - .on( - 'formFragmentLinkClickOrHashChange.verticalTabs', - handleFragmentLinkClickOrHashChange, - ); + $(once('vertical-tabs-fragments', 'body')).on( + 'formFragmentLinkClickOrHashChange.verticalTabs', + handleFragmentLinkClickOrHashChange, + ); - $(context) - .find('[data-vertical-tabs-panes]') - .once('vertical-tabs') - .each(function () { - const $this = $(this).addClass('vertical-tabs__panes'); + once('vertical-tabs', '[data-vertical-tabs-panes]', context).forEach( + (verticalTab) => { + const $this = $(verticalTab).addClass('vertical-tabs__panes'); const focusID = $this.find(':hidden.vertical-tabs__active-tab').val(); let tabFocus; @@ -120,7 +116,8 @@ if (tabFocus.length) { tabFocus.data('verticalTab').focus(); } - }); + }, + ); }, }; diff --git a/core/misc/vertical-tabs.js b/core/misc/vertical-tabs.js index 1ba55f9460e..2e54127c133 100644 --- a/core/misc/vertical-tabs.js +++ b/core/misc/vertical-tabs.js @@ -21,9 +21,9 @@ return; } - $('body').once('vertical-tabs-fragments').on('formFragmentLinkClickOrHashChange.verticalTabs', handleFragmentLinkClickOrHashChange); - $(context).find('[data-vertical-tabs-panes]').once('vertical-tabs').each(function () { - var $this = $(this).addClass('vertical-tabs__panes'); + $(once('vertical-tabs-fragments', 'body')).on('formFragmentLinkClickOrHashChange.verticalTabs', handleFragmentLinkClickOrHashChange); + once('vertical-tabs', '[data-vertical-tabs-panes]', context).forEach(function (verticalTab) { + var $this = $(verticalTab).addClass('vertical-tabs__panes'); var focusID = $this.find(':hidden.vertical-tabs__active-tab').val(); var tabFocus; var $details = $this.find('> details'); diff --git a/core/modules/big_pipe/big_pipe.libraries.yml b/core/modules/big_pipe/big_pipe.libraries.yml index 6da49b78e05..8aa05075fdc 100644 --- a/core/modules/big_pipe/big_pipe.libraries.yml +++ b/core/modules/big_pipe/big_pipe.libraries.yml @@ -6,6 +6,6 @@ big_pipe: bigPipePlaceholderIds: [] dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal.ajax - core/drupalSettings diff --git a/core/modules/big_pipe/js/big_pipe.es6.js b/core/modules/big_pipe/js/big_pipe.es6.js index 62f05d4067e..e035198d4fa 100644 --- a/core/modules/big_pipe/js/big_pipe.es6.js +++ b/core/modules/big_pipe/js/big_pipe.es6.js @@ -30,16 +30,14 @@ * * These Ajax commands replace placeholders with HTML and load missing CSS/JS. * - * @param {number} index - * Current index. * @param {HTMLScriptElement} placeholderReplacement * Script tag created by BigPipe. */ - function bigPipeProcessPlaceholderReplacement(index, placeholderReplacement) { + function bigPipeProcessPlaceholderReplacement(placeholderReplacement) { const placeholderId = placeholderReplacement.getAttribute( 'data-big-pipe-replacement-for-placeholder-with-id', ); - const content = this.textContent.trim(); + const content = placeholderReplacement.textContent.trim(); // Ignore any placeholders that are not in the known placeholder list. Used // to avoid someone trying to XSS the site via the placeholdering mechanism. if ( @@ -53,7 +51,7 @@ * Mark as unprocessed so this will be retried later. * @see bigPipeProcessDocument() */ - $(this).removeOnce('big-pipe'); + once.remove('big-pipe', placeholderReplacement); } else { // Create a Drupal.Ajax object without associating an element, a // progress indicator or a URL. @@ -95,10 +93,11 @@ return false; } - $(context) - .find('script[data-big-pipe-replacement-for-placeholder-with-id]') - .once('big-pipe') - .each(bigPipeProcessPlaceholderReplacement); + once( + 'big-pipe', + 'script[data-big-pipe-replacement-for-placeholder-with-id]', + context, + ).forEach(bigPipeProcessPlaceholderReplacement); // If we see the stop signal, clear the timeout: all placeholder // replacements are guaranteed to be received and processed. diff --git a/core/modules/big_pipe/js/big_pipe.js b/core/modules/big_pipe/js/big_pipe.js index 7d174dd6376..9d939243ef2 100644 --- a/core/modules/big_pipe/js/big_pipe.js +++ b/core/modules/big_pipe/js/big_pipe.js @@ -18,15 +18,15 @@ } } - function bigPipeProcessPlaceholderReplacement(index, placeholderReplacement) { + function bigPipeProcessPlaceholderReplacement(placeholderReplacement) { var placeholderId = placeholderReplacement.getAttribute('data-big-pipe-replacement-for-placeholder-with-id'); - var content = this.textContent.trim(); + var content = placeholderReplacement.textContent.trim(); if (typeof drupalSettings.bigPipePlaceholderIds[placeholderId] !== 'undefined') { var response = mapTextContentToAjaxResponse(content); if (response === false) { - $(this).removeOnce('big-pipe'); + once.remove('big-pipe', placeholderReplacement); } else { var ajaxObject = Drupal.ajax({ url: '', @@ -47,7 +47,7 @@ return false; } - $(context).find('script[data-big-pipe-replacement-for-placeholder-with-id]').once('big-pipe').each(bigPipeProcessPlaceholderReplacement); + once('big-pipe', 'script[data-big-pipe-replacement-for-placeholder-with-id]', context).forEach(bigPipeProcessPlaceholderReplacement); if (context.querySelector('script[data-big-pipe-event="stop"]')) { if (timeoutID) { diff --git a/core/modules/block/block.libraries.yml b/core/modules/block/block.libraries.yml index 9b5877f5177..ab7026fcd59 100644 --- a/core/modules/block/block.libraries.yml +++ b/core/modules/block/block.libraries.yml @@ -5,6 +5,7 @@ drupal.block: dependencies: - core/jquery - core/drupal + - core/once drupal.block.admin: version: VERSION @@ -19,3 +20,4 @@ drupal.block.admin: - core/drupal.announce - core/drupal.debounce - core/drupal.dialog.ajax + - core/once diff --git a/core/modules/block/js/block.admin.es6.js b/core/modules/block/js/block.admin.es6.js index 220267b68d8..d475348b741 100644 --- a/core/modules/block/js/block.admin.es6.js +++ b/core/modules/block/js/block.admin.es6.js @@ -3,7 +3,7 @@ * Block admin behaviors. */ -(function ($, Drupal, debounce) { +(function ($, Drupal, debounce, once) { /** * Filters the block list by a text input search string. * @@ -22,7 +22,7 @@ */ Drupal.behaviors.blockFilterByText = { attach(context, settings) { - const $input = $('input.block-filter-text').once('block-filter-text'); + const $input = $(once('block-filter-text', 'input.block-filter-text')); const $table = $($input.attr('data-element')); let $filterRows; @@ -86,24 +86,25 @@ attach(context, settings) { // Ensure that the block we are attempting to scroll to actually exists. if (settings.blockPlacement && $('.js-block-placed').length) { - $(context) - .find('[data-drupal-selector="edit-blocks"]') - .once('block-highlight') - .each(function () { - const $container = $(this); - // Just scrolling the document.body will not work in Firefox. The html - // element is needed as well. - $('html, body').animate( - { - scrollTop: - $('.js-block-placed').offset().top - - $container.offset().top + - $container.scrollTop(), - }, - 500, - ); - }); + once( + 'block-highlight', + '[data-drupal-selector="edit-blocks"]', + context, + ).forEach((container) => { + const $container = $(container); + // Just scrolling the document.body will not work in Firefox. The html + // element is needed as well. + $('html, body').animate( + { + scrollTop: + $('.js-block-placed').offset().top - + $container.offset().top + + $container.scrollTop(), + }, + 500, + ); + }); } }, }; -})(jQuery, Drupal, Drupal.debounce); +})(jQuery, Drupal, Drupal.debounce, once); diff --git a/core/modules/block/js/block.admin.js b/core/modules/block/js/block.admin.js index 482433569d4..28cdf71769f 100644 --- a/core/modules/block/js/block.admin.js +++ b/core/modules/block/js/block.admin.js @@ -5,10 +5,10 @@ * @preserve **/ -(function ($, Drupal, debounce) { +(function ($, Drupal, debounce, once) { Drupal.behaviors.blockFilterByText = { attach: function attach(context, settings) { - var $input = $('input.block-filter-text').once('block-filter-text'); + var $input = $(once('block-filter-text', 'input.block-filter-text')); var $table = $($input.attr('data-element')); var $filterRows; @@ -41,8 +41,8 @@ Drupal.behaviors.blockHighlightPlacement = { attach: function attach(context, settings) { if (settings.blockPlacement && $('.js-block-placed').length) { - $(context).find('[data-drupal-selector="edit-blocks"]').once('block-highlight').each(function () { - var $container = $(this); + once('block-highlight', '[data-drupal-selector="edit-blocks"]', context).forEach(function (container) { + var $container = $(container); $('html, body').animate({ scrollTop: $('.js-block-placed').offset().top - $container.offset().top + $container.scrollTop() }, 500); @@ -50,4 +50,4 @@ } } }; -})(jQuery, Drupal, Drupal.debounce);
\ No newline at end of file +})(jQuery, Drupal, Drupal.debounce, once);
\ No newline at end of file diff --git a/core/modules/block/js/block.es6.js b/core/modules/block/js/block.es6.js index 4d949639d62..eda67f8ac04 100644 --- a/core/modules/block/js/block.es6.js +++ b/core/modules/block/js/block.es6.js @@ -3,7 +3,7 @@ * Block behaviors. */ -(function ($, window, Drupal) { +(function ($, window, Drupal, once) { /** * Provide the summary information for the block settings vertical tabs. * @@ -218,10 +218,9 @@ }; // Add the behavior to each region select list. - $(context) - .find('select.block-region-select') - .once('block-region-select') - .on('change', function (event) { + $(once('block-region-select', 'select.block-region-select', context)).on( + 'change', + function (event) { // Make our new row and select field. const row = $(this).closest('tr'); const select = $(this); @@ -256,7 +255,8 @@ } // Remove focus from selectbox. select.trigger('blur'); - }); + }, + ); }, }; -})(jQuery, window, Drupal); +})(jQuery, window, Drupal, once); diff --git a/core/modules/block/js/block.js b/core/modules/block/js/block.js index 167cd2a1a0b..d541c9612a4 100644 --- a/core/modules/block/js/block.js +++ b/core/modules/block/js/block.js @@ -5,7 +5,7 @@ * @preserve **/ -(function ($, window, Drupal) { +(function ($, window, Drupal, once) { Drupal.behaviors.blockSettingsSummary = { attach: function attach() { if (typeof $.fn.drupalSetSummary === 'undefined') { @@ -112,7 +112,7 @@ updateBlockWeights(table, regionName); }; - $(context).find('select.block-region-select').once('block-region-select').on('change', function (event) { + $(once('block-region-select', 'select.block-region-select', context)).on('change', function (event) { var row = $(this).closest('tr'); var select = $(this); tableDrag.rowObject = new tableDrag.row(row[0]); @@ -138,4 +138,4 @@ }); } }; -})(jQuery, window, Drupal);
\ No newline at end of file +})(jQuery, window, Drupal, once);
\ No newline at end of file diff --git a/core/modules/ckeditor/ckeditor.libraries.yml b/core/modules/ckeditor/ckeditor.libraries.yml index 9e2449293c7..48bb5e47357 100644 --- a/core/modules/ckeditor/ckeditor.libraries.yml +++ b/core/modules/ckeditor/ckeditor.libraries.yml @@ -49,7 +49,7 @@ drupal.ckeditor.admin: - core/jquery - core/drupal - core/drupalSettings - - core/jquery.once + - core/once - core/backbone - core/drupal.dialog - core/drupal.announce @@ -66,7 +66,7 @@ drupal.ckeditor.drupalimage.admin: dependencies: - core/jquery - core/drupal - - core/jquery.once + - core/once - core/drupal.vertical-tabs - core/drupalSettings diff --git a/core/modules/ckeditor/js/ckeditor.admin.es6.js b/core/modules/ckeditor/js/ckeditor.admin.es6.js index 5c73bdacc0c..5390e81f14b 100644 --- a/core/modules/ckeditor/js/ckeditor.admin.es6.js +++ b/core/modules/ckeditor/js/ckeditor.admin.es6.js @@ -19,10 +19,13 @@ Drupal.behaviors.ckeditorAdmin = { attach(context) { // Process the CKEditor configuration fragment once. - const $configurationForm = $(context) - .find('.ckeditor-toolbar-configuration') - .once('ckeditor-configuration'); - if ($configurationForm.length) { + const configurationForm = once( + 'ckeditor-configuration', + '.ckeditor-toolbar-configuration', + context, + ); + if (configurationForm.length) { + const $configurationForm = $(configurationForm); const $textarea = $configurationForm // Hide the textarea that contains the serialized representation of the // CKEditor configuration. @@ -66,11 +69,13 @@ // really means that all CKEditor toolbar buttons have been removed. // Hence,all editor features will be removed, so any reactions from // filters will be undone. - const $configurationForm = $(context) - .find('.ckeditor-toolbar-configuration') - .findOnce('ckeditor-configuration'); + const configurationForm = once.filter( + 'ckeditor-configuration', + '.ckeditor-toolbar-configuration', + context, + ); if ( - $configurationForm.length && + configurationForm.length && Drupal.ckeditor.models && Drupal.ckeditor.models.Model ) { @@ -417,10 +422,13 @@ Drupal.behaviors.ckeditorAdminButtonPluginSettings = { attach(context) { const $context = $(context); - const $ckeditorPluginSettings = $context - .find('#ckeditor-plugin-settings') - .once('ckeditor-plugin-settings'); - if ($ckeditorPluginSettings.length) { + const ckeditorPluginSettings = once( + 'ckeditor-plugin-settings', + '#ckeditor-plugin-settings', + context, + ); + if (ckeditorPluginSettings.length) { + const $ckeditorPluginSettings = $(ckeditorPluginSettings); // Hide all button-dependent plugin settings initially. $ckeditorPluginSettings .find('[data-ckeditor-buttons]') diff --git a/core/modules/ckeditor/js/ckeditor.admin.js b/core/modules/ckeditor/js/ckeditor.admin.js index 1cc5c303893..a5eb2d9afc3 100644 --- a/core/modules/ckeditor/js/ckeditor.admin.js +++ b/core/modules/ckeditor/js/ckeditor.admin.js @@ -9,9 +9,10 @@ Drupal.ckeditor = Drupal.ckeditor || {}; Drupal.behaviors.ckeditorAdmin = { attach: function attach(context) { - var $configurationForm = $(context).find('.ckeditor-toolbar-configuration').once('ckeditor-configuration'); + var configurationForm = once('ckeditor-configuration', '.ckeditor-toolbar-configuration', context); - if ($configurationForm.length) { + if (configurationForm.length) { + var $configurationForm = $(configurationForm); var $textarea = $configurationForm.find('.js-form-item-editor-settings-toolbar-button-groups').hide().find('textarea'); $configurationForm.append(drupalSettings.ckeditor.toolbarAdmin); Drupal.ckeditor.models.Model = new Drupal.ckeditor.Model({ @@ -36,9 +37,9 @@ return; } - var $configurationForm = $(context).find('.ckeditor-toolbar-configuration').findOnce('ckeditor-configuration'); + var configurationForm = once.filter('ckeditor-configuration', '.ckeditor-toolbar-configuration', context); - if ($configurationForm.length && Drupal.ckeditor.models && Drupal.ckeditor.models.Model) { + if (configurationForm.length && Drupal.ckeditor.models && Drupal.ckeditor.models.Model) { var config = Drupal.ckeditor.models.Model.toJSON().activeEditorConfig; var buttons = Drupal.ckeditor.views.controller.getButtonList(config); var $activeToolbar = $('.ckeditor-toolbar-configuration').find('.ckeditor-toolbar-active'); @@ -194,9 +195,10 @@ Drupal.behaviors.ckeditorAdminButtonPluginSettings = { attach: function attach(context) { var $context = $(context); - var $ckeditorPluginSettings = $context.find('#ckeditor-plugin-settings').once('ckeditor-plugin-settings'); + var ckeditorPluginSettings = once('ckeditor-plugin-settings', '#ckeditor-plugin-settings', context); - if ($ckeditorPluginSettings.length) { + if (ckeditorPluginSettings.length) { + var $ckeditorPluginSettings = $(ckeditorPluginSettings); $ckeditorPluginSettings.find('[data-ckeditor-buttons]').each(function () { var $this = $(this); diff --git a/core/modules/color/color.es6.js b/core/modules/color/color.es6.js index 40270959b4b..6cde1cf4430 100644 --- a/core/modules/color/color.es6.js +++ b/core/modules/color/color.es6.js @@ -18,9 +18,9 @@ let j; let colors; // This behavior attaches by ID, so is only valid once on a page. - const form = $(context) - .find('#system-theme-settings .color-form') - .once('color'); + const form = $( + once('color', '#system-theme-settings .color-form', context), + ); if (form.length === 0) { return; } @@ -30,7 +30,9 @@ let focused = null; // Add Farbtastic. - $('<div class="color-placeholder"></div>').once('color').prependTo(form); + $(once('color', $('<div class="color-placeholder"></div>'))).prependTo( + form, + ); const farb = $.farbtastic('.color-placeholder'); // Decode reference colors to HSL. @@ -180,9 +182,9 @@ // Loop through all defined gradients. Object.keys(settings.gradients || {}).forEach((i) => { // Add element to display the gradient. - $('.color-preview') - .once('color') - .append(`<div id="gradient-${i}"></div>`); + $(once('color', '.color-preview')).append( + `<div id="gradient-${i}"></div>`, + ); const gradient = $(`.color-preview #gradient-${i}`); // Add height of current gradient to the list (divided by 10). height.push(parseInt(gradient.css('height'), 10) / 10); diff --git a/core/modules/color/color.js b/core/modules/color/color.js index 233d0b0e44b..4bf2091d799 100644 --- a/core/modules/color/color.js +++ b/core/modules/color/color.js @@ -11,7 +11,7 @@ var i; var j; var colors; - var form = $(context).find('#system-theme-settings .color-form').once('color'); + var form = $(once('color', '#system-theme-settings .color-form', context)); if (form.length === 0) { return; @@ -21,7 +21,7 @@ var hooks = []; var locks = []; var focused = null; - $('<div class="color-placeholder"></div>').once('color').prependTo(form); + $(once('color', $('<div class="color-placeholder"></div>'))).prependTo(form); var farb = $.farbtastic('.color-placeholder'); var reference = settings.color.reference; Object.keys(reference || {}).forEach(function (color) { @@ -113,7 +113,7 @@ } Object.keys(settings.gradients || {}).forEach(function (i) { - $('.color-preview').once('color').append("<div id=\"gradient-".concat(i, "\"></div>")); + $(once('color', '.color-preview')).append("<div id=\"gradient-".concat(i, "\"></div>")); var gradient = $(".color-preview #gradient-".concat(i)); height.push(parseInt(gradient.css('height'), 10) / 10); width.push(parseInt(gradient.css('width'), 10) / 10); diff --git a/core/modules/color/color.libraries.yml b/core/modules/color/color.libraries.yml index f34bc9855b7..860c0c16525 100644 --- a/core/modules/color/color.libraries.yml +++ b/core/modules/color/color.libraries.yml @@ -5,7 +5,7 @@ drupal.color: dependencies: - core/jquery - core/drupal - - core/jquery.once + - core/once - core/jquery.farbtastic - color/drupal.color.preview @@ -17,7 +17,7 @@ drupal.color.preview: - core/jquery - core/drupal - core/drupalSettings - - core/jquery.once + - core/once admin: version: VERSION diff --git a/core/modules/comment/comment.libraries.yml b/core/modules/comment/comment.libraries.yml index 78c4ff0b9ad..25c81511619 100644 --- a/core/modules/comment/comment.libraries.yml +++ b/core/modules/comment/comment.libraries.yml @@ -22,7 +22,7 @@ drupal.comment-new-indicator: js/comment-new-indicator.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal - history/api - core/drupal.displace @@ -33,6 +33,6 @@ drupal.node-new-comments-link: js/node-new-comments-link.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal - history/api diff --git a/core/modules/comment/js/comment-new-indicator.es6.js b/core/modules/comment/js/comment-new-indicator.es6.js index ee6420cf8a2..ffd9efed5ef 100644 --- a/core/modules/comment/js/comment-new-indicator.es6.js +++ b/core/modules/comment/js/comment-new-indicator.es6.js @@ -10,15 +10,15 @@ /** * Processes the markup for "new comment" indicators. * - * @param {jQuery} $placeholders + * @param {Array.<Element>} placeholders * The elements that should be processed. */ - function processCommentNewIndicators($placeholders) { + function processCommentNewIndicators(placeholders) { let isFirstNewComment = true; const newCommentString = Drupal.t('new'); let $placeholder; - $placeholders.each((index, placeholder) => { + placeholders.forEach((placeholder) => { $placeholder = $(placeholder); const timestamp = parseInt( $placeholder.attr('data-comment-timestamp'), @@ -69,33 +69,34 @@ // corresponding node IDs) newer than 30 days ago that have not already // been read after their last comment timestamp. const nodeIDs = []; - const $placeholders = $(context) - .find('[data-comment-timestamp]') - .once('history') - .filter(function () { - const $placeholder = $(this); - const commentTimestamp = parseInt( - $placeholder.attr('data-comment-timestamp'), - 10, - ); - const nodeID = $placeholder - .closest('[data-history-node-id]') - .attr('data-history-node-id'); - if (Drupal.history.needsServerCheck(nodeID, commentTimestamp)) { - nodeIDs.push(nodeID); - return true; - } + const placeholders = once( + 'history', + '[data-comment-timestamp]', + context, + ).filter((placeholder) => { + const $placeholder = $(placeholder); + const commentTimestamp = parseInt( + $placeholder.attr('data-comment-timestamp'), + 10, + ); + const nodeID = $placeholder + .closest('[data-history-node-id]') + .attr('data-history-node-id'); + if (Drupal.history.needsServerCheck(nodeID, commentTimestamp)) { + nodeIDs.push(nodeID); + return true; + } - return false; - }); + return false; + }); - if ($placeholders.length === 0) { + if (placeholders.length === 0) { return; } // Fetch the node read timestamps from the server. Drupal.history.fetchTimestamps(nodeIDs, () => { - processCommentNewIndicators($placeholders); + processCommentNewIndicators(placeholders); }); }, }; diff --git a/core/modules/comment/js/comment-new-indicator.js b/core/modules/comment/js/comment-new-indicator.js index c8794e7b690..22ec2069fd0 100644 --- a/core/modules/comment/js/comment-new-indicator.js +++ b/core/modules/comment/js/comment-new-indicator.js @@ -6,11 +6,11 @@ **/ (function ($, Drupal, window) { - function processCommentNewIndicators($placeholders) { + function processCommentNewIndicators(placeholders) { var isFirstNewComment = true; var newCommentString = Drupal.t('new'); var $placeholder; - $placeholders.each(function (index, placeholder) { + placeholders.forEach(function (placeholder) { $placeholder = $(placeholder); var timestamp = parseInt($placeholder.attr('data-comment-timestamp'), 10); var $node = $placeholder.closest('[data-history-node-id]'); @@ -35,8 +35,8 @@ Drupal.behaviors.commentNewIndicator = { attach: function attach(context) { var nodeIDs = []; - var $placeholders = $(context).find('[data-comment-timestamp]').once('history').filter(function () { - var $placeholder = $(this); + var placeholders = once('history', '[data-comment-timestamp]', context).filter(function (placeholder) { + var $placeholder = $(placeholder); var commentTimestamp = parseInt($placeholder.attr('data-comment-timestamp'), 10); var nodeID = $placeholder.closest('[data-history-node-id]').attr('data-history-node-id'); @@ -48,12 +48,12 @@ return false; }); - if ($placeholders.length === 0) { + if (placeholders.length === 0) { return; } Drupal.history.fetchTimestamps(nodeIDs, function () { - processCommentNewIndicators($placeholders); + processCommentNewIndicators(placeholders); }); } }; diff --git a/core/modules/comment/js/node-new-comments-link.es6.js b/core/modules/comment/js/node-new-comments-link.es6.js index 6d6aa600723..add49dd2946 100644 --- a/core/modules/comment/js/node-new-comments-link.es6.js +++ b/core/modules/comment/js/node-new-comments-link.es6.js @@ -66,15 +66,15 @@ /** * Processes new comment links and adds appropriate text in relevant cases. * - * @param {jQuery} $placeholders + * @param {Array.<Element>} placeholders * The placeholder elements of the current page. */ - function processNodeNewCommentLinks($placeholders) { + function processNodeNewCommentLinks(placeholders) { // Figure out which placeholders need the "x new comments" links. const $placeholdersToUpdate = {}; let fieldName = 'comment'; let $placeholder; - $placeholders.each((index, placeholder) => { + placeholders.forEach((placeholder) => { $placeholder = $(placeholder); const timestamp = parseInt( $placeholder.attr('data-history-node-last-comment-timestamp'), @@ -157,38 +157,38 @@ // corresponding node IDs) newer than 30 days ago that have not already // been read after their last comment timestamp. const nodeIDs = []; - const $placeholders = $(context) - .find('[data-history-node-last-comment-timestamp]') - .once('history') - .filter(function () { - const $placeholder = $(this); - const lastCommentTimestamp = parseInt( - $placeholder.attr('data-history-node-last-comment-timestamp'), - 10, - ); - const nodeID = $placeholder - .closest('[data-history-node-id]') - .attr('data-history-node-id'); - if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) { - nodeIDs.push(nodeID); - // Hide this placeholder link until it is certain we'll need it. - hide($placeholder); - return true; - } + const placeholders = once( + 'history', + '[data-history-node-last-comment-timestamp]', + context, + ).filter((placeholder) => { + const $placeholder = $(placeholder); + const lastCommentTimestamp = parseInt( + $placeholder.attr('data-history-node-last-comment-timestamp'), + 10, + ); + const nodeID = $placeholder + .closest('[data-history-node-id]') + .attr('data-history-node-id'); + if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) { + nodeIDs.push(nodeID); + // Hide this placeholder link until it is certain we'll need it. + hide($placeholder); + return true; + } - // Remove this placeholder link from the DOM because we won't need - // it. - remove($placeholder); - return false; - }); + // Remove this placeholder link from the DOM because we won't need it. + remove($placeholder); + return false; + }); - if ($placeholders.length === 0) { + if (placeholders.length === 0) { return; } // Perform an AJAX request to retrieve node read timestamps. Drupal.history.fetchTimestamps(nodeIDs, () => { - processNodeNewCommentLinks($placeholders); + processNodeNewCommentLinks(placeholders); }); }, }; diff --git a/core/modules/comment/js/node-new-comments-link.js b/core/modules/comment/js/node-new-comments-link.js index a3a821ddd14..29d268a49f2 100644 --- a/core/modules/comment/js/node-new-comments-link.js +++ b/core/modules/comment/js/node-new-comments-link.js @@ -18,11 +18,11 @@ return $placeholder.closest('.comment-new-comments').prev().removeClass('last').end().show(); } - function processNodeNewCommentLinks($placeholders) { + function processNodeNewCommentLinks(placeholders) { var $placeholdersToUpdate = {}; var fieldName = 'comment'; var $placeholder; - $placeholders.each(function (index, placeholder) { + placeholders.forEach(function (placeholder) { $placeholder = $(placeholder); var timestamp = parseInt($placeholder.attr('data-history-node-last-comment-timestamp'), 10); fieldName = $placeholder.attr('data-history-node-field-name'); @@ -69,8 +69,8 @@ Drupal.behaviors.nodeNewCommentsLink = { attach: function attach(context) { var nodeIDs = []; - var $placeholders = $(context).find('[data-history-node-last-comment-timestamp]').once('history').filter(function () { - var $placeholder = $(this); + var placeholders = once('history', '[data-history-node-last-comment-timestamp]', context).filter(function (placeholder) { + var $placeholder = $(placeholder); var lastCommentTimestamp = parseInt($placeholder.attr('data-history-node-last-comment-timestamp'), 10); var nodeID = $placeholder.closest('[data-history-node-id]').attr('data-history-node-id'); @@ -84,12 +84,12 @@ return false; }); - if ($placeholders.length === 0) { + if (placeholders.length === 0) { return; } Drupal.history.fetchTimestamps(nodeIDs, function () { - processNodeNewCommentLinks($placeholders); + processNodeNewCommentLinks(placeholders); }); } }; diff --git a/core/modules/content_translation/content_translation.admin.es6.js b/core/modules/content_translation/content_translation.admin.es6.js index 600994859c5..1360ca33474 100644 --- a/core/modules/content_translation/content_translation.admin.es6.js +++ b/core/modules/content_translation/content_translation.admin.es6.js @@ -82,29 +82,29 @@ attach(context) { // Initially hide all field rows for non translatable bundles and all // column rows for non translatable fields. - $(context) - .find('table .bundle-settings .translatable :input') - .once('translation-entity-admin-hide') - .each(function () { - const $input = $(this); - const $bundleSettings = $input.closest('.bundle-settings'); - if (!$input.is(':checked')) { - $bundleSettings.nextUntil('.bundle-settings').hide(); - } else { - $bundleSettings - .nextUntil('.bundle-settings', '.field-settings') - .find('.translatable :input:not(:checked)') - .closest('.field-settings') - .nextUntil(':not(.column-settings)') - .hide(); - } - }); + once( + 'translation-entity-admin-hide', + // Keep jQuery because of the use of `:input`. + $(context).find('table .bundle-settings .translatable :input'), + ).forEach((input) => { + const $input = $(input); + const $bundleSettings = $input.closest('.bundle-settings'); + if (!$input.is(':checked')) { + $bundleSettings.nextUntil('.bundle-settings').hide(); + } else { + $bundleSettings + .nextUntil('.bundle-settings', '.field-settings') + .find('.translatable :input:not(:checked)') + .closest('.field-settings') + .nextUntil(':not(.column-settings)') + .hide(); + } + }); // When a bundle is made translatable all of its fields should inherit // this setting. Instead when it is made non translatable its fields are // hidden, since their translatability no longer matters. - $('body') - .once('translation-entity-admin-bind') + $(once('translation-entity-admin-bind', 'body')) .on('click', 'table .bundle-settings .translatable :input', (e) => { const $target = $(e.target); const $bundleSettings = $target.closest('.bundle-settings'); diff --git a/core/modules/content_translation/content_translation.admin.js b/core/modules/content_translation/content_translation.admin.js index fcf92a971b4..7b243b5f88a 100644 --- a/core/modules/content_translation/content_translation.admin.js +++ b/core/modules/content_translation/content_translation.admin.js @@ -52,8 +52,8 @@ }; Drupal.behaviors.contentTranslation = { attach: function attach(context) { - $(context).find('table .bundle-settings .translatable :input').once('translation-entity-admin-hide').each(function () { - var $input = $(this); + once('translation-entity-admin-hide', $(context).find('table .bundle-settings .translatable :input')).forEach(function (input) { + var $input = $(input); var $bundleSettings = $input.closest('.bundle-settings'); if (!$input.is(':checked')) { @@ -62,7 +62,7 @@ $bundleSettings.nextUntil('.bundle-settings', '.field-settings').find('.translatable :input:not(:checked)').closest('.field-settings').nextUntil(':not(.column-settings)').hide(); } }); - $('body').once('translation-entity-admin-bind').on('click', 'table .bundle-settings .translatable :input', function (e) { + $(once('translation-entity-admin-bind', 'body')).on('click', 'table .bundle-settings .translatable :input', function (e) { var $target = $(e.target); var $bundleSettings = $target.closest('.bundle-settings'); var $settings = $bundleSettings.nextUntil('.bundle-settings'); diff --git a/core/modules/content_translation/content_translation.libraries.yml b/core/modules/content_translation/content_translation.libraries.yml index 3dd1ce0dc05..3857be167e7 100644 --- a/core/modules/content_translation/content_translation.libraries.yml +++ b/core/modules/content_translation/content_translation.libraries.yml @@ -8,4 +8,4 @@ drupal.content_translation.admin: dependencies: - core/jquery - core/drupal - - core/jquery.once + - core/once diff --git a/core/modules/contextual/contextual.libraries.yml b/core/modules/contextual/contextual.libraries.yml index ec9068037b1..3a5918f7e15 100644 --- a/core/modules/contextual/contextual.libraries.yml +++ b/core/modules/contextual/contextual.libraries.yml @@ -24,7 +24,7 @@ drupal.contextual-links: - core/drupalSettings - core/backbone - core/modernizr - - core/jquery.once + - core/once drupal.contextual-toolbar: version: VERSION @@ -42,6 +42,6 @@ drupal.contextual-toolbar: - core/jquery - core/drupal - core/backbone - - core/jquery.once + - core/once - core/drupal.tabbingmanager - core/drupal.announce diff --git a/core/modules/contextual/js/contextual.es6.js b/core/modules/contextual/js/contextual.es6.js index 12f1405a807..1c1c485c1c3 100644 --- a/core/modules/contextual/js/contextual.es6.js +++ b/core/modules/contextual/js/contextual.es6.js @@ -154,9 +154,9 @@ const $context = $(context); // Find all contextual links placeholders, if any. - let $placeholders = $context - .find('[data-contextual-id]') - .once('contextual-render'); + let $placeholders = $( + once('contextual-render', '[data-contextual-id]', context), + ); if ($placeholders.length === 0) { return; } diff --git a/core/modules/contextual/js/contextual.js b/core/modules/contextual/js/contextual.js index 62c9e2c3215..4911b2949b8 100644 --- a/core/modules/contextual/js/contextual.js +++ b/core/modules/contextual/js/contextual.js @@ -88,7 +88,7 @@ Drupal.behaviors.contextual = { attach: function attach(context) { var $context = $(context); - var $placeholders = $context.find('[data-contextual-id]').once('contextual-render'); + var $placeholders = $(once('contextual-render', '[data-contextual-id]', context)); if ($placeholders.length === 0) { return; diff --git a/core/modules/contextual/js/contextual.toolbar.es6.js b/core/modules/contextual/js/contextual.toolbar.es6.js index 5f93b4ae8d8..79ed6cd8df0 100644 --- a/core/modules/contextual/js/contextual.toolbar.es6.js +++ b/core/modules/contextual/js/contextual.toolbar.es6.js @@ -59,7 +59,7 @@ */ Drupal.behaviors.contextualToolbar = { attach(context) { - if ($('body').once('contextualToolbar-init').length) { + if (once('contextualToolbar-init', 'body').length) { initContextualToolbar(context); } }, diff --git a/core/modules/contextual/js/contextual.toolbar.js b/core/modules/contextual/js/contextual.toolbar.js index 5f193ed06ad..bbd8792d069 100644 --- a/core/modules/contextual/js/contextual.toolbar.js +++ b/core/modules/contextual/js/contextual.toolbar.js @@ -34,7 +34,7 @@ Drupal.behaviors.contextualToolbar = { attach: function attach(context) { - if ($('body').once('contextualToolbar-init').length) { + if (once('contextualToolbar-init', 'body').length) { initContextualToolbar(context); } } diff --git a/core/modules/editor/editor.libraries.yml b/core/modules/editor/editor.libraries.yml index 6c4b34f6cde..6f6c8f1b201 100644 --- a/core/modules/editor/editor.libraries.yml +++ b/core/modules/editor/editor.libraries.yml @@ -4,7 +4,7 @@ drupal.editor.admin: js/editor.admin.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal drupal.editor: @@ -15,7 +15,7 @@ drupal.editor: - core/jquery - core/drupal - core/drupalSettings - - core/jquery.once + - core/once - core/drupal.dialog drupal.editor.dialog: diff --git a/core/modules/editor/js/editor.admin.es6.js b/core/modules/editor/js/editor.admin.es6.js index b1688ee8ff8..53478a98923 100644 --- a/core/modules/editor/js/editor.admin.es6.js +++ b/core/modules/editor/js/editor.admin.es6.js @@ -1002,28 +1002,25 @@ */ Drupal.behaviors.initializeFilterConfiguration = { attach(context, settings) { - const $context = $(context); + once( + 'filter-editor-status', + '#filters-status-wrapper input.form-checkbox', + context, + ).forEach((checkbox) => { + const $checkbox = $(checkbox); + const nameAttribute = $checkbox.attr('name'); - $context - .find('#filters-status-wrapper input.form-checkbox') - .once('filter-editor-status') - .each(function () { - const $checkbox = $(this); - const nameAttribute = $checkbox.attr('name'); + // The filter's checkbox has a name attribute of the form + // "filters[<name of filter>][status]", parse "<name of filter>" from + // it. + const filterID = nameAttribute.substring(8, nameAttribute.indexOf(']')); - // The filter's checkbox has a name attribute of the form - // "filters[<name of filter>][status]", parse "<name of filter>" - // from it. - const filterID = nameAttribute.substring( - 8, - nameAttribute.indexOf(']'), - ); - - // Create a Drupal.FilterStatus object to track the state (whether it's - // active or not and its current settings, if any) of each filter. - Drupal.filterConfiguration.statuses[filterID] = - new Drupal.FilterStatus(filterID); - }); + // Create a Drupal.FilterStatus object to track the state (whether it's + // active or not and its current settings, if any) of each filter. + Drupal.filterConfiguration.statuses[filterID] = new Drupal.FilterStatus( + filterID, + ); + }); }, }; })(jQuery, _, Drupal, document); diff --git a/core/modules/editor/js/editor.admin.js b/core/modules/editor/js/editor.admin.js index 4bc14761d28..eacbaa17d2e 100644 --- a/core/modules/editor/js/editor.admin.js +++ b/core/modules/editor/js/editor.admin.js @@ -360,9 +360,8 @@ }; Drupal.behaviors.initializeFilterConfiguration = { attach: function attach(context, settings) { - var $context = $(context); - $context.find('#filters-status-wrapper input.form-checkbox').once('filter-editor-status').each(function () { - var $checkbox = $(this); + once('filter-editor-status', '#filters-status-wrapper input.form-checkbox', context).forEach(function (checkbox) { + var $checkbox = $(checkbox); var nameAttribute = $checkbox.attr('name'); var filterID = nameAttribute.substring(8, nameAttribute.indexOf(']')); Drupal.filterConfiguration.statuses[filterID] = new Drupal.FilterStatus(filterID); diff --git a/core/modules/editor/js/editor.es6.js b/core/modules/editor/js/editor.es6.js index ecaa9c7c9a7..b6deb24b62f 100644 --- a/core/modules/editor/js/editor.es6.js +++ b/core/modules/editor/js/editor.es6.js @@ -204,57 +204,54 @@ return; } - $(context) - .find('[data-editor-for]') - .once('editor') - .each(function () { - const $this = $(this); - const field = findFieldForFormatSelector($this); + once('editor', '[data-editor-for]', context).forEach((editor) => { + const $this = $(editor); + const field = findFieldForFormatSelector($this); - // Opt-out if no supported text area was found. - if (!field) { - return; - } + // Opt-out if no supported text area was found. + if (!field) { + return; + } - // Store the current active format. - const activeFormatID = $this.val(); - field.setAttribute('data-editor-active-text-format', activeFormatID); + // Store the current active format. + const activeFormatID = $this.val(); + field.setAttribute('data-editor-active-text-format', activeFormatID); - // Directly attach this text editor, if the text format is enabled. - if (settings.editor.formats[activeFormatID]) { - // XSS protection for the current text format/editor is performed on - // the server side, so we don't need to do anything special here. - Drupal.editorAttach(field, settings.editor.formats[activeFormatID]); - } - // When there is no text editor for this text format, still track - // changes, because the user has the ability to switch to some text - // editor, otherwise this code would not be executed. - $(field).on('change.editor keypress.editor', () => { - field.setAttribute('data-editor-value-is-changed', 'true'); - // Just knowing that the value was changed is enough, stop tracking. - $(field).off('.editor'); - }); + // Directly attach this text editor, if the text format is enabled. + if (settings.editor.formats[activeFormatID]) { + // XSS protection for the current text format/editor is performed on + // the server side, so we don't need to do anything special here. + Drupal.editorAttach(field, settings.editor.formats[activeFormatID]); + } + // When there is no text editor for this text format, still track + // changes, because the user has the ability to switch to some text + // editor, otherwise this code would not be executed. + $(field).on('change.editor keypress.editor', () => { + field.setAttribute('data-editor-value-is-changed', 'true'); + // Just knowing that the value was changed is enough, stop tracking. + $(field).off('.editor'); + }); - // Attach onChange handler to text format selector element. - if ($this.is('select')) { - $this.on('change.editorAttach', { field }, onTextFormatChange); + // Attach onChange handler to text format selector element. + if ($this.is('select')) { + $this.on('change.editorAttach', { field }, onTextFormatChange); + } + // Detach any editor when the containing form is submitted. + $this.parents('form').on('submit', (event) => { + // Do not detach if the event was canceled. + if (event.isDefaultPrevented()) { + return; + } + // Detach the current editor (if any). + if (settings.editor.formats[activeFormatID]) { + Drupal.editorDetach( + field, + settings.editor.formats[activeFormatID], + 'serialize', + ); } - // Detach any editor when the containing form is submitted. - $this.parents('form').on('submit', (event) => { - // Do not detach if the event was canceled. - if (event.isDefaultPrevented()) { - return; - } - // Detach the current editor (if any). - if (settings.editor.formats[activeFormatID]) { - Drupal.editorDetach( - field, - settings.editor.formats[activeFormatID], - 'serialize', - ); - } - }); }); + }); }, detach(context, settings, trigger) { @@ -264,13 +261,13 @@ if (trigger === 'serialize') { // Removing the editor-processed class guarantees that the editor will // be reattached. Only do this if we're planning to destroy the editor. - editors = $(context).find('[data-editor-for]').findOnce('editor'); + editors = once.filter('editor', '[data-editor-for]', context); } else { - editors = $(context).find('[data-editor-for]').removeOnce('editor'); + editors = once.remove('editor', '[data-editor-for]', context); } - editors.each(function () { - const $this = $(this); + editors.forEach((editor) => { + const $this = $(editor); const activeFormatID = $this.val(); const field = findFieldForFormatSelector($this); if (field && activeFormatID in settings.editor.formats) { diff --git a/core/modules/editor/js/editor.js b/core/modules/editor/js/editor.js index 1fa89a2867e..622251932e8 100644 --- a/core/modules/editor/js/editor.js +++ b/core/modules/editor/js/editor.js @@ -109,8 +109,8 @@ return; } - $(context).find('[data-editor-for]').once('editor').each(function () { - var $this = $(this); + once('editor', '[data-editor-for]', context).forEach(function (editor) { + var $this = $(editor); var field = findFieldForFormatSelector($this); if (!field) { @@ -150,13 +150,13 @@ var editors; if (trigger === 'serialize') { - editors = $(context).find('[data-editor-for]').findOnce('editor'); + editors = once.filter('editor', '[data-editor-for]', context); } else { - editors = $(context).find('[data-editor-for]').removeOnce('editor'); + editors = once.remove('editor', '[data-editor-for]', context); } - editors.each(function () { - var $this = $(this); + editors.forEach(function (editor) { + var $this = $(editor); var activeFormatID = $this.val(); var field = findFieldForFormatSelector($this); diff --git a/core/modules/field_ui/field_ui.es6.js b/core/modules/field_ui/field_ui.es6.js index 86268048e9d..4779b5f8628 100644 --- a/core/modules/field_ui/field_ui.es6.js +++ b/core/modules/field_ui/field_ui.es6.js @@ -12,10 +12,13 @@ */ Drupal.behaviors.fieldUIFieldStorageAddForm = { attach(context) { - const $form = $(context) - .find('[data-drupal-selector="field-ui-field-storage-add-form"]') - .once('field_ui_add'); - if ($form.length) { + const form = once( + 'field_ui_add', + '[data-drupal-selector="field-ui-field-storage-add-form"]', + context, + ); + if (form.length) { + const $form = $(form); // Add a few 'js-form-required' and 'form-required' css classes here. // We can not use the Form API '#required' property because both label // elements for "add new" and "re-use existing" can never be filled and @@ -80,16 +83,17 @@ */ Drupal.behaviors.fieldUIDisplayOverview = { attach(context, settings) { - $(context) - .find('table#field-display-overview') - .once('field-display-overview') - .each(function () { - Drupal.fieldUIOverview.attach( - this, - settings.fieldUIRowsData, - Drupal.fieldUIDisplayOverview, - ); - }); + once( + 'field-display-overview', + 'table#field-display-overview', + context, + ).forEach((overview) => { + Drupal.fieldUIOverview.attach( + overview, + settings.fieldUIRowsData, + Drupal.fieldUIDisplayOverview, + ); + }); }, }; diff --git a/core/modules/field_ui/field_ui.js b/core/modules/field_ui/field_ui.js index 8c5ba129aee..8261ea7dbe2 100644 --- a/core/modules/field_ui/field_ui.js +++ b/core/modules/field_ui/field_ui.js @@ -8,9 +8,10 @@ (function ($, Drupal, drupalSettings) { Drupal.behaviors.fieldUIFieldStorageAddForm = { attach: function attach(context) { - var $form = $(context).find('[data-drupal-selector="field-ui-field-storage-add-form"]').once('field_ui_add'); + var form = once('field_ui_add', '[data-drupal-selector="field-ui-field-storage-add-form"]', context); - if ($form.length) { + if (form.length) { + var $form = $(form); $form.find('.js-form-item-label label,' + '.js-form-item-field-name label,' + '.js-form-item-existing-storage-label label').addClass('js-form-required form-required'); var $newFieldType = $form.find('select[name="new_storage_type"]'); var $existingStorageName = $form.find('select[name="existing_storage_name"]'); @@ -36,8 +37,8 @@ }; Drupal.behaviors.fieldUIDisplayOverview = { attach: function attach(context, settings) { - $(context).find('table#field-display-overview').once('field-display-overview').each(function () { - Drupal.fieldUIOverview.attach(this, settings.fieldUIRowsData, Drupal.fieldUIDisplayOverview); + once('field-display-overview', 'table#field-display-overview', context).forEach(function (overview) { + Drupal.fieldUIOverview.attach(overview, settings.fieldUIRowsData, Drupal.fieldUIDisplayOverview); }); } }; diff --git a/core/modules/field_ui/field_ui.libraries.yml b/core/modules/field_ui/field_ui.libraries.yml index 4add558fe38..8db10f6e91d 100644 --- a/core/modules/field_ui/field_ui.libraries.yml +++ b/core/modules/field_ui/field_ui.libraries.yml @@ -9,4 +9,4 @@ drupal.field_ui: - core/jquery - core/drupal - core/drupalSettings - - core/jquery.once + - core/once diff --git a/core/modules/file/file.es6.js b/core/modules/file/file.es6.js index ee01e71f0b5..3c6d19a4c38 100644 --- a/core/modules/file/file.es6.js +++ b/core/modules/file/file.es6.js @@ -24,14 +24,11 @@ let elements; function initFileValidation(selector) { - $context - .find(selector) - .once('fileValidate') - .on( - 'change.fileValidate', - { extensions: elements[selector] }, - Drupal.file.validateExtension, - ); + $(once('fileValidate', $context.find(selector))).on( + 'change.fileValidate', + { extensions: elements[selector] }, + Drupal.file.validateExtension, + ); } if (settings.file && settings.file.elements) { @@ -44,10 +41,10 @@ let elements; function removeFileValidation(selector) { - $context - .find(selector) - .removeOnce('fileValidate') - .off('change.fileValidate', Drupal.file.validateExtension); + $(once.remove('fileValidate', $context.find(selector))).off( + 'change.fileValidate', + Drupal.file.validateExtension, + ); } if (trigger === 'unload' && settings.file && settings.file.elements) { @@ -69,17 +66,16 @@ */ Drupal.behaviors.fileAutoUpload = { attach(context) { - $(context) - .find('input[type="file"]') - .once('auto-file-upload') - .on('change.autoFileUpload', Drupal.file.triggerUploadButton); + $(once('auto-file-upload', 'input[type="file"]', context)).on( + 'change.autoFileUpload', + Drupal.file.triggerUploadButton, + ); }, detach(context, settings, trigger) { if (trigger === 'unload') { - $(context) - .find('input[type="file"]') - .removeOnce('auto-file-upload') - .off('.autoFileUpload'); + $(once.remove('auto-file-upload', 'input[type="file"]', context)).off( + '.autoFileUpload', + ); } }, }; diff --git a/core/modules/file/file.js b/core/modules/file/file.js index 7a7ae89f25b..b963984b442 100644 --- a/core/modules/file/file.js +++ b/core/modules/file/file.js @@ -12,7 +12,7 @@ var elements; function initFileValidation(selector) { - $context.find(selector).once('fileValidate').on('change.fileValidate', { + $(once('fileValidate', $context.find(selector))).on('change.fileValidate', { extensions: elements[selector] }, Drupal.file.validateExtension); } @@ -27,7 +27,7 @@ var elements; function removeFileValidation(selector) { - $context.find(selector).removeOnce('fileValidate').off('change.fileValidate', Drupal.file.validateExtension); + $(once.remove('fileValidate', $context.find(selector))).off('change.fileValidate', Drupal.file.validateExtension); } if (trigger === 'unload' && settings.file && settings.file.elements) { @@ -38,11 +38,11 @@ }; Drupal.behaviors.fileAutoUpload = { attach: function attach(context) { - $(context).find('input[type="file"]').once('auto-file-upload').on('change.autoFileUpload', Drupal.file.triggerUploadButton); + $(once('auto-file-upload', 'input[type="file"]', context)).on('change.autoFileUpload', Drupal.file.triggerUploadButton); }, detach: function detach(context, settings, trigger) { if (trigger === 'unload') { - $(context).find('input[type="file"]').removeOnce('auto-file-upload').off('.autoFileUpload'); + $(once.remove('auto-file-upload', 'input[type="file"]', context)).off('.autoFileUpload'); } } }; diff --git a/core/modules/file/file.libraries.yml b/core/modules/file/file.libraries.yml index def38d9617e..81c9324ea53 100644 --- a/core/modules/file/file.libraries.yml +++ b/core/modules/file/file.libraries.yml @@ -4,6 +4,6 @@ drupal.file: file.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal - core/drupalSettings diff --git a/core/modules/filter/filter.admin.es6.js b/core/modules/filter/filter.admin.es6.js index 9e6a038fb05..731ed5b7a45 100644 --- a/core/modules/filter/filter.admin.es6.js +++ b/core/modules/filter/filter.admin.es6.js @@ -15,59 +15,60 @@ Drupal.behaviors.filterStatus = { attach(context, settings) { const $context = $(context); - $context - .find('#filters-status-wrapper input.form-checkbox') - .once('filter-status') - .each(function () { - const $checkbox = $(this); - // Retrieve the tabledrag row belonging to this filter. - const $row = $context - .find(`#${$checkbox.attr('id').replace(/-status$/, '-weight')}`) - .closest('tr'); - // Retrieve the vertical tab belonging to this filter. - const $filterSettings = $context.find( - `[data-drupal-selector='${$checkbox - .attr('id') - .replace(/-status$/, '-settings')}']`, - ); - const filterSettingsTab = $filterSettings.data('verticalTab'); + once( + 'filter-status', + '#filters-status-wrapper input.form-checkbox', + context, + ).forEach((checkbox) => { + const $checkbox = $(checkbox); + // Retrieve the tabledrag row belonging to this filter. + const $row = $context + .find(`#${$checkbox.attr('id').replace(/-status$/, '-weight')}`) + .closest('tr'); + // Retrieve the vertical tab belonging to this filter. + const $filterSettings = $context.find( + `[data-drupal-selector='${$checkbox + .attr('id') + .replace(/-status$/, '-settings')}']`, + ); + const filterSettingsTab = $filterSettings.data('verticalTab'); - // Bind click handler to this checkbox to conditionally show and hide - // the filter's tableDrag row and vertical tab pane. - $checkbox.on('click.filterUpdate', () => { - if ($checkbox.is(':checked')) { - $row.show(); - if (filterSettingsTab) { - filterSettingsTab.tabShow().updateSummary(); - } else { - // On very narrow viewports, Vertical Tabs are disabled. - $filterSettings.show(); - } + // Bind click handler to this checkbox to conditionally show and hide + // the filter's tableDrag row and vertical tab pane. + $checkbox.on('click.filterUpdate', () => { + if ($checkbox.is(':checked')) { + $row.show(); + if (filterSettingsTab) { + filterSettingsTab.tabShow().updateSummary(); } else { - $row.hide(); - if (filterSettingsTab) { - filterSettingsTab.tabHide().updateSummary(); - } else { - // On very narrow viewports, Vertical Tabs are disabled. - $filterSettings.hide(); - } + // On very narrow viewports, Vertical Tabs are disabled. + $filterSettings.show(); + } + } else { + $row.hide(); + if (filterSettingsTab) { + filterSettingsTab.tabHide().updateSummary(); + } else { + // On very narrow viewports, Vertical Tabs are disabled. + $filterSettings.hide(); } - // Restripe table after toggling visibility of table row. - Drupal.tableDrag['filter-order'].restripeTable(); - }); - - // Attach summary for configurable filters (only for screen readers). - if (filterSettingsTab) { - filterSettingsTab.details.drupalSetSummary(() => - $checkbox.is(':checked') - ? Drupal.t('Enabled') - : Drupal.t('Disabled'), - ); } - - // Trigger our bound click handler to update elements to initial state. - $checkbox.triggerHandler('click.filterUpdate'); + // Restripe table after toggling visibility of table row. + Drupal.tableDrag['filter-order'].restripeTable(); }); + + // Attach summary for configurable filters (only for screen readers). + if (filterSettingsTab) { + filterSettingsTab.details.drupalSetSummary(() => + $checkbox.is(':checked') + ? Drupal.t('Enabled') + : Drupal.t('Disabled'), + ); + } + + // Trigger our bound click handler to update elements to initial state. + $checkbox.triggerHandler('click.filterUpdate'); + }); }, }; })(jQuery, Drupal); diff --git a/core/modules/filter/filter.admin.js b/core/modules/filter/filter.admin.js index c4d8315d366..43baa73394c 100644 --- a/core/modules/filter/filter.admin.js +++ b/core/modules/filter/filter.admin.js @@ -9,8 +9,8 @@ Drupal.behaviors.filterStatus = { attach: function attach(context, settings) { var $context = $(context); - $context.find('#filters-status-wrapper input.form-checkbox').once('filter-status').each(function () { - var $checkbox = $(this); + once('filter-status', '#filters-status-wrapper input.form-checkbox', context).forEach(function (checkbox) { + var $checkbox = $(checkbox); var $row = $context.find("#".concat($checkbox.attr('id').replace(/-status$/, '-weight'))).closest('tr'); var $filterSettings = $context.find("[data-drupal-selector='".concat($checkbox.attr('id').replace(/-status$/, '-settings'), "']")); var filterSettingsTab = $filterSettings.data('verticalTab'); diff --git a/core/modules/filter/filter.es6.js b/core/modules/filter/filter.es6.js index afbdc5b0cf4..58b7232cee2 100644 --- a/core/modules/filter/filter.es6.js +++ b/core/modules/filter/filter.es6.js @@ -25,9 +25,7 @@ .show(); } - $(context) - .find('.js-filter-guidelines') - .once('filter-guidelines') + $(once('filter-guidelines', '.js-filter-guidelines', context)) .find(':header') .hide() .closest('.js-filter-wrapper') diff --git a/core/modules/filter/filter.filter_html.admin.es6.js b/core/modules/filter/filter.filter_html.admin.es6.js index 6b4c26a5952..05cb0508c27 100644 --- a/core/modules/filter/filter.filter_html.admin.es6.js +++ b/core/modules/filter/filter.filter_html.admin.es6.js @@ -67,43 +67,44 @@ attach(context, settings) { const that = this; - $(context) - .find('[name="filters[filter_html][settings][allowed_html]"]') - .once('filter-filter_html-updating') - .each(function () { - that.$allowedHTMLFormItem = $(this); - that.$allowedHTMLDescription = that.$allowedHTMLFormItem - .closest('.js-form-item') - .find('.description'); - that.userTags = that._parseSetting(this.value); + once( + 'filter-filter_html-updating', + '[name="filters[filter_html][settings][allowed_html]"]', + context, + ).forEach((formItem) => { + that.$allowedHTMLFormItem = $(formItem); + that.$allowedHTMLDescription = that.$allowedHTMLFormItem + .closest('.js-form-item') + .find('.description'); + that.userTags = that._parseSetting(formItem.value); - // Update the new allowed tags based on added text editor features. - $(document) - .on('drupalEditorFeatureAdded', (e, feature) => { + // Update the new allowed tags based on added text editor features. + $(document) + .on('drupalEditorFeatureAdded', (e, feature) => { + that.newFeatures[feature.name] = feature.rules; + that._updateAllowedTags(); + }) + .on('drupalEditorFeatureModified', (e, feature) => { + if (that.newFeatures.hasOwnProperty(feature.name)) { that.newFeatures[feature.name] = feature.rules; that._updateAllowedTags(); - }) - .on('drupalEditorFeatureModified', (e, feature) => { - if (that.newFeatures.hasOwnProperty(feature.name)) { - that.newFeatures[feature.name] = feature.rules; - that._updateAllowedTags(); - } - }) - .on('drupalEditorFeatureRemoved', (e, feature) => { - if (that.newFeatures.hasOwnProperty(feature.name)) { - delete that.newFeatures[feature.name]; - that._updateAllowedTags(); - } - }); - - // When the allowed tags list is manually changed, update userTags. - that.$allowedHTMLFormItem.on('change.updateUserTags', function () { - that.userTags = _.difference( - that._parseSetting(this.value), - that.autoTags, - ); + } + }) + .on('drupalEditorFeatureRemoved', (e, feature) => { + if (that.newFeatures.hasOwnProperty(feature.name)) { + delete that.newFeatures[feature.name]; + that._updateAllowedTags(); + } }); + + // When the allowed tags list is manually changed, update userTags. + that.$allowedHTMLFormItem.on('change.updateUserTags', function () { + that.userTags = _.difference( + that._parseSetting(this.value), + that.autoTags, + ); }); + }); }, /** diff --git a/core/modules/filter/filter.filter_html.admin.js b/core/modules/filter/filter.filter_html.admin.js index 44b665cdbd5..d217351661b 100644 --- a/core/modules/filter/filter.filter_html.admin.js +++ b/core/modules/filter/filter.filter_html.admin.js @@ -30,10 +30,10 @@ newFeatures: {}, attach: function attach(context, settings) { var that = this; - $(context).find('[name="filters[filter_html][settings][allowed_html]"]').once('filter-filter_html-updating').each(function () { - that.$allowedHTMLFormItem = $(this); + once('filter-filter_html-updating', '[name="filters[filter_html][settings][allowed_html]"]', context).forEach(function (formItem) { + that.$allowedHTMLFormItem = $(formItem); that.$allowedHTMLDescription = that.$allowedHTMLFormItem.closest('.js-form-item').find('.description'); - that.userTags = that._parseSetting(this.value); + that.userTags = that._parseSetting(formItem.value); $(document).on('drupalEditorFeatureAdded', function (e, feature) { that.newFeatures[feature.name] = feature.rules; diff --git a/core/modules/filter/filter.js b/core/modules/filter/filter.js index 55736bddcf3..e8d57f1d79d 100644 --- a/core/modules/filter/filter.js +++ b/core/modules/filter/filter.js @@ -14,7 +14,7 @@ $this.closest('.js-filter-wrapper').find('[data-drupal-format-id]').hide().filter("[data-drupal-format-id=\"".concat(value, "\"]")).show(); } - $(context).find('.js-filter-guidelines').once('filter-guidelines').find(':header').hide().closest('.js-filter-wrapper').find('select.js-filter-list').on('change.filterGuidelines', updateFilterGuidelines).trigger('change.filterGuidelines'); + $(once('filter-guidelines', '.js-filter-guidelines', context)).find(':header').hide().closest('.js-filter-wrapper').find('select.js-filter-list').on('change.filterGuidelines', updateFilterGuidelines).trigger('change.filterGuidelines'); } }; })(jQuery, Drupal);
\ No newline at end of file diff --git a/core/modules/filter/filter.libraries.yml b/core/modules/filter/filter.libraries.yml index f20613205f5..f3ad1144341 100644 --- a/core/modules/filter/filter.libraries.yml +++ b/core/modules/filter/filter.libraries.yml @@ -5,7 +5,7 @@ drupal.filter.admin: dependencies: - core/jquery - core/drupal - - core/jquery.once + - core/once - core/drupal.form drupal.filter.filter_html.admin: @@ -14,7 +14,7 @@ drupal.filter.filter_html.admin: filter.filter_html.admin.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/underscore drupal.filter: @@ -24,7 +24,7 @@ drupal.filter: dependencies: - core/jquery - core/drupal - - core/jquery.once + - core/once caption: version: VERSION diff --git a/core/modules/language/language.admin.es6.js b/core/modules/language/language.admin.es6.js index 6f7483a530a..62724214afa 100644 --- a/core/modules/language/language.admin.es6.js +++ b/core/modules/language/language.admin.es6.js @@ -28,11 +28,13 @@ } // Bind hide/show and rearrange customization checkboxes. - $configForm - .once('negotiation-language-admin-bind') - .on('change', inputSelector, (event) => { + $(once('negotiation-language-admin-bind', $configForm)).on( + 'change', + inputSelector, + (event) => { toggleTable(event.target); - }); + }, + ); // Initially, hide language detection types that are not customized. $configForm .find(`${inputSelector}:not(:checked)`) diff --git a/core/modules/language/language.admin.js b/core/modules/language/language.admin.js index 4011af980c3..4ae06b194e0 100644 --- a/core/modules/language/language.admin.js +++ b/core/modules/language/language.admin.js @@ -16,7 +16,7 @@ $checkbox.closest('.table-language-group').find('table, .tabledrag-toggle-weight').toggle($checkbox.prop('checked')); } - $configForm.once('negotiation-language-admin-bind').on('change', inputSelector, function (event) { + $(once('negotiation-language-admin-bind', $configForm)).on('change', inputSelector, function (event) { toggleTable(event.target); }); $configForm.find("".concat(inputSelector, ":not(:checked)")).each(function (index, element) { diff --git a/core/modules/language/language.libraries.yml b/core/modules/language/language.libraries.yml index 0c4cc8c2973..0e7ff2c3d0d 100644 --- a/core/modules/language/language.libraries.yml +++ b/core/modules/language/language.libraries.yml @@ -8,4 +8,4 @@ drupal.language.admin: dependencies: - core/jquery - core/drupal - - core/jquery.once + - core/once diff --git a/core/modules/layout_builder/js/layout-builder.es6.js b/core/modules/layout_builder/js/layout-builder.es6.js index 0b4885282b5..149d2bd53a9 100644 --- a/core/modules/layout_builder/js/layout-builder.es6.js +++ b/core/modules/layout_builder/js/layout-builder.es6.js @@ -88,9 +88,9 @@ } }; - $('input.js-layout-builder-filter', context) - .once('block-filter-text') - .on('keyup', debounce(filterBlockList, 200)); + $( + once('block-filter-text', 'input.js-layout-builder-filter', context), + ).on('keyup', debounce(filterBlockList, 200)); }, }; diff --git a/core/modules/layout_builder/js/layout-builder.js b/core/modules/layout_builder/js/layout-builder.js index 27fa04522f4..a3fc41e9c2c 100644 --- a/core/modules/layout_builder/js/layout-builder.js +++ b/core/modules/layout_builder/js/layout-builder.js @@ -42,7 +42,7 @@ } }; - $('input.js-layout-builder-filter', context).once('block-filter-text').on('keyup', debounce(filterBlockList, 200)); + $(once('block-filter-text', 'input.js-layout-builder-filter', context)).on('keyup', debounce(filterBlockList, 200)); } }; diff --git a/core/modules/locale/locale.admin.es6.js b/core/modules/locale/locale.admin.es6.js index d332922de9a..54e8e16daea 100644 --- a/core/modules/locale/locale.admin.es6.js +++ b/core/modules/locale/locale.admin.es6.js @@ -16,10 +16,9 @@ */ Drupal.behaviors.localeTranslateDirty = { attach() { - const $form = $('#locale-translate-edit-form').once( - 'localetranslatedirty', - ); - if ($form.length) { + const form = once('localetranslatedirty', '#locale-translate-edit-form'); + if (form.length) { + const $form = $(form); // Display a notice if any row changed. $form.one('formUpdated.localeTranslateDirty', 'table', function () { const $marker = $( @@ -31,24 +30,25 @@ // Highlight changed row. $form.on('formUpdated.localeTranslateDirty', 'tr', function () { const $row = $(this); - const $rowToMark = $row.once('localemark'); + const rowToMark = once('localemark', $row); const marker = Drupal.theme('localeTranslateChangedMarker'); $row.addClass('changed'); // Add an asterisk only once if row changed. - if ($rowToMark.length) { - $rowToMark.find('td:first-child .js-form-item').append(marker); + if (rowToMark.length) { + $(rowToMark).find('td:first-child .js-form-item').append(marker); } }); } }, detach(context, settings, trigger) { if (trigger === 'unload') { - const $form = $('#locale-translate-edit-form').removeOnce( + const form = once.remove( 'localetranslatedirty', + '#locale-translate-edit-form', ); - if ($form.length) { - $form.off('formUpdated.localeTranslateDirty'); + if (form.length) { + $(form).off('formUpdated.localeTranslateDirty'); } } }, @@ -64,10 +64,9 @@ */ Drupal.behaviors.hideUpdateInformation = { attach(context, settings) { - const $table = $('#locale-translation-status-form').once( - 'expand-updates', - ); - if ($table.length) { + const table = once('expand-updates', '#locale-translation-status-form'); + if (table.length) { + const $table = $(table); const $tbodies = $table.find('tbody'); // Open/close the description details by toggling a tr class. diff --git a/core/modules/locale/locale.admin.js b/core/modules/locale/locale.admin.js index 7eeda410e5a..d5eb6baf99a 100644 --- a/core/modules/locale/locale.admin.js +++ b/core/modules/locale/locale.admin.js @@ -8,9 +8,10 @@ (function ($, Drupal) { Drupal.behaviors.localeTranslateDirty = { attach: function attach() { - var $form = $('#locale-translate-edit-form').once('localetranslatedirty'); + var form = once('localetranslatedirty', '#locale-translate-edit-form'); - if ($form.length) { + if (form.length) { + var $form = $(form); $form.one('formUpdated.localeTranslateDirty', 'table', function () { var $marker = $(Drupal.theme('localeTranslateChangedWarning')).hide(); $(this).addClass('changed').before($marker); @@ -18,31 +19,32 @@ }); $form.on('formUpdated.localeTranslateDirty', 'tr', function () { var $row = $(this); - var $rowToMark = $row.once('localemark'); + var rowToMark = once('localemark', $row); var marker = Drupal.theme('localeTranslateChangedMarker'); $row.addClass('changed'); - if ($rowToMark.length) { - $rowToMark.find('td:first-child .js-form-item').append(marker); + if (rowToMark.length) { + $(rowToMark).find('td:first-child .js-form-item').append(marker); } }); } }, detach: function detach(context, settings, trigger) { if (trigger === 'unload') { - var $form = $('#locale-translate-edit-form').removeOnce('localetranslatedirty'); + var form = once.remove('localetranslatedirty', '#locale-translate-edit-form'); - if ($form.length) { - $form.off('formUpdated.localeTranslateDirty'); + if (form.length) { + $(form).off('formUpdated.localeTranslateDirty'); } } } }; Drupal.behaviors.hideUpdateInformation = { attach: function attach(context, settings) { - var $table = $('#locale-translation-status-form').once('expand-updates'); + var table = once('expand-updates', '#locale-translation-status-form'); - if ($table.length) { + if (table.length) { + var $table = $(table); var $tbodies = $table.find('tbody'); $tbodies.on('click keydown', '.description', function (e) { if (e.keyCode && e.keyCode !== 13 && e.keyCode !== 32) { diff --git a/core/modules/locale/locale.bulk.es6.js b/core/modules/locale/locale.bulk.es6.js index f8f20069939..7066baee50b 100644 --- a/core/modules/locale/locale.bulk.es6.js +++ b/core/modules/locale/locale.bulk.es6.js @@ -16,8 +16,9 @@ */ Drupal.behaviors.importLanguageCodeSelector = { attach(context, settings) { - const $form = $('#locale-translate-import-form').once('autodetect-lang'); - if ($form.length) { + const form = once('autodetect-lang', '#locale-translate-import-form'); + if (form.length) { + const $form = $(form); const $langcode = $form.find('.langcode-input'); $form.find('.file-import-input').on('change', function () { // If the filename is fully the language code or the filename diff --git a/core/modules/locale/locale.bulk.js b/core/modules/locale/locale.bulk.js index 05d156e4749..4222a7891a9 100644 --- a/core/modules/locale/locale.bulk.js +++ b/core/modules/locale/locale.bulk.js @@ -8,9 +8,10 @@ (function ($, Drupal) { Drupal.behaviors.importLanguageCodeSelector = { attach: function attach(context, settings) { - var $form = $('#locale-translate-import-form').once('autodetect-lang'); + var form = once('autodetect-lang', '#locale-translate-import-form'); - if ($form.length) { + if (form.length) { + var $form = $(form); var $langcode = $form.find('.langcode-input'); $form.find('.file-import-input').on('change', function () { var matches = $(this).val().match(/([^.][.]*)([\w-]+)\.po$/); diff --git a/core/modules/locale/locale.libraries.yml b/core/modules/locale/locale.libraries.yml index 4ce0d665cf8..fb06e81ff6c 100644 --- a/core/modules/locale/locale.libraries.yml +++ b/core/modules/locale/locale.libraries.yml @@ -9,7 +9,7 @@ drupal.locale.admin: - core/jquery - core/drupal - core/drupal.form - - core/jquery.once + - core/once translations: # No sensible version can be specified, since the translations may change at diff --git a/core/modules/media_library/js/media_library.click_to_select.es6.js b/core/modules/media_library/js/media_library.click_to_select.es6.js index 0940eaa10ab..f0e0d582b7c 100644 --- a/core/modules/media_library/js/media_library.click_to_select.es6.js +++ b/core/modules/media_library/js/media_library.click_to_select.es6.js @@ -13,21 +13,29 @@ */ Drupal.behaviors.ClickToSelect = { attach(context) { - $('.js-click-to-select-trigger', context) - .once('media-library-click-to-select') - .on('click', (event) => { - // Links inside the trigger should not be click-able. - event.preventDefault(); - // Click the hidden checkbox when the trigger is clicked. - const $input = $(event.currentTarget) - .closest('.js-click-to-select') - .find('.js-click-to-select-checkbox input'); - $input.prop('checked', !$input.prop('checked')).trigger('change'); - }); + $( + once( + 'media-library-click-to-select', + '.js-click-to-select-trigger', + context, + ), + ).on('click', (event) => { + // Links inside the trigger should not be click-able. + event.preventDefault(); + // Click the hidden checkbox when the trigger is clicked. + const $input = $(event.currentTarget) + .closest('.js-click-to-select') + .find('.js-click-to-select-checkbox input'); + $input.prop('checked', !$input.prop('checked')).trigger('change'); + }); - $('.js-click-to-select-checkbox input', context) - .once('media-library-click-to-select') - // Adds checked class to the click-to-select element. + $( + once( + 'media-library-click-to-select', + '.js-click-to-select-checkbox input', + context, + ), + ) .on('change', ({ currentTarget }) => { $(currentTarget) .closest('.js-click-to-select') @@ -41,13 +49,17 @@ }); // Adds hover class to the click-to-select element. - $('.js-click-to-select-trigger, .js-click-to-select-checkbox', context) - .once('media-library-click-to-select-hover') - .on('mouseover mouseout', ({ currentTarget, type }) => { - $(currentTarget) - .closest('.js-click-to-select') - .toggleClass('is-hover', type === 'mouseover'); - }); + $( + once( + 'media-library-click-to-select-hover', + '.js-click-to-select-trigger, .js-click-to-select-checkbox', + context, + ), + ).on('mouseover mouseout', ({ currentTarget, type }) => { + $(currentTarget) + .closest('.js-click-to-select') + .toggleClass('is-hover', type === 'mouseover'); + }); }, }; })(jQuery, Drupal); diff --git a/core/modules/media_library/js/media_library.click_to_select.js b/core/modules/media_library/js/media_library.click_to_select.js index 9d0b2e82eca..4c4aeaa397e 100644 --- a/core/modules/media_library/js/media_library.click_to_select.js +++ b/core/modules/media_library/js/media_library.click_to_select.js @@ -8,12 +8,12 @@ (function ($, Drupal) { Drupal.behaviors.ClickToSelect = { attach: function attach(context) { - $('.js-click-to-select-trigger', context).once('media-library-click-to-select').on('click', function (event) { + $(once('media-library-click-to-select', '.js-click-to-select-trigger', context)).on('click', function (event) { event.preventDefault(); var $input = $(event.currentTarget).closest('.js-click-to-select').find('.js-click-to-select-checkbox input'); $input.prop('checked', !$input.prop('checked')).trigger('change'); }); - $('.js-click-to-select-checkbox input', context).once('media-library-click-to-select').on('change', function (_ref) { + $(once('media-library-click-to-select', '.js-click-to-select-checkbox input', context)).on('change', function (_ref) { var currentTarget = _ref.currentTarget; $(currentTarget).closest('.js-click-to-select').toggleClass('checked', $(currentTarget).prop('checked')); }).on('focus blur', function (_ref2) { @@ -21,7 +21,7 @@ type = _ref2.type; $(currentTarget).closest('.js-click-to-select').toggleClass('is-focus', type === 'focus'); }); - $('.js-click-to-select-trigger, .js-click-to-select-checkbox', context).once('media-library-click-to-select-hover').on('mouseover mouseout', function (_ref3) { + $(once('media-library-click-to-select-hover', '.js-click-to-select-trigger, .js-click-to-select-checkbox', context)).on('mouseover mouseout', function (_ref3) { var currentTarget = _ref3.currentTarget, type = _ref3.type; $(currentTarget).closest('.js-click-to-select').toggleClass('is-hover', type === 'mouseover'); diff --git a/core/modules/media_library/js/media_library.ui.es6.js b/core/modules/media_library/js/media_library.ui.es6.js index c2b47be9372..d6a73039836 100644 --- a/core/modules/media_library/js/media_library.ui.es6.js +++ b/core/modules/media_library/js/media_library.ui.es6.js @@ -55,9 +55,7 @@ Drupal.behaviors.MediaLibraryTabs = { attach(context) { const $menu = $('.js-media-library-menu'); - $menu - .find('a', context) - .once('media-library-menu-item') + $(once('media-library-menu-item', $menu.find('a'))) .on('keypress', (e) => { // The AJAX link has the button role, so we need to make sure the link // is also triggered when pressing the spacebar. @@ -178,67 +176,71 @@ // @todo Add media library specific classes and data attributes to the // media library display links when we can alter display links. // https://www.drupal.org/project/drupal/issues/3036694 - $('.views-display-link-widget, .views-display-link-widget_table', context) - .once('media-library-views-display-link') - .on('click', (e) => { - e.preventDefault(); - e.stopPropagation(); - - const $link = $(e.currentTarget); - - // Add a loading and display announcement for screen reader users. - let loadingAnnouncement = ''; - let displayAnnouncement = ''; - let focusSelector = ''; - if ($link.hasClass('views-display-link-widget')) { - loadingAnnouncement = Drupal.t('Loading grid view.'); - displayAnnouncement = Drupal.t('Changed to grid view.'); - focusSelector = '.views-display-link-widget'; - } else if ($link.hasClass('views-display-link-widget_table')) { - loadingAnnouncement = Drupal.t('Loading table view.'); - displayAnnouncement = Drupal.t('Changed to table view.'); - focusSelector = '.views-display-link-widget_table'; - } + $( + once( + 'media-library-views-display-link', + '.views-display-link-widget, .views-display-link-widget_table', + context, + ), + ).on('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + + const $link = $(e.currentTarget); + + // Add a loading and display announcement for screen reader users. + let loadingAnnouncement = ''; + let displayAnnouncement = ''; + let focusSelector = ''; + if ($link.hasClass('views-display-link-widget')) { + loadingAnnouncement = Drupal.t('Loading grid view.'); + displayAnnouncement = Drupal.t('Changed to grid view.'); + focusSelector = '.views-display-link-widget'; + } else if ($link.hasClass('views-display-link-widget_table')) { + loadingAnnouncement = Drupal.t('Loading table view.'); + displayAnnouncement = Drupal.t('Changed to table view.'); + focusSelector = '.views-display-link-widget_table'; + } - // Replace the library view. - const ajaxObject = Drupal.ajax({ - wrapper: 'media-library-view', - url: e.currentTarget.href, - dialogType: 'ajax', - progress: { - type: 'fullscreen', - message: loadingAnnouncement || Drupal.t('Please wait...'), - }, - }); + // Replace the library view. + const ajaxObject = Drupal.ajax({ + wrapper: 'media-library-view', + url: e.currentTarget.href, + dialogType: 'ajax', + progress: { + type: 'fullscreen', + message: loadingAnnouncement || Drupal.t('Please wait...'), + }, + }); - // Override the AJAX success callback to announce the updated content - // to screen readers. - if (displayAnnouncement || focusSelector) { - const success = ajaxObject.success; - ajaxObject.success = function (response, status) { - success.bind(this)(response, status); - // The AJAX link replaces the whole view, including the clicked - // link. Move the focus back to the clicked link when the view is - // replaced. - if (focusSelector) { - $(focusSelector).focus(); - } - // Announce the new view is loaded to screen readers. - if (displayAnnouncement) { - Drupal.announce(displayAnnouncement); - } - }; - } + // Override the AJAX success callback to announce the updated content + // to screen readers. + if (displayAnnouncement || focusSelector) { + const success = ajaxObject.success; + ajaxObject.success = function (response, status) { + success.bind(this)(response, status); + // The AJAX link replaces the whole view, including the clicked + // link. Move the focus back to the clicked link when the view is + // replaced. + if (focusSelector) { + $(focusSelector).focus(); + } + // Announce the new view is loaded to screen readers. + if (displayAnnouncement) { + Drupal.announce(displayAnnouncement); + } + }; + } - ajaxObject.execute(); + ajaxObject.execute(); - // Announce the new view is being loaded to screen readers. - // @todo Replace custom announcement when - // https://www.drupal.org/project/drupal/issues/2973140 is in. - if (loadingAnnouncement) { - Drupal.announce(loadingAnnouncement); - } - }); + // Announce the new view is being loaded to screen readers. + // @todo Replace custom announcement when + // https://www.drupal.org/project/drupal/issues/2973140 is in. + if (loadingAnnouncement) { + Drupal.announce(loadingAnnouncement); + } + }); }, }; @@ -325,7 +327,7 @@ // Update the selection array and the hidden form field when a media item // is selected. - $mediaItems.once('media-item-change').on('change', (e) => { + $(once('media-item-change', $mediaItems)).on('change', (e) => { const id = e.currentTarget.value; // Update the selection. @@ -355,22 +357,24 @@ }); // The hidden selection form field changes when the selection is updated. - $('#media-library-modal-selection', $form) - .once('media-library-selection-change') - .on('change', (e) => { - updateSelectionCount(settings.media_library.selection_remaining); - - // Prevent users from selecting more items than allowed. - if ( - currentSelection.length === - settings.media_library.selection_remaining - ) { - disableItems($mediaItems.not(':checked')); - enableItems($mediaItems.filter(':checked')); - } else { - enableItems($mediaItems); - } - }); + $( + once( + 'media-library-selection-change', + $form.find('#media-library-modal-selection'), + ), + ).on('change', (e) => { + updateSelectionCount(settings.media_library.selection_remaining); + + // Prevent users from selecting more items than allowed. + if ( + currentSelection.length === settings.media_library.selection_remaining + ) { + disableItems($mediaItems.not(':checked')); + enableItems($mediaItems.filter(':checked')); + } else { + enableItems($mediaItems); + } + }); // Apply the current selection to the media library view. Changing the // checkbox values triggers the change event for the media items. The @@ -384,20 +388,21 @@ // Add the selection count to the button pane when a media library dialog // is created. - $(window) - .once('media-library-selection-info') - .on('dialog:aftercreate', () => { - // Since the dialog HTML is not part of the context, we can't use - // context here. - const $buttonPane = $( - '.media-library-widget-modal .ui-dialog-buttonpane', - ); - if (!$buttonPane.length) { - return; - } - $buttonPane.append(Drupal.theme('mediaLibrarySelectionCount')); - updateSelectionCount(settings.media_library.selection_remaining); - }); + if (!once('media-library-selection-info', 'html').length) { + return; + } + $(window).on('dialog:aftercreate', () => { + // Since the dialog HTML is not part of the context, we can't use + // context here. + const $buttonPane = $( + '.media-library-widget-modal .ui-dialog-buttonpane', + ); + if (!$buttonPane.length) { + return; + } + $buttonPane.append(Drupal.theme('mediaLibrarySelectionCount')); + updateSelectionCount(settings.media_library.selection_remaining); + }); }, }; @@ -411,11 +416,12 @@ */ Drupal.behaviors.MediaLibraryModalClearSelection = { attach() { - $(window) - .once('media-library-clear-selection') - .on('dialog:afterclose', () => { - Drupal.MediaLibrary.currentSelection = []; - }); + if (!once('media-library-clear-selection', 'html').length) { + return; + } + $(window).on('dialog:afterclose', () => { + Drupal.MediaLibrary.currentSelection = []; + }); }, }; diff --git a/core/modules/media_library/js/media_library.ui.js b/core/modules/media_library/js/media_library.ui.js index b24ee5db9e2..32050310012 100644 --- a/core/modules/media_library/js/media_library.ui.js +++ b/core/modules/media_library/js/media_library.ui.js @@ -20,7 +20,7 @@ Drupal.behaviors.MediaLibraryTabs = { attach: function attach(context) { var $menu = $('.js-media-library-menu'); - $menu.find('a', context).once('media-library-menu-item').on('keypress', function (e) { + $(once('media-library-menu-item', $menu.find('a'))).on('keypress', function (e) { if (e.which === 32) { e.preventDefault(); e.stopPropagation(); @@ -85,7 +85,7 @@ attach: function attach(context) { var $view = $(context).hasClass('.js-media-library-view') ? $(context) : $('.js-media-library-view', context); $view.closest('.views-element-container').attr('id', 'media-library-view'); - $('.views-display-link-widget, .views-display-link-widget_table', context).once('media-library-views-display-link').on('click', function (e) { + $(once('media-library-views-display-link', '.views-display-link-widget, .views-display-link-widget_table', context)).on('click', function (e) { e.preventDefault(); e.stopPropagation(); var $link = $(e.currentTarget); @@ -163,7 +163,7 @@ $('.js-media-library-selected-count').html(selectItemsText); } - $mediaItems.once('media-item-change').on('change', function (e) { + $(once('media-item-change', $mediaItems)).on('change', function (e) { var id = e.currentTarget.value; var position = currentSelection.indexOf(id); @@ -178,7 +178,7 @@ $form.find('#media-library-modal-selection').val(currentSelection.join()).trigger('change'); $('.js-media-library-add-form-current-selection').val(currentSelection.join()); }); - $('#media-library-modal-selection', $form).once('media-library-selection-change').on('change', function (e) { + $(once('media-library-selection-change', $form.find('#media-library-modal-selection'))).on('change', function (e) { updateSelectionCount(settings.media_library.selection_remaining); if (currentSelection.length === settings.media_library.selection_remaining) { @@ -191,7 +191,12 @@ currentSelection.forEach(function (value) { $form.find("input[type=\"checkbox\"][value=\"".concat(value, "\"]")).prop('checked', true).trigger('change'); }); - $(window).once('media-library-selection-info').on('dialog:aftercreate', function () { + + if (!once('media-library-selection-info', 'html').length) { + return; + } + + $(window).on('dialog:aftercreate', function () { var $buttonPane = $('.media-library-widget-modal .ui-dialog-buttonpane'); if (!$buttonPane.length) { @@ -205,7 +210,11 @@ }; Drupal.behaviors.MediaLibraryModalClearSelection = { attach: function attach() { - $(window).once('media-library-clear-selection').on('dialog:afterclose', function () { + if (!once('media-library-clear-selection', 'html').length) { + return; + } + + $(window).on('dialog:afterclose', function () { Drupal.MediaLibrary.currentSelection = []; }); } diff --git a/core/modules/media_library/js/media_library.view.es6.js b/core/modules/media_library/js/media_library.view.es6.js index ab5b81cf94e..327cf63069b 100644 --- a/core/modules/media_library/js/media_library.view.es6.js +++ b/core/modules/media_library/js/media_library.view.es6.js @@ -13,9 +13,12 @@ Drupal.behaviors.MediaLibrarySelectAll = { attach(context) { const $view = $( - '.js-media-library-view[data-view-display-id="page"]', - context, - ).once('media-library-select-all'); + once( + 'media-library-select-all', + '.js-media-library-view[data-view-display-id="page"]', + context, + ), + ); if ($view.length && $view.find('.js-media-library-item').length) { const $checkbox = $(Drupal.theme('checkbox')).on( 'click', diff --git a/core/modules/media_library/js/media_library.view.js b/core/modules/media_library/js/media_library.view.js index af7dbd68183..8c4ecf2fdb7 100644 --- a/core/modules/media_library/js/media_library.view.js +++ b/core/modules/media_library/js/media_library.view.js @@ -8,7 +8,7 @@ (function ($, Drupal) { Drupal.behaviors.MediaLibrarySelectAll = { attach: function attach(context) { - var $view = $('.js-media-library-view[data-view-display-id="page"]', context).once('media-library-select-all'); + var $view = $(once('media-library-select-all', '.js-media-library-view[data-view-display-id="page"]', context)); if ($view.length && $view.find('.js-media-library-item').length) { var $checkbox = $(Drupal.theme('checkbox')).on('click', function (_ref) { diff --git a/core/modules/media_library/js/media_library.widget.es6.js b/core/modules/media_library/js/media_library.widget.es6.js index b42ef705240..88ad11fbc71 100644 --- a/core/modules/media_library/js/media_library.widget.es6.js +++ b/core/modules/media_library/js/media_library.widget.es6.js @@ -44,8 +44,13 @@ show: Drupal.t('Show media item weights'), hide: Drupal.t('Hide media item weights'), }; - $('.js-media-library-widget-toggle-weight', context) - .once('media-library-toggle') + $( + once( + 'media-library-toggle', + '.js-media-library-widget-toggle-weight', + context, + ), + ) .on('click', (e) => { e.preventDefault(); $(e.currentTarget) @@ -61,8 +66,7 @@ .toggle(); }) .text(strings.show); - $('.js-media-library-item-weight', context) - .once('media-library-toggle') + $(once('media-library-toggle', '.js-media-library-item-weight', context)) .parent() .hide(); }, @@ -83,18 +87,20 @@ // more items, the button needs to be disabled. Since we can't shift the // focus to disabled elements, the focus is set back to the open button // via JavaScript by adding the 'data-disabled-focus' attribute. - $('.js-media-library-open-button[data-disabled-focus="true"]', context) - .once('media-library-disable') - .each(function () { - $(this).focus(); + once( + 'media-library-disable', + '.js-media-library-open-button[data-disabled-focus="true"]', + context, + ).forEach((button) => { + $(button).focus(); - // There is a small delay between the focus set by the browser and the - // focus of screen readers. We need to give screen readers time to - // shift the focus as well before the button is disabled. - setTimeout(() => { - $(this).attr('disabled', 'disabled'); - }, 50); - }); + // There is a small delay between the focus set by the browser and the + // focus of screen readers. We need to give screen readers time to shift + // the focus as well before the button is disabled. + setTimeout(() => { + $(button).attr('disabled', 'disabled'); + }, 50); + }); }, }; })(jQuery, Drupal, Sortable); diff --git a/core/modules/media_library/js/media_library.widget.js b/core/modules/media_library/js/media_library.widget.js index 0fe2475ebe9..d2e74bab303 100644 --- a/core/modules/media_library/js/media_library.widget.js +++ b/core/modules/media_library/js/media_library.widget.js @@ -28,21 +28,19 @@ show: Drupal.t('Show media item weights'), hide: Drupal.t('Hide media item weights') }; - $('.js-media-library-widget-toggle-weight', context).once('media-library-toggle').on('click', function (e) { + $(once('media-library-toggle', '.js-media-library-widget-toggle-weight', context)).on('click', function (e) { e.preventDefault(); $(e.currentTarget).toggleClass('active').text($(e.currentTarget).hasClass('active') ? strings.hide : strings.show).closest('.js-media-library-widget').find('.js-media-library-item-weight').parent().toggle(); }).text(strings.show); - $('.js-media-library-item-weight', context).once('media-library-toggle').parent().hide(); + $(once('media-library-toggle', '.js-media-library-item-weight', context)).parent().hide(); } }; Drupal.behaviors.MediaLibraryWidgetDisableButton = { attach: function attach(context) { - $('.js-media-library-open-button[data-disabled-focus="true"]', context).once('media-library-disable').each(function () { - var _this = this; - - $(this).focus(); + once('media-library-disable', '.js-media-library-open-button[data-disabled-focus="true"]', context).forEach(function (button) { + $(button).focus(); setTimeout(function () { - $(_this).attr('disabled', 'disabled'); + $(button).attr('disabled', 'disabled'); }, 50); }); } diff --git a/core/modules/media_library/media_library.libraries.yml b/core/modules/media_library/media_library.libraries.yml index 9a3d256ee79..4d1134a0304 100644 --- a/core/modules/media_library/media_library.libraries.yml +++ b/core/modules/media_library/media_library.libraries.yml @@ -4,7 +4,7 @@ click_to_select: js/media_library.click_to_select.js: {} dependencies: - core/drupal - - core/jquery.once + - core/once view: version: VERSION @@ -21,7 +21,7 @@ widget: js/media_library.widget.js: {} dependencies: - core/drupal.dialog.ajax - - core/jquery.once + - core/once - core/sortable - core/drupal.nodelist.foreach @@ -32,6 +32,7 @@ ui: dependencies: - core/drupal.ajax - core/drupal.announce - - core/jquery.once + - core/once + - core/jquery - media_library/view - core/tabbable diff --git a/core/modules/menu_ui/menu_ui.admin.es6.js b/core/modules/menu_ui/menu_ui.admin.es6.js index 517a823adb2..d2e4dd46bd3 100644 --- a/core/modules/menu_ui/menu_ui.admin.es6.js +++ b/core/modules/menu_ui/menu_ui.admin.es6.js @@ -10,8 +10,9 @@ */ Drupal.behaviors.menuUiChangeParentItems = { attach(context, settings) { - const $menu = $('#edit-menu').once('menu-parent'); - if ($menu.length) { + const menu = once('menu-parent', '#edit-menu'); + if (menu.length) { + const $menu = $(menu); // Update the list of available parent menu items to match the initial // available menus. Drupal.menuUiUpdateParentList(); diff --git a/core/modules/menu_ui/menu_ui.admin.js b/core/modules/menu_ui/menu_ui.admin.js index 63ce3384d9d..26d9716bca6 100644 --- a/core/modules/menu_ui/menu_ui.admin.js +++ b/core/modules/menu_ui/menu_ui.admin.js @@ -8,9 +8,10 @@ (function ($, Drupal) { Drupal.behaviors.menuUiChangeParentItems = { attach: function attach(context, settings) { - var $menu = $('#edit-menu').once('menu-parent'); + var menu = once('menu-parent', '#edit-menu'); - if ($menu.length) { + if (menu.length) { + var $menu = $(menu); Drupal.menuUiUpdateParentList(); $menu.on('change', 'input', Drupal.menuUiUpdateParentList); } diff --git a/core/modules/node/node.libraries.yml b/core/modules/node/node.libraries.yml index a420112ced1..9af36335b41 100644 --- a/core/modules/node/node.libraries.yml +++ b/core/modules/node/node.libraries.yml @@ -18,7 +18,7 @@ drupal.node.preview: node.preview.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal - core/drupal.dialog - core/drupal.form diff --git a/core/modules/node/node.preview.es6.js b/core/modules/node/node.preview.es6.js index edb702bc604..071d190fd8f 100644 --- a/core/modules/node/node.preview.es6.js +++ b/core/modules/node/node.preview.es6.js @@ -54,9 +54,11 @@ } } - const $preview = $(context).once('node-preview'); - if ($(context).find('.node-preview-container').length) { - $preview.on( + if (!context.querySelector('.node-preview-container')) { + return; + } + if (once('node-preview', 'html').length) { + $(document).on( 'click.preview', 'a:not([href^="#"], .node-preview-container a)', clickPreviewModal, @@ -65,9 +67,11 @@ }, detach(context, settings, trigger) { if (trigger === 'unload') { - const $preview = $(context).find('.content').removeOnce('node-preview'); - if ($preview.length) { - $preview.off('click.preview'); + if ( + context.querySelector('.node-preview-container') && + once.remove('node-preview', 'html').length + ) { + $(document).off('click.preview'); } } }, @@ -83,11 +87,13 @@ */ Drupal.behaviors.nodePreviewSwitchViewMode = { attach(context) { - const $autosubmit = $(context) - .find('[data-drupal-autosubmit]') - .once('autosubmit'); - if ($autosubmit.length) { - $autosubmit.on('formUpdated.preview', function () { + const autosubmit = once( + 'autosubmit', + '[data-drupal-autosubmit]', + context, + ); + if (autosubmit.length) { + $(autosubmit).on('formUpdated.preview', function () { $(this.form).trigger('submit'); }); } diff --git a/core/modules/node/node.preview.js b/core/modules/node/node.preview.js index 0f8508362d3..669dada2ec2 100644 --- a/core/modules/node/node.preview.js +++ b/core/modules/node/node.preview.js @@ -29,28 +29,28 @@ } } - var $preview = $(context).once('node-preview'); + if (!context.querySelector('.node-preview-container')) { + return; + } - if ($(context).find('.node-preview-container').length) { - $preview.on('click.preview', 'a:not([href^="#"], .node-preview-container a)', clickPreviewModal); + if (once('node-preview', 'html').length) { + $(document).on('click.preview', 'a:not([href^="#"], .node-preview-container a)', clickPreviewModal); } }, detach: function detach(context, settings, trigger) { if (trigger === 'unload') { - var $preview = $(context).find('.content').removeOnce('node-preview'); - - if ($preview.length) { - $preview.off('click.preview'); + if (context.querySelector('.node-preview-container') && once.remove('node-preview', 'html').length) { + $(document).off('click.preview'); } } } }; Drupal.behaviors.nodePreviewSwitchViewMode = { attach: function attach(context) { - var $autosubmit = $(context).find('[data-drupal-autosubmit]').once('autosubmit'); + var autosubmit = once('autosubmit', '[data-drupal-autosubmit]', context); - if ($autosubmit.length) { - $autosubmit.on('formUpdated.preview', function () { + if (autosubmit.length) { + $(autosubmit).on('formUpdated.preview', function () { $(this.form).trigger('submit'); }); } diff --git a/core/modules/quickedit/js/quickedit.es6.js b/core/modules/quickedit/js/quickedit.es6.js index 1a4f65f2a9b..fe0dc6a8b66 100644 --- a/core/modules/quickedit/js/quickedit.es6.js +++ b/core/modules/quickedit/js/quickedit.es6.js @@ -64,7 +64,7 @@ /** * Initialize the Quick Edit app. * - * @param {HTMLElement} bodyElement + * @param {Element} bodyElement * This document's body element. */ function initQuickEdit(bodyElement) { @@ -515,33 +515,26 @@ Drupal.behaviors.quickedit = { attach(context) { // Initialize the Quick Edit app once per page load. - $('body').once('quickedit-init').each(initQuickEdit); + once('quickedit-init', 'body').forEach(initQuickEdit); // Find all in-place editable fields, if any. - const $fields = $(context) - .find('[data-quickedit-field-id]') - .once('quickedit'); - if ($fields.length === 0) { + const fields = once('quickedit', '[data-quickedit-field-id]', context); + if (fields.length === 0) { return; } // Process each entity element: identical entities that appear multiple // times will get a numeric identifier, starting at 0. - $(context) - .find('[data-quickedit-entity-id]') - .once('quickedit') - .each((index, entityElement) => { - processEntity(entityElement); - }); + once('quickedit', '[data-quickedit-entity-id]', context).forEach( + processEntity, + ); // Process each field element: queue to be used or to fetch metadata. // When a field is being rerendered after editing, it will be processed // immediately. New fields will be unable to be processed immediately, // but will instead be queued to have their metadata fetched, which occurs // below in fetchMissingMetaData(). - $fields.each((index, fieldElement) => { - processField(fieldElement); - }); + fields.forEach(processField); // Entities and fields on the page have been detected, try to set up the // contextual links for those entities that already have the necessary @@ -737,7 +730,7 @@ // If the contextual link is cached on the client side, an entity instance // will not yet have been assigned. So assign one. if (!data.$region.is('[data-quickedit-entity-instance-id]')) { - data.$region.once('quickedit'); + once('quickedit', data.$region); processEntity(data.$region.get(0)); } const contextualLink = { diff --git a/core/modules/quickedit/js/quickedit.js b/core/modules/quickedit/js/quickedit.js index 8461e0f2ee9..d2d487de21f 100644 --- a/core/modules/quickedit/js/quickedit.js +++ b/core/modules/quickedit/js/quickedit.js @@ -283,19 +283,15 @@ Drupal.behaviors.quickedit = { attach: function attach(context) { - $('body').once('quickedit-init').each(initQuickEdit); - var $fields = $(context).find('[data-quickedit-field-id]').once('quickedit'); + once('quickedit-init', 'body').forEach(initQuickEdit); + var fields = once('quickedit', '[data-quickedit-field-id]', context); - if ($fields.length === 0) { + if (fields.length === 0) { return; } - $(context).find('[data-quickedit-entity-id]').once('quickedit').each(function (index, entityElement) { - processEntity(entityElement); - }); - $fields.each(function (index, fieldElement) { - processField(fieldElement); - }); + once('quickedit', '[data-quickedit-entity-id]', context).forEach(processEntity); + fields.forEach(processField); contextualLinksQueue = _.filter(contextualLinksQueue, function (contextualLink) { return !initializeEntityContextualLink(contextualLink); }); @@ -367,7 +363,7 @@ $(document).on('drupalContextualLinkAdded', function (event, data) { if (data.$region.is('[data-quickedit-entity-id]')) { if (!data.$region.is('[data-quickedit-entity-instance-id]')) { - data.$region.once('quickedit'); + once('quickedit', data.$region); processEntity(data.$region.get(0)); } diff --git a/core/modules/quickedit/quickedit.libraries.yml b/core/modules/quickedit/quickedit.libraries.yml index 8111f00ecb7..1169abbd300 100644 --- a/core/modules/quickedit/quickedit.libraries.yml +++ b/core/modules/quickedit/quickedit.libraries.yml @@ -28,7 +28,7 @@ quickedit: css/quickedit.icons.theme.css: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/underscore - core/backbone - core/jquery.form diff --git a/core/modules/settings_tray/js/settings_tray.es6.js b/core/modules/settings_tray/js/settings_tray.es6.js index 1838789c6dc..448c0934db7 100644 --- a/core/modules/settings_tray/js/settings_tray.es6.js +++ b/core/modules/settings_tray/js/settings_tray.es6.js @@ -81,8 +81,8 @@ $editButton.text(Drupal.t('Editing')); closeToolbarTrays(); - $editables = $('[data-drupal-settingstray="editable"]').once( - 'settingstray', + $editables = $( + once('settingstray', '[data-drupal-settingstray="editable"]'), ); if ($editables.length) { // Use event capture to prevent clicks on links. @@ -132,8 +132,8 @@ } // Disable edit mode. else { - $editables = $('[data-drupal-settingstray="editable"]').removeOnce( - 'settingstray', + $editables = $( + once.remove('settingstray', '[data-drupal-settingstray="editable"]'), ); if ($editables.length) { document @@ -221,16 +221,13 @@ prepareAjaxLinks(); // When the first contextual link is added to the page set Edit Mode. - $('body') - .once('settings_tray.edit_mode_init') - .each(() => { - const editMode = - localStorage.getItem('Drupal.contextualToolbar.isViewing') === - 'false'; - if (editMode) { - setEditModeState(true); - } - }); + once('settings_tray.edit_mode_init', 'body').forEach(() => { + const editMode = + localStorage.getItem('Drupal.contextualToolbar.isViewing') === 'false'; + if (editMode) { + setEditModeState(true); + } + }); /** * Bind a listener to all 'Quick edit' links for blocks. Click "Edit" @@ -267,9 +264,10 @@ */ Drupal.behaviors.toggleEditMode = { attach() { - $(toggleEditSelector) - .once('settingstray') - .on('click.settingstray', toggleEditMode); + $(once('settingstray', toggleEditSelector)).on( + 'click.settingstray', + toggleEditMode, + ); }, }; diff --git a/core/modules/settings_tray/js/settings_tray.js b/core/modules/settings_tray/js/settings_tray.js index 688e280cc93..d2a1b60ec61 100644 --- a/core/modules/settings_tray/js/settings_tray.js +++ b/core/modules/settings_tray/js/settings_tray.js @@ -48,7 +48,7 @@ if (editMode) { $editButton.text(Drupal.t('Editing')); closeToolbarTrays(); - $editables = $('[data-drupal-settingstray="editable"]').once('settingstray'); + $editables = $(once('settingstray', '[data-drupal-settingstray="editable"]')); if ($editables.length) { document.querySelector('[data-off-canvas-main-canvas]').addEventListener('click', preventClick, true); @@ -73,7 +73,7 @@ }); } } else { - $editables = $('[data-drupal-settingstray="editable"]').removeOnce('settingstray'); + $editables = $(once.remove('settingstray', '[data-drupal-settingstray="editable"]')); if ($editables.length) { document.querySelector('[data-off-canvas-main-canvas]').removeEventListener('click', preventClick, true); @@ -115,7 +115,7 @@ $(document).on('drupalContextualLinkAdded', function (event, data) { prepareAjaxLinks(); - $('body').once('settings_tray.edit_mode_init').each(function () { + once('settings_tray.edit_mode_init', 'body').forEach(function () { var editMode = localStorage.getItem('Drupal.contextualToolbar.isViewing') === 'false'; if (editMode) { @@ -138,7 +138,7 @@ }); Drupal.behaviors.toggleEditMode = { attach: function attach() { - $(toggleEditSelector).once('settingstray').on('click.settingstray', toggleEditMode); + $(once('settingstray', toggleEditSelector)).on('click.settingstray', toggleEditMode); } }; $(window).on({ diff --git a/core/modules/settings_tray/settings_tray.libraries.yml b/core/modules/settings_tray/settings_tray.libraries.yml index de5c82c78d5..de1494c7f69 100644 --- a/core/modules/settings_tray/settings_tray.libraries.yml +++ b/core/modules/settings_tray/settings_tray.libraries.yml @@ -15,5 +15,5 @@ drupal.settings_tray: dependencies: - core/jquery - core/drupal - - core/jquery.once + - core/once - core/drupal.ajax diff --git a/core/modules/system/js/system.date.es6.js b/core/modules/system/js/system.date.es6.js index 610ac05938d..8617d4ae1d1 100644 --- a/core/modules/system/js/system.date.es6.js +++ b/core/modules/system/js/system.date.es6.js @@ -16,20 +16,25 @@ */ Drupal.behaviors.dateFormat = { attach(context) { - const $context = $(context); - const $source = $context - .find('[data-drupal-date-formatter="source"]') - .once('dateFormat'); - const $target = $context - .find('[data-drupal-date-formatter="preview"]') - .once('dateFormat'); - const $preview = $target.find('em'); + const source = once( + 'dateFormat', + '[data-drupal-date-formatter="source"]', + context, + ); + const target = once( + 'dateFormat', + '[data-drupal-date-formatter="preview"]', + context, + ); // All elements have to exist. - if (!$source.length || !$target.length) { + if (!source.length || !target.length) { return; } + const $target = $(target); + const $preview = $target.find('em'); + /** * Event handler that replaces date characters with value. * @@ -49,7 +54,7 @@ /** * On given event triggers the date character replacement. */ - $source + $(source) .on( 'keyup.dateFormat change.dateFormat input.dateFormat', dateFormatHandler, diff --git a/core/modules/system/js/system.date.js b/core/modules/system/js/system.date.js index 8de2e65a5e8..7c083f0bc5c 100644 --- a/core/modules/system/js/system.date.js +++ b/core/modules/system/js/system.date.js @@ -9,15 +9,16 @@ var dateFormats = drupalSettings.dateFormats; Drupal.behaviors.dateFormat = { attach: function attach(context) { - var $context = $(context); - var $source = $context.find('[data-drupal-date-formatter="source"]').once('dateFormat'); - var $target = $context.find('[data-drupal-date-formatter="preview"]').once('dateFormat'); - var $preview = $target.find('em'); + var source = once('dateFormat', '[data-drupal-date-formatter="source"]', context); + var target = once('dateFormat', '[data-drupal-date-formatter="preview"]', context); - if (!$source.length || !$target.length) { + if (!source.length || !target.length) { return; } + var $target = $(target); + var $preview = $target.find('em'); + function dateFormatHandler(e) { var baseValue = $(e.target).val() || ''; var dateString = baseValue.replace(/\\?(.?)/gi, function (key, value) { @@ -27,7 +28,7 @@ $target.toggleClass('js-hide', !dateString.length); } - $source.on('keyup.dateFormat change.dateFormat input.dateFormat', dateFormatHandler).trigger('keyup'); + $(source).on('keyup.dateFormat change.dateFormat input.dateFormat', dateFormatHandler).trigger('keyup'); } }; })(jQuery, Drupal, drupalSettings);
\ No newline at end of file diff --git a/core/modules/system/js/system.es6.js b/core/modules/system/js/system.es6.js index e6e1e7ab03f..7717d290b56 100644 --- a/core/modules/system/js/system.es6.js +++ b/core/modules/system/js/system.es6.js @@ -31,21 +31,21 @@ // Listen to value:copy events on all dependent fields. // We have to use body and not document because of the way jQuery events // bubble up the DOM tree. - $('body') - .once('copy-field-values') - .on('value:copy', this.valueTargetCopyHandler); + $(once('copy-field-values', 'body')).on( + 'value:copy', + this.valueTargetCopyHandler, + ); // Listen on all source elements. - $(`#${ids.join(', #')}`) - .once('copy-field-values') - .on('blur', this.valueSourceBlurHandler); + $(once('copy-field-values', `#${ids.join(', #')}`)).on( + 'blur', + this.valueSourceBlurHandler, + ); } }, detach(context, settings, trigger) { if (trigger === 'unload' && ids.length) { - $('body').removeOnce('copy-field-values').off('value:copy'); - $(`#${ids.join(', #')}`) - .removeOnce('copy-field-values') - .off('blur'); + $(once.remove('copy-field-values', 'body')).off('value:copy'); + $(once.remove('copy-field-values', `#${ids.join(', #')}`)).off('blur'); } }, diff --git a/core/modules/system/js/system.js b/core/modules/system/js/system.js index f8cbd41f618..a69e362f7c9 100644 --- a/core/modules/system/js/system.js +++ b/core/modules/system/js/system.js @@ -14,14 +14,14 @@ }); if (ids.length) { - $('body').once('copy-field-values').on('value:copy', this.valueTargetCopyHandler); - $("#".concat(ids.join(', #'))).once('copy-field-values').on('blur', this.valueSourceBlurHandler); + $(once('copy-field-values', 'body')).on('value:copy', this.valueTargetCopyHandler); + $(once('copy-field-values', "#".concat(ids.join(', #')))).on('blur', this.valueSourceBlurHandler); } }, detach: function detach(context, settings, trigger) { if (trigger === 'unload' && ids.length) { - $('body').removeOnce('copy-field-values').off('value:copy'); - $("#".concat(ids.join(', #'))).removeOnce('copy-field-values').off('blur'); + $(once.remove('copy-field-values', 'body')).off('value:copy'); + $(once.remove('copy-field-values', "#".concat(ids.join(', #')))).off('blur'); } }, valueTargetCopyHandler: function valueTargetCopyHandler(e, value) { diff --git a/core/modules/system/js/system.modules.es6.js b/core/modules/system/js/system.modules.es6.js index bc67ef6a48b..98be18f9890 100644 --- a/core/modules/system/js/system.modules.es6.js +++ b/core/modules/system/js/system.modules.es6.js @@ -18,8 +18,11 @@ */ Drupal.behaviors.tableFilterByText = { attach(context, settings) { - const $input = $('input.table-filter-text').once('table-filter-text'); - const $table = $($input.attr('data-table')); + const [input] = once('table-filter-text', 'input.table-filter-text'); + if (!input) { + return; + } + const $table = $(input.getAttribute('data-table')); let $rowsAndDetails; let $rows; let $details; @@ -92,7 +95,7 @@ $rows = $table.find('tbody tr'); $details = $rowsAndDetails.filter('.package-listing'); - $input.on({ + $(input).on({ keyup: debounce(filterModuleList, 200), keydown: preventEnterKey, }); diff --git a/core/modules/system/js/system.modules.js b/core/modules/system/js/system.modules.js index cdfff64e0ad..9e2f7d403d1 100644 --- a/core/modules/system/js/system.modules.js +++ b/core/modules/system/js/system.modules.js @@ -5,11 +5,30 @@ * @preserve **/ +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } + +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } + +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } + +function _iterableToArrayLimit(arr, i) { var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]); if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + (function ($, Drupal, debounce) { Drupal.behaviors.tableFilterByText = { attach: function attach(context, settings) { - var $input = $('input.table-filter-text').once('table-filter-text'); - var $table = $($input.attr('data-table')); + var _once = once('table-filter-text', 'input.table-filter-text'), + _once2 = _slicedToArray(_once, 1), + input = _once2[0]; + + if (!input) { + return; + } + + var $table = $(input.getAttribute('data-table')); var $rowsAndDetails; var $rows; var $details; @@ -60,7 +79,7 @@ $rowsAndDetails = $table.find('tr, details'); $rows = $table.find('tbody tr'); $details = $rowsAndDetails.filter('.package-listing'); - $input.on({ + $(input).on({ keyup: debounce(filterModuleList, 200), keydown: preventEnterKey }); diff --git a/core/modules/system/system.libraries.yml b/core/modules/system/system.libraries.yml index 98eb2839191..2f510872d51 100644 --- a/core/modules/system/system.libraries.yml +++ b/core/modules/system/system.libraries.yml @@ -51,7 +51,7 @@ drupal.system: - core/jquery - core/drupal - core/drupalSettings - - core/jquery.once + - core/once drupal.system.modules: version: VERSION @@ -61,7 +61,7 @@ drupal.system.modules: - core/jquery - core/drupal - core/drupal.debounce - - core/jquery.once + - core/once - core/drupal.announce diff: @@ -78,5 +78,5 @@ drupal.system.date: - core/jquery - core/drupal - core/drupalSettings - - core/jquery.once + - core/once - core/drupal.form diff --git a/core/modules/system/tests/modules/ajax_test/js/insert-ajax.es6.js b/core/modules/system/tests/modules/ajax_test/js/insert-ajax.es6.js index 8c9efbabb68..175e0596128 100644 --- a/core/modules/system/tests/modules/ajax_test/js/insert-ajax.es6.js +++ b/core/modules/system/tests/modules/ajax_test/js/insert-ajax.es6.js @@ -7,37 +7,33 @@ (function ($, window, Drupal) { Drupal.behaviors.insertTest = { attach(context) { - $('.ajax-insert') - .once('ajax-insert') - .on('click', (event) => { - event.preventDefault(); - const ajaxSettings = { - url: event.currentTarget.getAttribute('href'), - wrapper: 'ajax-target', - base: false, - element: false, - method: event.currentTarget.getAttribute('data-method'), - effect: event.currentTarget.getAttribute('data-effect'), - }; - const myAjaxObject = Drupal.ajax(ajaxSettings); - myAjaxObject.execute(); - }); + $(once('ajax-insert', '.ajax-insert')).on('click', (event) => { + event.preventDefault(); + const ajaxSettings = { + url: event.currentTarget.getAttribute('href'), + wrapper: 'ajax-target', + base: false, + element: false, + method: event.currentTarget.getAttribute('data-method'), + effect: event.currentTarget.getAttribute('data-effect'), + }; + const myAjaxObject = Drupal.ajax(ajaxSettings); + myAjaxObject.execute(); + }); - $('.ajax-insert-inline') - .once('ajax-insert') - .on('click', (event) => { - event.preventDefault(); - const ajaxSettings = { - url: event.currentTarget.getAttribute('href'), - wrapper: 'ajax-target-inline', - base: false, - element: false, - method: event.currentTarget.getAttribute('data-method'), - effect: event.currentTarget.getAttribute('data-effect'), - }; - const myAjaxObject = Drupal.ajax(ajaxSettings); - myAjaxObject.execute(); - }); + $(once('ajax-insert', '.ajax-insert-inline')).on('click', (event) => { + event.preventDefault(); + const ajaxSettings = { + url: event.currentTarget.getAttribute('href'), + wrapper: 'ajax-target-inline', + base: false, + element: false, + method: event.currentTarget.getAttribute('data-method'), + effect: event.currentTarget.getAttribute('data-effect'), + }; + const myAjaxObject = Drupal.ajax(ajaxSettings); + myAjaxObject.execute(); + }); $(context).addClass('processed'); }, diff --git a/core/modules/system/tests/modules/ajax_test/js/insert-ajax.js b/core/modules/system/tests/modules/ajax_test/js/insert-ajax.js index 2a7f763accb..2c3db6a61dc 100644 --- a/core/modules/system/tests/modules/ajax_test/js/insert-ajax.js +++ b/core/modules/system/tests/modules/ajax_test/js/insert-ajax.js @@ -8,7 +8,7 @@ (function ($, window, Drupal) { Drupal.behaviors.insertTest = { attach: function attach(context) { - $('.ajax-insert').once('ajax-insert').on('click', function (event) { + $(once('ajax-insert', '.ajax-insert')).on('click', function (event) { event.preventDefault(); var ajaxSettings = { url: event.currentTarget.getAttribute('href'), @@ -21,7 +21,7 @@ var myAjaxObject = Drupal.ajax(ajaxSettings); myAjaxObject.execute(); }); - $('.ajax-insert-inline').once('ajax-insert').on('click', function (event) { + $(once('ajax-insert', '.ajax-insert-inline')).on('click', function (event) { event.preventDefault(); var ajaxSettings = { url: event.currentTarget.getAttribute('href'), diff --git a/core/modules/system/tests/modules/js_cookie_test/js/js_cookie_shim_test.es6.js b/core/modules/system/tests/modules/js_cookie_test/js/js_cookie_shim_test.es6.js index b8f5f373e51..4335a6ab5db 100644 --- a/core/modules/system/tests/modules/js_cookie_test/js/js_cookie_shim_test.es6.js +++ b/core/modules/system/tests/modules/js_cookie_test/js/js_cookie_shim_test.es6.js @@ -5,7 +5,7 @@ (({ behaviors }, $) => { behaviors.jqueryCookie = { attach: () => { - if ($('body').once('js_cookie_test-init').length) { + if (once('js_cookie_test-init', 'body').length) { $('.js_cookie_test_add_button').on('click', () => { $.cookie('js_cookie_test', 'red panda'); }); diff --git a/core/modules/system/tests/modules/js_cookie_test/js/js_cookie_shim_test.js b/core/modules/system/tests/modules/js_cookie_test/js/js_cookie_shim_test.js index a8dfa51c9fa..2a7a3fd1991 100644 --- a/core/modules/system/tests/modules/js_cookie_test/js/js_cookie_shim_test.js +++ b/core/modules/system/tests/modules/js_cookie_test/js/js_cookie_shim_test.js @@ -9,7 +9,7 @@ var behaviors = _ref.behaviors; behaviors.jqueryCookie = { attach: function attach() { - if ($('body').once('js_cookie_test-init').length) { + if (once('js_cookie_test-init', 'body').length) { $('.js_cookie_test_add_button').on('click', function () { $.cookie('js_cookie_test', 'red panda'); }); diff --git a/core/modules/system/tests/modules/js_cookie_test/js_cookie_test.libraries.yml b/core/modules/system/tests/modules/js_cookie_test/js_cookie_test.libraries.yml index 0f15de6c686..8c1667e86e7 100644 --- a/core/modules/system/tests/modules/js_cookie_test/js_cookie_test.libraries.yml +++ b/core/modules/system/tests/modules/js_cookie_test/js_cookie_test.libraries.yml @@ -6,4 +6,4 @@ with_shim_test: - core/jquery - core/drupal - core/jquery.cookie - - core/jquery.once + - core/once diff --git a/core/modules/system/tests/modules/js_message_test/js/js_message_test.es6.js b/core/modules/system/tests/modules/js_message_test/js/js_message_test.es6.js index d50c50518ec..4c38b23f58d 100644 --- a/core/modules/system/tests/modules/js_message_test/js/js_message_test.es6.js +++ b/core/modules/system/tests/modules/js_message_test/js/js_message_test.es6.js @@ -36,9 +36,10 @@ */ behaviors.js_message_test = { attach() { - $('[data-drupal-messages-area]') - .once('messages-details') - .on('click', '[data-action]', (e) => { + $(once('messages-details', '[data-drupal-messages-area]')).on( + 'click', + '[data-action]', + (e) => { const $target = $(e.currentTarget); const type = $target.attr('data-type'); const area = @@ -58,10 +59,11 @@ } else if (action === 'remove') { message.remove(messageObjects[area].indexes[type].pop()); } - }); - $('[data-action="add-multiple"]') - .once('add-multiple') - .on('click', () => { + }, + ); + $(once('add-multiple', '[data-action="add-multiple"]')).on( + 'click', + () => { /** * Add several of different types to make sure message type doesn't * cause issues in the API. @@ -76,18 +78,20 @@ ), ); }); - }); - $('[data-action="remove-multiple"]') - .once('remove-multiple') - .on('click', () => { + }, + ); + $(once('remove-multiple', '[data-action="remove-multiple"]')).on( + 'click', + () => { messageObjects.multiple.forEach((messageIndex) => messageObjects.default.zone.remove(messageIndex), ); messageObjects.multiple = []; - }); - $('[data-action="add-multiple-error"]') - .once('add-multiple-error') - .on('click', () => { + }, + ); + $(once('add-multiple-error', '[data-action="add-multiple-error"]')).on( + 'click', + () => { // Use the same number of elements to facilitate things on the PHP side. [0, 1, 2, 3, 4, 5].forEach((i) => messageObjects.default.zone.add(`Msg-${i}`, { type: 'error' }), @@ -96,29 +100,27 @@ `Msg-${testMessages.types.length * 2}`, { type: 'status' }, ); - }); - $('[data-action="remove-type"]') - .once('remove-type') - .on('click', () => { - Array.prototype.map - .call( - document.querySelectorAll('[data-drupal-message-id^="error"]'), - (element) => element.getAttribute('data-drupal-message-id'), - ) - .forEach((id) => messageObjects.default.zone.remove(id)); - }); - $('[data-action="clear-all"]') - .once('clear-all') - .on('click', () => { - messageObjects.default.zone.clear(); - }); - $('[data-action="id-no-status"]') - .once('id-no-status') - .on('click', () => { + }, + ); + $(once('remove-type', '[data-action="remove-type"]')).on('click', () => { + Array.prototype.map + .call( + document.querySelectorAll('[data-drupal-message-id^="error"]'), + (element) => element.getAttribute('data-drupal-message-id'), + ) + .forEach((id) => messageObjects.default.zone.remove(id)); + }); + $(once('clear-all', '[data-action="clear-all"]')).on('click', () => { + messageObjects.default.zone.clear(); + }); + $(once('id-no-status', '[data-action="id-no-status"]')).on( + 'click', + () => { messageObjects.default.zone.add('Msg-id-no-status', { id: 'my-special-id', }); - }); + }, + ); }, }; })(jQuery, Drupal, drupalSettings); diff --git a/core/modules/system/tests/modules/js_message_test/js/js_message_test.js b/core/modules/system/tests/modules/js_message_test/js/js_message_test.js index cc764465680..e4f2ce8a00f 100644 --- a/core/modules/system/tests/modules/js_message_test/js/js_message_test.js +++ b/core/modules/system/tests/modules/js_message_test/js/js_message_test.js @@ -28,7 +28,7 @@ }); behaviors.js_message_test = { attach: function attach() { - $('[data-drupal-messages-area]').once('messages-details').on('click', '[data-action]', function (e) { + $(once('messages-details', '[data-drupal-messages-area]')).on('click', '[data-action]', function (e) { var $target = $(e.currentTarget); var type = $target.attr('data-type'); var area = $target.closest('[data-drupal-messages-area]').attr('data-drupal-messages-area') || 'default'; @@ -43,20 +43,20 @@ message.remove(messageObjects[area].indexes[type].pop()); } }); - $('[data-action="add-multiple"]').once('add-multiple').on('click', function () { + $(once('add-multiple', '[data-action="add-multiple"]')).on('click', function () { [0, 1, 2, 3, 4, 5].forEach(function (i) { messageObjects.multiple.push(messageObjects.default.zone.add("This is message number ".concat(i, " of the type, ").concat(testMessages.types[i % testMessages.types.length], ". You be the judge of its importance."), { type: testMessages.types[i % testMessages.types.length] })); }); }); - $('[data-action="remove-multiple"]').once('remove-multiple').on('click', function () { + $(once('remove-multiple', '[data-action="remove-multiple"]')).on('click', function () { messageObjects.multiple.forEach(function (messageIndex) { return messageObjects.default.zone.remove(messageIndex); }); messageObjects.multiple = []; }); - $('[data-action="add-multiple-error"]').once('add-multiple-error').on('click', function () { + $(once('add-multiple-error', '[data-action="add-multiple-error"]')).on('click', function () { [0, 1, 2, 3, 4, 5].forEach(function (i) { return messageObjects.default.zone.add("Msg-".concat(i), { type: 'error' @@ -66,17 +66,17 @@ type: 'status' }); }); - $('[data-action="remove-type"]').once('remove-type').on('click', function () { + $(once('remove-type', '[data-action="remove-type"]')).on('click', function () { Array.prototype.map.call(document.querySelectorAll('[data-drupal-message-id^="error"]'), function (element) { return element.getAttribute('data-drupal-message-id'); }).forEach(function (id) { return messageObjects.default.zone.remove(id); }); }); - $('[data-action="clear-all"]').once('clear-all').on('click', function () { + $(once('clear-all', '[data-action="clear-all"]')).on('click', function () { messageObjects.default.zone.clear(); }); - $('[data-action="id-no-status"]').once('id-no-status').on('click', function () { + $(once('id-no-status', '[data-action="id-no-status"]')).on('click', function () { messageObjects.default.zone.add('Msg-id-no-status', { id: 'my-special-id' }); diff --git a/core/modules/system/tests/modules/js_message_test/js_message_test.libraries.yml b/core/modules/system/tests/modules/js_message_test/js_message_test.libraries.yml index 57501a9ce03..25efe0d8e5f 100644 --- a/core/modules/system/tests/modules/js_message_test/js_message_test.libraries.yml +++ b/core/modules/system/tests/modules/js_message_test/js_message_test.libraries.yml @@ -5,4 +5,4 @@ show_message: dependencies: - core/drupalSettings - core/drupal.message - - core/jquery.once + - core/once diff --git a/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.es6.js b/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.es6.js index 01e878d4500..b0d631cc9b4 100644 --- a/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.es6.js +++ b/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.es6.js @@ -12,11 +12,12 @@ */ Drupal.behaviors.tableDragTest = { attach(context) { - $('.tabledrag-handle', context) - .once('tabledrag-test') - .on('keydown.tabledrag-test', (event) => { + $(once('tabledrag-test', '.tabledrag-handle', context)).on( + 'keydown.tabledrag-test', + (event) => { $(event.currentTarget).removeClass('tabledrag-test-dragging'); - }); + }, + ); }, }; })(jQuery, Drupal); diff --git a/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.js b/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.js index 8e0d8108fe3..6eb1d1ebc45 100644 --- a/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.js +++ b/core/modules/system/tests/modules/tabledrag_test/js/tabledrag_test.js @@ -8,7 +8,7 @@ (function ($, Drupal) { Drupal.behaviors.tableDragTest = { attach: function attach(context) { - $('.tabledrag-handle', context).once('tabledrag-test').on('keydown.tabledrag-test', function (event) { + $(once('tabledrag-test', '.tabledrag-handle', context)).on('keydown.tabledrag-test', function (event) { $(event.currentTarget).removeClass('tabledrag-test-dragging'); }); } diff --git a/core/modules/text/text.es6.js b/core/modules/text/text.es6.js index 3098e5dbf36..3aa8f61998f 100644 --- a/core/modules/text/text.es6.js +++ b/core/modules/text/text.es6.js @@ -14,52 +14,49 @@ */ Drupal.behaviors.textSummary = { attach(context, settings) { - $(context) - .find('.js-text-summary') - .once('text-summary') - .each(function () { - const $widget = $(this).closest('.js-text-format-wrapper'); + once('text-summary', '.js-text-summary', context).forEach((summary) => { + const $widget = $(summary).closest('.js-text-format-wrapper'); - const $summary = $widget.find('.js-text-summary-wrapper'); - const $summaryLabel = $summary.find('label').eq(0); - const $full = $widget.children('.js-form-type-textarea'); - let $fullLabel = $full.find('label').eq(0); + const $summary = $widget.find('.js-text-summary-wrapper'); + const $summaryLabel = $summary.find('label').eq(0); + const $full = $widget.children('.js-form-type-textarea'); + let $fullLabel = $full.find('label').eq(0); - // Create a placeholder label when the field cardinality is greater - // than 1. - if ($fullLabel.length === 0) { - $fullLabel = $('<label></label>').prependTo($full); - } + // Create a placeholder label when the field cardinality is greater + // than 1. + if ($fullLabel.length === 0) { + $fullLabel = $('<label></label>').prependTo($full); + } - // Set up the edit/hide summary link. - const $link = $( - `<span class="field-edit-link"> (<button type="button" class="link link-edit-summary">${Drupal.t( - 'Hide summary', - )}</button>)</span>`, - ); - const $button = $link.find('button'); - let toggleClick = true; - $link - .on('click', (e) => { - if (toggleClick) { - $summary.hide(); - $button.html(Drupal.t('Edit summary')); - $link.appendTo($fullLabel); - } else { - $summary.show(); - $button.html(Drupal.t('Hide summary')); - $link.appendTo($summaryLabel); - } - e.preventDefault(); - toggleClick = !toggleClick; - }) - .appendTo($summaryLabel); + // Set up the edit/hide summary link. + const $link = $( + `<span class="field-edit-link"> (<button type="button" class="link link-edit-summary">${Drupal.t( + 'Hide summary', + )}</button>)</span>`, + ); + const $button = $link.find('button'); + let toggleClick = true; + $link + .on('click', (e) => { + if (toggleClick) { + $summary.hide(); + $button.html(Drupal.t('Edit summary')); + $link.appendTo($fullLabel); + } else { + $summary.show(); + $button.html(Drupal.t('Hide summary')); + $link.appendTo($summaryLabel); + } + e.preventDefault(); + toggleClick = !toggleClick; + }) + .appendTo($summaryLabel); - // If no summary is set, hide the summary field. - if ($widget.find('.js-text-summary').val() === '') { - $link.trigger('click'); - } - }); + // If no summary is set, hide the summary field. + if ($widget.find('.js-text-summary').val() === '') { + $link.trigger('click'); + } + }); }, }; })(jQuery, Drupal); diff --git a/core/modules/text/text.js b/core/modules/text/text.js index 6bd1b9c2408..568083e1cd1 100644 --- a/core/modules/text/text.js +++ b/core/modules/text/text.js @@ -8,8 +8,8 @@ (function ($, Drupal) { Drupal.behaviors.textSummary = { attach: function attach(context, settings) { - $(context).find('.js-text-summary').once('text-summary').each(function () { - var $widget = $(this).closest('.js-text-format-wrapper'); + once('text-summary', '.js-text-summary', context).forEach(function (summary) { + var $widget = $(summary).closest('.js-text-format-wrapper'); var $summary = $widget.find('.js-text-summary-wrapper'); var $summaryLabel = $summary.find('label').eq(0); var $full = $widget.children('.js-form-type-textarea'); diff --git a/core/modules/text/text.libraries.yml b/core/modules/text/text.libraries.yml index 8e824112894..ebcfd3ab88b 100644 --- a/core/modules/text/text.libraries.yml +++ b/core/modules/text/text.libraries.yml @@ -4,5 +4,5 @@ drupal.text: text.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal diff --git a/core/modules/toolbar/js/escapeAdmin.es6.js b/core/modules/toolbar/js/escapeAdmin.es6.js index c84e928a3fe..e4eda0363ed 100644 --- a/core/modules/toolbar/js/escapeAdmin.es6.js +++ b/core/modules/toolbar/js/escapeAdmin.es6.js @@ -32,10 +32,9 @@ */ Drupal.behaviors.escapeAdmin = { attach() { - const $toolbarEscape = $('[data-toolbar-escape-admin]').once( - 'escapeAdmin', - ); - if ($toolbarEscape.length && pathInfo.currentPathIsAdmin) { + const toolbarEscape = once('escapeAdmin', '[data-toolbar-escape-admin]'); + if (toolbarEscape.length && pathInfo.currentPathIsAdmin) { + const $toolbarEscape = $(toolbarEscape); if (escapeAdminPath !== null) { $toolbarEscape.attr('href', escapeAdminPath); } else { diff --git a/core/modules/toolbar/js/escapeAdmin.js b/core/modules/toolbar/js/escapeAdmin.js index 0c469c2a43a..1b7fda1986d 100644 --- a/core/modules/toolbar/js/escapeAdmin.js +++ b/core/modules/toolbar/js/escapeAdmin.js @@ -16,9 +16,11 @@ Drupal.behaviors.escapeAdmin = { attach: function attach() { - var $toolbarEscape = $('[data-toolbar-escape-admin]').once('escapeAdmin'); + var toolbarEscape = once('escapeAdmin', '[data-toolbar-escape-admin]'); + + if (toolbarEscape.length && pathInfo.currentPathIsAdmin) { + var $toolbarEscape = $(toolbarEscape); - if ($toolbarEscape.length && pathInfo.currentPathIsAdmin) { if (escapeAdminPath !== null) { $toolbarEscape.attr('href', escapeAdminPath); } else { diff --git a/core/modules/toolbar/js/toolbar.es6.js b/core/modules/toolbar/js/toolbar.es6.js index 09190530f3f..017e91112a4 100644 --- a/core/modules/toolbar/js/toolbar.es6.js +++ b/core/modules/toolbar/js/toolbar.es6.js @@ -44,161 +44,152 @@ return; } // Process the administrative toolbar. - $(context) - .find('#toolbar-administration') - .once('toolbar') - .each(function () { - // Establish the toolbar models and views. - const model = new Drupal.toolbar.ToolbarModel({ - locked: JSON.parse( - localStorage.getItem('Drupal.toolbar.trayVerticalLocked'), - ), - activeTab: document.getElementById( - JSON.parse(localStorage.getItem('Drupal.toolbar.activeTabID')), - ), - height: $('#toolbar-administration').outerHeight(), - }); + once('toolbar', '#toolbar-administration', context).forEach((toolbar) => { + // Establish the toolbar models and views. + const model = new Drupal.toolbar.ToolbarModel({ + locked: JSON.parse( + localStorage.getItem('Drupal.toolbar.trayVerticalLocked'), + ), + activeTab: document.getElementById( + JSON.parse(localStorage.getItem('Drupal.toolbar.activeTabID')), + ), + height: $('#toolbar-administration').outerHeight(), + }); + + Drupal.toolbar.models.toolbarModel = model; - Drupal.toolbar.models.toolbarModel = model; + // Attach a listener to the configured media query breakpoints. + // Executes it before Drupal.toolbar.views to avoid extra rendering. + Object.keys(options.breakpoints).forEach((label) => { + const mq = options.breakpoints[label]; + const mql = window.matchMedia(mq); + Drupal.toolbar.mql[label] = mql; + // Curry the model and the label of the media query breakpoint to + // the mediaQueryChangeHandler function. + mql.addListener( + Drupal.toolbar.mediaQueryChangeHandler.bind(null, model, label), + ); + // Fire the mediaQueryChangeHandler for each configured breakpoint + // so that they process once. + Drupal.toolbar.mediaQueryChangeHandler.call(null, model, label, mql); + }); - // Attach a listener to the configured media query breakpoints. - // Executes it before Drupal.toolbar.views to avoid extra rendering. - Object.keys(options.breakpoints).forEach((label) => { - const mq = options.breakpoints[label]; - const mql = window.matchMedia(mq); - Drupal.toolbar.mql[label] = mql; - // Curry the model and the label of the media query breakpoint to - // the mediaQueryChangeHandler function. - mql.addListener( - Drupal.toolbar.mediaQueryChangeHandler.bind(null, model, label), - ); - // Fire the mediaQueryChangeHandler for each configured breakpoint - // so that they process once. - Drupal.toolbar.mediaQueryChangeHandler.call( - null, - model, - label, - mql, - ); + Drupal.toolbar.views.toolbarVisualView = + new Drupal.toolbar.ToolbarVisualView({ + el: toolbar, + model, + strings: options.strings, }); + Drupal.toolbar.views.toolbarAuralView = + new Drupal.toolbar.ToolbarAuralView({ + el: toolbar, + model, + strings: options.strings, + }); + Drupal.toolbar.views.bodyVisualView = new Drupal.toolbar.BodyVisualView( + { + el: toolbar, + model, + }, + ); - Drupal.toolbar.views.toolbarVisualView = - new Drupal.toolbar.ToolbarVisualView({ - el: this, - model, - strings: options.strings, - }); - Drupal.toolbar.views.toolbarAuralView = - new Drupal.toolbar.ToolbarAuralView({ - el: this, - model, - strings: options.strings, - }); - Drupal.toolbar.views.bodyVisualView = - new Drupal.toolbar.BodyVisualView({ - el: this, - model, - }); + // Force layout render to fix mobile view. Only needed on load, not + // for every media query match. + model.trigger('change:isFixed', model, model.get('isFixed')); + model.trigger('change:activeTray', model, model.get('activeTray')); - // Force layout render to fix mobile view. Only needed on load, not - // for every media query match. - model.trigger('change:isFixed', model, model.get('isFixed')); - model.trigger('change:activeTray', model, model.get('activeTray')); + // Render collapsible menus. + const menuModel = new Drupal.toolbar.MenuModel(); + Drupal.toolbar.models.menuModel = menuModel; + Drupal.toolbar.views.menuVisualView = new Drupal.toolbar.MenuVisualView( + { + el: $(toolbar).find('.toolbar-menu-administration').get(0), + model: menuModel, + strings: options.strings, + }, + ); - // Render collapsible menus. - const menuModel = new Drupal.toolbar.MenuModel(); - Drupal.toolbar.models.menuModel = menuModel; - Drupal.toolbar.views.menuVisualView = - new Drupal.toolbar.MenuVisualView({ - el: $(this).find('.toolbar-menu-administration').get(0), - model: menuModel, - strings: options.strings, - }); + // Handle the resolution of Drupal.toolbar.setSubtrees. + // This is handled with a deferred so that the function may be invoked + // asynchronously. + Drupal.toolbar.setSubtrees.done((subtrees) => { + menuModel.set('subtrees', subtrees); + const theme = drupalSettings.ajaxPageState.theme; + localStorage.setItem( + `Drupal.toolbar.subtrees.${theme}`, + JSON.stringify(subtrees), + ); + // Indicate on the toolbarModel that subtrees are now loaded. + model.set('areSubtreesLoaded', true); + }); - // Handle the resolution of Drupal.toolbar.setSubtrees. - // This is handled with a deferred so that the function may be invoked - // asynchronously. - Drupal.toolbar.setSubtrees.done((subtrees) => { - menuModel.set('subtrees', subtrees); - const theme = drupalSettings.ajaxPageState.theme; - localStorage.setItem( - `Drupal.toolbar.subtrees.${theme}`, - JSON.stringify(subtrees), - ); - // Indicate on the toolbarModel that subtrees are now loaded. - model.set('areSubtreesLoaded', true); - }); + // Trigger an initial attempt to load menu subitems. This first attempt + // is made after the media query handlers have had an opportunity to + // process. The toolbar starts in the vertical orientation by default, + // unless the viewport is wide enough to accommodate a horizontal + // orientation. Thus we give the Toolbar a chance to determine if it + // should be set to horizontal orientation before attempting to load + // menu subtrees. + Drupal.toolbar.views.toolbarVisualView.loadSubtrees(); - // Trigger an initial attempt to load menu subitems. This first attempt - // is made after the media query handlers have had an opportunity to - // process. The toolbar starts in the vertical orientation by default, - // unless the viewport is wide enough to accommodate a horizontal - // orientation. Thus we give the Toolbar a chance to determine if it - // should be set to horizontal orientation before attempting to load - // menu subtrees. - Drupal.toolbar.views.toolbarVisualView.loadSubtrees(); + $(document) + // Update the model when the viewport offset changes. + .on('drupalViewportOffsetChange.toolbar', (event, offsets) => { + model.set('offsets', offsets); + }); - $(document) - // Update the model when the viewport offset changes. - .on('drupalViewportOffsetChange.toolbar', (event, offsets) => { - model.set('offsets', offsets); - }); + // Broadcast model changes to other modules. + model + .on('change:orientation', (model, orientation) => { + $(document).trigger('drupalToolbarOrientationChange', orientation); + }) + .on('change:activeTab', (model, tab) => { + $(document).trigger('drupalToolbarTabChange', tab); + }) + .on('change:activeTray', (model, tray) => { + $(document).trigger('drupalToolbarTrayChange', tray); + }); - // Broadcast model changes to other modules. - model - .on('change:orientation', (model, orientation) => { - $(document).trigger( - 'drupalToolbarOrientationChange', - orientation, - ); - }) - .on('change:activeTab', (model, tab) => { - $(document).trigger('drupalToolbarTabChange', tab); - }) - .on('change:activeTray', (model, tray) => { - $(document).trigger('drupalToolbarTrayChange', tray); - }); + // If the toolbar's orientation is horizontal and no active tab is + // defined then show the tray of the first toolbar tab by default (but + // not the first 'Home' toolbar tab). + if ( + Drupal.toolbar.models.toolbarModel.get('orientation') === + 'horizontal' && + Drupal.toolbar.models.toolbarModel.get('activeTab') === null + ) { + Drupal.toolbar.models.toolbarModel.set({ + activeTab: $( + '.toolbar-bar .toolbar-tab:not(.home-toolbar-tab) a', + ).get(0), + }); + } - // If the toolbar's orientation is horizontal and no active tab is - // defined then show the tray of the first toolbar tab by default (but - // not the first 'Home' toolbar tab). - if ( - Drupal.toolbar.models.toolbarModel.get('orientation') === - 'horizontal' && - Drupal.toolbar.models.toolbarModel.get('activeTab') === null - ) { - Drupal.toolbar.models.toolbarModel.set({ - activeTab: $( - '.toolbar-bar .toolbar-tab:not(.home-toolbar-tab) a', - ).get(0), - }); - } + $(window).on({ + 'dialog:aftercreate': (event, dialog, $element, settings) => { + const $toolbar = $('#toolbar-bar'); + $toolbar.css('margin-top', '0'); - $(window).on({ - 'dialog:aftercreate': (event, dialog, $element, settings) => { - const $toolbar = $('#toolbar-bar'); - $toolbar.css('margin-top', '0'); + // When off-canvas is positioned in top, toolbar has to be moved down. + if (settings.drupalOffCanvasPosition === 'top') { + const height = Drupal.offCanvas + .getContainer($element) + .outerHeight(); + $toolbar.css('margin-top', `${height}px`); - // When off-canvas is positioned in top, toolbar has to be moved down. - if (settings.drupalOffCanvasPosition === 'top') { - const height = Drupal.offCanvas + $element.on('dialogContentResize.off-canvas', () => { + const newHeight = Drupal.offCanvas .getContainer($element) .outerHeight(); - $toolbar.css('margin-top', `${height}px`); - - $element.on('dialogContentResize.off-canvas', () => { - const newHeight = Drupal.offCanvas - .getContainer($element) - .outerHeight(); - $toolbar.css('margin-top', `${newHeight}px`); - }); - } - }, - 'dialog:beforeclose': () => { - $('#toolbar-bar').css('margin-top', '0'); - }, - }); + $toolbar.css('margin-top', `${newHeight}px`); + }); + } + }, + 'dialog:beforeclose': () => { + $('#toolbar-bar').css('margin-top', '0'); + }, }); + }); }, }; diff --git a/core/modules/toolbar/js/toolbar.js b/core/modules/toolbar/js/toolbar.js index faf546e4e03..53e052ba6fb 100644 --- a/core/modules/toolbar/js/toolbar.js +++ b/core/modules/toolbar/js/toolbar.js @@ -24,7 +24,7 @@ return; } - $(context).find('#toolbar-administration').once('toolbar').each(function () { + once('toolbar', '#toolbar-administration', context).forEach(function (toolbar) { var model = new Drupal.toolbar.ToolbarModel({ locked: JSON.parse(localStorage.getItem('Drupal.toolbar.trayVerticalLocked')), activeTab: document.getElementById(JSON.parse(localStorage.getItem('Drupal.toolbar.activeTabID'))), @@ -39,17 +39,17 @@ Drupal.toolbar.mediaQueryChangeHandler.call(null, model, label, mql); }); Drupal.toolbar.views.toolbarVisualView = new Drupal.toolbar.ToolbarVisualView({ - el: this, + el: toolbar, model: model, strings: options.strings }); Drupal.toolbar.views.toolbarAuralView = new Drupal.toolbar.ToolbarAuralView({ - el: this, + el: toolbar, model: model, strings: options.strings }); Drupal.toolbar.views.bodyVisualView = new Drupal.toolbar.BodyVisualView({ - el: this, + el: toolbar, model: model }); model.trigger('change:isFixed', model, model.get('isFixed')); @@ -57,7 +57,7 @@ var menuModel = new Drupal.toolbar.MenuModel(); Drupal.toolbar.models.menuModel = menuModel; Drupal.toolbar.views.menuVisualView = new Drupal.toolbar.MenuVisualView({ - el: $(this).find('.toolbar-menu-administration').get(0), + el: $(toolbar).find('.toolbar-menu-administration').get(0), model: menuModel, strings: options.strings }); diff --git a/core/modules/toolbar/js/toolbar.menu.es6.js b/core/modules/toolbar/js/toolbar.menu.es6.js index dd85e00c5d5..d80c0a49c19 100644 --- a/core/modules/toolbar/js/toolbar.menu.es6.js +++ b/core/modules/toolbar/js/toolbar.menu.es6.js @@ -165,8 +165,9 @@ // Return the jQuery object. return this.each(function (selector) { - const $menu = $(this).once('toolbar-menu'); - if ($menu.length) { + const menu = once('toolbar-menu', this); + if (menu.length) { + const $menu = $(menu); // Bind event handlers. $menu .on('click.toolbar', '.toolbar-box', toggleClickHandler) diff --git a/core/modules/toolbar/js/toolbar.menu.js b/core/modules/toolbar/js/toolbar.menu.js index fccab385afc..de4f8b596a0 100644 --- a/core/modules/toolbar/js/toolbar.menu.js +++ b/core/modules/toolbar/js/toolbar.menu.js @@ -83,9 +83,10 @@ } return this.each(function (selector) { - var $menu = $(this).once('toolbar-menu'); + var menu = once('toolbar-menu', this); - if ($menu.length) { + if (menu.length) { + var $menu = $(menu); $menu.on('click.toolbar', '.toolbar-box', toggleClickHandler).on('click.toolbar', '.toolbar-box a', linkClickHandler); $menu.addClass('root'); initItems($menu); diff --git a/core/modules/toolbar/js/views/MenuVisualView.es6.js b/core/modules/toolbar/js/views/MenuVisualView.es6.js index 1e706acae9a..916afb21a09 100644 --- a/core/modules/toolbar/js/views/MenuVisualView.es6.js +++ b/core/modules/toolbar/js/views/MenuVisualView.es6.js @@ -24,10 +24,9 @@ const subtrees = this.model.get('subtrees'); // Add subtrees. Object.keys(subtrees || {}).forEach((id) => { - this.$el - .find(`#toolbar-link-${id}`) - .once('toolbar-subtrees') - .after(subtrees[id]); + $( + once('toolbar-subtrees', this.$el.find(`#toolbar-link-${id}`)), + ).after(subtrees[id]); }); // Render the main menu as a nested, collapsible accordion. if ('drupalToolbarMenu' in $.fn) { diff --git a/core/modules/toolbar/js/views/MenuVisualView.js b/core/modules/toolbar/js/views/MenuVisualView.js index a82214c87da..2cbd95067a3 100644 --- a/core/modules/toolbar/js/views/MenuVisualView.js +++ b/core/modules/toolbar/js/views/MenuVisualView.js @@ -15,7 +15,7 @@ var subtrees = this.model.get('subtrees'); Object.keys(subtrees || {}).forEach(function (id) { - _this.$el.find("#toolbar-link-".concat(id)).once('toolbar-subtrees').after(subtrees[id]); + $(once('toolbar-subtrees', _this.$el.find("#toolbar-link-".concat(id)))).after(subtrees[id]); }); if ('drupalToolbarMenu' in $.fn) { diff --git a/core/modules/toolbar/toolbar.libraries.yml b/core/modules/toolbar/toolbar.libraries.yml index 2306bf33198..d8140142d70 100644 --- a/core/modules/toolbar/toolbar.libraries.yml +++ b/core/modules/toolbar/toolbar.libraries.yml @@ -25,7 +25,7 @@ toolbar: - core/drupal.ajax - core/drupal.announce - core/backbone - - core/jquery.once + - core/once - core/drupal.displace - toolbar/toolbar.menu @@ -39,7 +39,7 @@ toolbar.menu: dependencies: - core/jquery - core/drupal - - core/jquery.once + - core/once toolbar.escapeAdmin: version: VERSION @@ -49,4 +49,4 @@ toolbar.escapeAdmin: - core/jquery - core/drupal - core/drupalSettings - - core/jquery.once + - core/once diff --git a/core/modules/tour/js/tour.es6.js b/core/modules/tour/js/tour.es6.js index e682e3db7ed..96c66d9846c 100644 --- a/core/modules/tour/js/tour.es6.js +++ b/core/modules/tour/js/tour.es6.js @@ -25,34 +25,31 @@ */ Drupal.behaviors.tour = { attach(context) { - $('body') - .once('tour') - .each(() => { - const model = new Drupal.tour.models.StateModel(); - // eslint-disable-next-line no-new - new Drupal.tour.views.ToggleTourView({ - el: $(context).find('#toolbar-tab-tour'), - model, - }); - - model - // Allow other scripts to respond to tour events. - .on('change:isActive', (tourModel, isActive) => { - $(document).trigger( - isActive ? 'drupalTourStarted' : 'drupalTourStopped', - ); - }); - // Initialization: check whether a tour is available on the current - // page. - if (settings._tour_internal) { - model.set('tour', settings._tour_internal); - } - - // Start the tour immediately if toggled via query string. - if (/tour=?/i.test(queryString)) { - model.set('isActive', true); - } + once('tour', 'body').forEach(() => { + const model = new Drupal.tour.models.StateModel(); + // eslint-disable-next-line no-new + new Drupal.tour.views.ToggleTourView({ + el: $(context).find('#toolbar-tab-tour'), + model, }); + + model + // Allow other scripts to respond to tour events. + .on('change:isActive', (tourModel, isActive) => { + $(document).trigger( + isActive ? 'drupalTourStarted' : 'drupalTourStopped', + ); + }); + // Initialization: check whether a tour is available on the current + // page. + if (settings._tour_internal) { + model.set('tour', settings._tour_internal); + } + // Start the tour immediately if toggled via query string. + if (/tour=?/i.test(queryString)) { + model.set('isActive', true); + } + }); }, }; diff --git a/core/modules/tour/js/tour.js b/core/modules/tour/js/tour.js index a54c41d759f..c9bf7798c5e 100644 --- a/core/modules/tour/js/tour.js +++ b/core/modules/tour/js/tour.js @@ -9,7 +9,7 @@ var queryString = decodeURI(window.location.search); Drupal.behaviors.tour = { attach: function attach(context) { - $('body').once('tour').each(function () { + once('tour', 'body').forEach(function () { var model = new Drupal.tour.models.StateModel(); new Drupal.tour.views.ToggleTourView({ el: $(context).find('#toolbar-tab-tour'), diff --git a/core/modules/tour/tour.libraries.yml b/core/modules/tour/tour.libraries.yml index 2b408ebd82e..f8f717b019f 100644 --- a/core/modules/tour/tour.libraries.yml +++ b/core/modules/tour/tour.libraries.yml @@ -4,7 +4,7 @@ tour: js/tour.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal - core/backbone - core/shepherd diff --git a/core/modules/tracker/js/tracker-history.es6.js b/core/modules/tracker/js/tracker-history.es6.js index cf49d9fbf71..934fb186a13 100644 --- a/core/modules/tracker/js/tracker-history.es6.js +++ b/core/modules/tracker/js/tracker-history.es6.js @@ -4,11 +4,11 @@ * May only be loaded for authenticated users, with the History module enabled. */ (function ($, Drupal, window) { - function processNodeNewIndicators($placeholders) { + function processNodeNewIndicators(placeholders) { const newNodeString = Drupal.t('new'); const updatedNodeString = Drupal.t('updated'); - $placeholders.each((index, placeholder) => { + placeholders.forEach((placeholder) => { const timestamp = parseInt( placeholder.getAttribute('data-history-node-timestamp'), 10, @@ -24,10 +24,10 @@ }); } - function processNewRepliesIndicators($placeholders) { + function processNewRepliesIndicators(placeholders) { // Figure out which placeholders need the "x new" replies links. const placeholdersToUpdate = {}; - $placeholders.each((index, placeholder) => { + placeholders.forEach((placeholder) => { const timestamp = parseInt( placeholder.getAttribute('data-history-node-last-comment-timestamp'), 10, @@ -80,67 +80,69 @@ // Find all "new" comment indicator placeholders newer than 30 days ago that // have not already been read after their last comment timestamp. const nodeIDs = []; - const $nodeNewPlaceholders = $(context) - .find('[data-history-node-timestamp]') - .once('history') - .filter(function () { - const nodeTimestamp = parseInt( - this.getAttribute('data-history-node-timestamp'), - 10, - ); - const nodeID = this.getAttribute('data-history-node-id'); - if (Drupal.history.needsServerCheck(nodeID, nodeTimestamp)) { - nodeIDs.push(nodeID); - return true; - } + const nodeNewPlaceholders = once( + 'history', + '[data-history-node-timestamp]', + context, + ).filter((placeholder) => { + const nodeTimestamp = parseInt( + placeholder.getAttribute('data-history-node-timestamp'), + 10, + ); + const nodeID = placeholder.getAttribute('data-history-node-id'); + if (Drupal.history.needsServerCheck(nodeID, nodeTimestamp)) { + nodeIDs.push(nodeID); + return true; + } - return false; - }); + return false; + }); // Find all "new" comment indicator placeholders newer than 30 days ago that // have not already been read after their last comment timestamp. - const $newRepliesPlaceholders = $(context) - .find('[data-history-node-last-comment-timestamp]') - .once('history') - .filter(function () { - const lastCommentTimestamp = parseInt( - this.getAttribute('data-history-node-last-comment-timestamp'), - 10, - ); - const nodeTimestamp = parseInt( - this.previousSibling.previousSibling.getAttribute( - 'data-history-node-timestamp', - ), - 10, - ); - // Discard placeholders that have zero comments. - if (lastCommentTimestamp === nodeTimestamp) { - return false; - } - const nodeID = this.previousSibling.previousSibling.getAttribute( - 'data-history-node-id', - ); - if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) { - if (nodeIDs.indexOf(nodeID) === -1) { - nodeIDs.push(nodeID); - } - return true; + const newRepliesPlaceholders = once( + 'history', + '[data-history-node-last-comment-timestamp]', + context, + ).filter((placeholder) => { + const lastCommentTimestamp = parseInt( + placeholder.getAttribute('data-history-node-last-comment-timestamp'), + 10, + ); + const nodeTimestamp = parseInt( + placeholder.previousSibling.previousSibling.getAttribute( + 'data-history-node-timestamp', + ), + 10, + ); + // Discard placeholders that have zero comments. + if (lastCommentTimestamp === nodeTimestamp) { + return false; + } + const nodeID = placeholder.previousSibling.previousSibling.getAttribute( + 'data-history-node-id', + ); + if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) { + if (nodeIDs.indexOf(nodeID) === -1) { + nodeIDs.push(nodeID); } + return true; + } - return false; - }); + return false; + }); if ( - $nodeNewPlaceholders.length === 0 && - $newRepliesPlaceholders.length === 0 + nodeNewPlaceholders.length === 0 && + newRepliesPlaceholders.length === 0 ) { return; } // Fetch the node read timestamps from the server. Drupal.history.fetchTimestamps(nodeIDs, () => { - processNodeNewIndicators($nodeNewPlaceholders); - processNewRepliesIndicators($newRepliesPlaceholders); + processNodeNewIndicators(nodeNewPlaceholders); + processNewRepliesIndicators(newRepliesPlaceholders); }); }, }; diff --git a/core/modules/tracker/js/tracker-history.js b/core/modules/tracker/js/tracker-history.js index dcfa946d3c3..74ac7330242 100644 --- a/core/modules/tracker/js/tracker-history.js +++ b/core/modules/tracker/js/tracker-history.js @@ -6,10 +6,10 @@ **/ (function ($, Drupal, window) { - function processNodeNewIndicators($placeholders) { + function processNodeNewIndicators(placeholders) { var newNodeString = Drupal.t('new'); var updatedNodeString = Drupal.t('updated'); - $placeholders.each(function (index, placeholder) { + placeholders.forEach(function (placeholder) { var timestamp = parseInt(placeholder.getAttribute('data-history-node-timestamp'), 10); var nodeID = placeholder.getAttribute('data-history-node-id'); var lastViewTimestamp = Drupal.history.getLastRead(nodeID); @@ -21,9 +21,9 @@ }); } - function processNewRepliesIndicators($placeholders) { + function processNewRepliesIndicators(placeholders) { var placeholdersToUpdate = {}; - $placeholders.each(function (index, placeholder) { + placeholders.forEach(function (placeholder) { var timestamp = parseInt(placeholder.getAttribute('data-history-node-last-comment-timestamp'), 10); var nodeID = placeholder.previousSibling.previousSibling.getAttribute('data-history-node-id'); var lastViewTimestamp = Drupal.history.getLastRead(nodeID); @@ -60,9 +60,9 @@ Drupal.behaviors.trackerHistory = { attach: function attach(context) { var nodeIDs = []; - var $nodeNewPlaceholders = $(context).find('[data-history-node-timestamp]').once('history').filter(function () { - var nodeTimestamp = parseInt(this.getAttribute('data-history-node-timestamp'), 10); - var nodeID = this.getAttribute('data-history-node-id'); + var nodeNewPlaceholders = once('history', '[data-history-node-timestamp]', context).filter(function (placeholder) { + var nodeTimestamp = parseInt(placeholder.getAttribute('data-history-node-timestamp'), 10); + var nodeID = placeholder.getAttribute('data-history-node-id'); if (Drupal.history.needsServerCheck(nodeID, nodeTimestamp)) { nodeIDs.push(nodeID); @@ -71,15 +71,15 @@ return false; }); - var $newRepliesPlaceholders = $(context).find('[data-history-node-last-comment-timestamp]').once('history').filter(function () { - var lastCommentTimestamp = parseInt(this.getAttribute('data-history-node-last-comment-timestamp'), 10); - var nodeTimestamp = parseInt(this.previousSibling.previousSibling.getAttribute('data-history-node-timestamp'), 10); + var newRepliesPlaceholders = once('history', '[data-history-node-last-comment-timestamp]', context).filter(function (placeholder) { + var lastCommentTimestamp = parseInt(placeholder.getAttribute('data-history-node-last-comment-timestamp'), 10); + var nodeTimestamp = parseInt(placeholder.previousSibling.previousSibling.getAttribute('data-history-node-timestamp'), 10); if (lastCommentTimestamp === nodeTimestamp) { return false; } - var nodeID = this.previousSibling.previousSibling.getAttribute('data-history-node-id'); + var nodeID = placeholder.previousSibling.previousSibling.getAttribute('data-history-node-id'); if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) { if (nodeIDs.indexOf(nodeID) === -1) { @@ -92,13 +92,13 @@ return false; }); - if ($nodeNewPlaceholders.length === 0 && $newRepliesPlaceholders.length === 0) { + if (nodeNewPlaceholders.length === 0 && newRepliesPlaceholders.length === 0) { return; } Drupal.history.fetchTimestamps(nodeIDs, function () { - processNodeNewIndicators($nodeNewPlaceholders); - processNewRepliesIndicators($newRepliesPlaceholders); + processNodeNewIndicators(nodeNewPlaceholders); + processNewRepliesIndicators(newRepliesPlaceholders); }); } }; diff --git a/core/modules/user/user.es6.js b/core/modules/user/user.es6.js index cd2a50e72cd..0b6a6c966aa 100644 --- a/core/modules/user/user.es6.js +++ b/core/modules/user/user.es6.js @@ -63,224 +63,219 @@ Drupal.behaviors.password = { attach(context, settings) { const cssClasses = Drupal.user.password.css; - $(context) - .find('input.js-password-field') - .once('password') - .each((index, value) => { - const $mainInput = $(value); - const $mainInputParent = $mainInput - .parent() - .addClass(cssClasses.passwordParent); - const $passwordWidget = $mainInput.closest( - '.js-form-type-password-confirm', + once('password', 'input.js-password-field', context).forEach((value) => { + const $mainInput = $(value); + const $mainInputParent = $mainInput + .parent() + .addClass(cssClasses.passwordParent); + const $passwordWidget = $mainInput.closest( + '.js-form-type-password-confirm', + ); + const $confirmInput = $passwordWidget.find('input.js-password-confirm'); + const $passwordConfirmMessage = $( + Drupal.theme('passwordConfirmMessage', settings.password), + ); + + let $passwordMatchStatus = $passwordConfirmMessage + .find('[data-drupal-selector="password-match-status-text"]') + .first(); + if ($passwordMatchStatus.length === 0) { + $passwordMatchStatus = $passwordConfirmMessage.find('span').first(); + Drupal.deprecationError({ + message: + 'Returning <span> without data-drupal-selector="password-match-status-text" attribute is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. See https://www.drupal.org/node/3152101', + }); + } + + const $confirmInputParent = $confirmInput + .parent() + .addClass('confirm-parent') + .append($passwordConfirmMessage); + + // List of classes to be removed from the strength bar on a state + // change. + const passwordStrengthBarClassesToRemove = [ + cssClasses.passwordWeak || '', + cssClasses.passwordFair || '', + cssClasses.passwordGood || '', + cssClasses.passwordStrong || '', + ] + .join(' ') + .trim(); + + // List of classes to be removed from the text wrapper on a state + // change. + const confirmTextWrapperClassesToRemove = [ + cssClasses.passwordsMatch || '', + cssClasses.passwordsNotMatch || '', + ] + .join(' ') + .trim(); + + // List of classes to be removed from the widget on a state change. + const widgetClassesToRemove = [ + cssClasses.widgetInitial || '', + cssClasses.passwordEmpty || '', + cssClasses.passwordFilled || '', + cssClasses.confirmEmpty || '', + cssClasses.confirmFilled || '', + ] + .join(' ') + .trim(); + + const password = {}; + + // If the password strength indicator is enabled, add its markup. + if (settings.password.showStrengthIndicator) { + const $passwordStrength = $( + Drupal.theme('passwordStrength', settings.password), ); - const $confirmInput = $passwordWidget.find( - 'input.js-password-confirm', - ); - const $passwordConfirmMessage = $( - Drupal.theme('passwordConfirmMessage', settings.password), - ); - - let $passwordMatchStatus = $passwordConfirmMessage - .find('[data-drupal-selector="password-match-status-text"]') + password.$strengthBar = $passwordStrength + .find('[data-drupal-selector="password-strength-indicator"]') .first(); - if ($passwordMatchStatus.length === 0) { - $passwordMatchStatus = $passwordConfirmMessage.find('span').first(); + if (password.$strengthBar.length === 0) { + password.$strengthBar = $passwordStrength + .find('.js-password-strength__indicator') + .first(); Drupal.deprecationError({ message: - 'Returning <span> without data-drupal-selector="password-match-status-text" attribute is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. See https://www.drupal.org/node/3152101', + 'The js-password-strength__indicator class is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Replace js-password-strength__indicator with a data-drupal-selector="password-strength-indicator" attribute. See https://www.drupal.org/node/3152101', }); } - - const $confirmInputParent = $confirmInput - .parent() - .addClass('confirm-parent') - .append($passwordConfirmMessage); - - // List of classes to be removed from the strength bar on a state - // change. - const passwordStrengthBarClassesToRemove = [ - cssClasses.passwordWeak || '', - cssClasses.passwordFair || '', - cssClasses.passwordGood || '', - cssClasses.passwordStrong || '', - ] - .join(' ') - .trim(); - - // List of classes to be removed from the text wrapper on a state - // change. - const confirmTextWrapperClassesToRemove = [ - cssClasses.passwordsMatch || '', - cssClasses.passwordsNotMatch || '', - ] - .join(' ') - .trim(); - - // List of classes to be removed from the widget on a state change. - const widgetClassesToRemove = [ - cssClasses.widgetInitial || '', - cssClasses.passwordEmpty || '', - cssClasses.passwordFilled || '', - cssClasses.confirmEmpty || '', - cssClasses.confirmFilled || '', - ] - .join(' ') - .trim(); - - const password = {}; - - // If the password strength indicator is enabled, add its markup. - if (settings.password.showStrengthIndicator) { - const $passwordStrength = $( - Drupal.theme('passwordStrength', settings.password), - ); - password.$strengthBar = $passwordStrength - .find('[data-drupal-selector="password-strength-indicator"]') - .first(); - if (password.$strengthBar.length === 0) { - password.$strengthBar = $passwordStrength - .find('.js-password-strength__indicator') - .first(); - Drupal.deprecationError({ - message: - 'The js-password-strength__indicator class is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Replace js-password-strength__indicator with a data-drupal-selector="password-strength-indicator" attribute. See https://www.drupal.org/node/3152101', - }); - } + password.$strengthTextWrapper = $passwordStrength + .find('[data-drupal-selector="password-strength-text"]') + .first(); + if (password.$strengthTextWrapper.length === 0) { password.$strengthTextWrapper = $passwordStrength - .find('[data-drupal-selector="password-strength-text"]') + .find('.js-password-strength__text') .first(); - if (password.$strengthTextWrapper.length === 0) { - password.$strengthTextWrapper = $passwordStrength - .find('.js-password-strength__text') - .first(); - Drupal.deprecationError({ - message: - 'The js-password-strength__text class is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Replace js-password-strength__text with a data-drupal-selector="password-strength-text" attribute. See https://www.drupal.org/node/3152101', - }); - } - password.$suggestions = $( - Drupal.theme('passwordSuggestions', settings.password, []), - ); - - password.$suggestions.hide(); - $mainInputParent.append($passwordStrength); - $confirmInputParent.after(password.$suggestions); + Drupal.deprecationError({ + message: + 'The js-password-strength__text class is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Replace js-password-strength__text with a data-drupal-selector="password-strength-text" attribute. See https://www.drupal.org/node/3152101', + }); } + password.$suggestions = $( + Drupal.theme('passwordSuggestions', settings.password, []), + ); - /** - * Adds classes to the widget indicating if the elements are filled. - */ - const addWidgetClasses = () => { - $passwordWidget - .addClass( - $mainInput.val() - ? cssClasses.passwordFilled - : cssClasses.passwordEmpty, - ) - .addClass( - $confirmInput.val() - ? cssClasses.confirmFilled - : cssClasses.confirmEmpty, + password.$suggestions.hide(); + $mainInputParent.append($passwordStrength); + $confirmInputParent.after(password.$suggestions); + } + + /** + * Adds classes to the widget indicating if the elements are filled. + */ + const addWidgetClasses = () => { + $passwordWidget + .addClass( + $mainInput.val() + ? cssClasses.passwordFilled + : cssClasses.passwordEmpty, + ) + .addClass( + $confirmInput.val() + ? cssClasses.confirmFilled + : cssClasses.confirmEmpty, + ); + }; + + /** + * Check that password and confirmation inputs match. + * + * @param {string} confirmInputVal + * The value of the confirm input. + */ + const passwordCheckMatch = (confirmInputVal) => { + const passwordsAreMatching = $mainInput.val() === confirmInputVal; + const confirmClass = passwordsAreMatching + ? cssClasses.passwordsMatch + : cssClasses.passwordsNotMatch; + const confirmMessage = passwordsAreMatching + ? settings.password.confirmSuccess + : settings.password.confirmFailure; + + // Update the success message and set the class if needed. + if ( + !$passwordMatchStatus.hasClass(confirmClass) || + !$passwordMatchStatus.html() === confirmMessage + ) { + if (confirmTextWrapperClassesToRemove) { + $passwordMatchStatus.removeClass( + confirmTextWrapperClassesToRemove, ); - }; - - /** - * Check that password and confirmation inputs match. - * - * @param {string} confirmInputVal - * The value of the confirm input. - */ - const passwordCheckMatch = (confirmInputVal) => { - const passwordsAreMatching = $mainInput.val() === confirmInputVal; - const confirmClass = passwordsAreMatching - ? cssClasses.passwordsMatch - : cssClasses.passwordsNotMatch; - const confirmMessage = passwordsAreMatching - ? settings.password.confirmSuccess - : settings.password.confirmFailure; - - // Update the success message and set the class if needed. - if ( - !$passwordMatchStatus.hasClass(confirmClass) || - !$passwordMatchStatus.html() === confirmMessage - ) { - if (confirmTextWrapperClassesToRemove) { - $passwordMatchStatus.removeClass( - confirmTextWrapperClassesToRemove, - ); - } - $passwordMatchStatus.html(confirmMessage).addClass(confirmClass); } - }; - - /** - * Checks the password strength. - */ - const passwordCheck = () => { - if (settings.password.showStrengthIndicator) { - // Evaluate the password strength. - const result = Drupal.evaluatePasswordStrength( - $mainInput.val(), + $passwordMatchStatus.html(confirmMessage).addClass(confirmClass); + } + }; + + /** + * Checks the password strength. + */ + const passwordCheck = () => { + if (settings.password.showStrengthIndicator) { + // Evaluate the password strength. + const result = Drupal.evaluatePasswordStrength( + $mainInput.val(), + settings.password, + ); + const $currentPasswordSuggestions = $( + Drupal.theme( + 'passwordSuggestions', settings.password, - ); - const $currentPasswordSuggestions = $( - Drupal.theme( - 'passwordSuggestions', - settings.password, - result.messageTips, - ), - ); + result.messageTips, + ), + ); - // Update the suggestions for how to improve the password if needed. - if ( - password.$suggestions.html() !== - $currentPasswordSuggestions.html() - ) { - password.$suggestions.replaceWith($currentPasswordSuggestions); - password.$suggestions = $currentPasswordSuggestions.toggle( - // Only show the description box if a weakness exists in the - // password. - result.strength !== 100, - ); - } - - if (passwordStrengthBarClassesToRemove) { - password.$strengthBar.removeClass( - passwordStrengthBarClassesToRemove, - ); - } - // Adjust the length of the strength indicator. - password.$strengthBar - .css('width', `${result.strength}%`) - .addClass(result.indicatorClass); - - // Update the strength indication text. - password.$strengthTextWrapper.html(result.indicatorText); + // Update the suggestions for how to improve the password if needed. + if ( + password.$suggestions.html() !== + $currentPasswordSuggestions.html() + ) { + password.$suggestions.replaceWith($currentPasswordSuggestions); + password.$suggestions = $currentPasswordSuggestions.toggle( + // Only show the description box if a weakness exists in the + // password. + result.strength !== 100, + ); } - // Check the value in the confirm input and show results. - if ($confirmInput.val()) { - passwordCheckMatch($confirmInput.val()); - $passwordConfirmMessage.css({ visibility: 'visible' }); - } else { - $passwordConfirmMessage.css({ visibility: 'hidden' }); + if (passwordStrengthBarClassesToRemove) { + password.$strengthBar.removeClass( + passwordStrengthBarClassesToRemove, + ); } + // Adjust the length of the strength indicator. + password.$strengthBar + .css('width', `${result.strength}%`) + .addClass(result.indicatorClass); - if (widgetClassesToRemove) { - $passwordWidget.removeClass(widgetClassesToRemove); - addWidgetClasses(); - } - }; + // Update the strength indication text. + password.$strengthTextWrapper.html(result.indicatorText); + } + + // Check the value in the confirm input and show results. + if ($confirmInput.val()) { + passwordCheckMatch($confirmInput.val()); + $passwordConfirmMessage.css({ visibility: 'visible' }); + } else { + $passwordConfirmMessage.css({ visibility: 'hidden' }); + } if (widgetClassesToRemove) { + $passwordWidget.removeClass(widgetClassesToRemove); addWidgetClasses(); } + }; + + if (widgetClassesToRemove) { + addWidgetClasses(); + } - // Monitor input events. - $mainInput.on('input', passwordCheck); - $confirmInput.on('input', passwordCheck); - }); + // Monitor input events. + $mainInput.on('input', passwordCheck); + $confirmInput.on('input', passwordCheck); + }); }, }; diff --git a/core/modules/user/user.js b/core/modules/user/user.js index 1d30e44bd45..5e55522cf0a 100644 --- a/core/modules/user/user.js +++ b/core/modules/user/user.js @@ -27,7 +27,7 @@ Drupal.behaviors.password = { attach: function attach(context, settings) { var cssClasses = Drupal.user.password.css; - $(context).find('input.js-password-field').once('password').each(function (index, value) { + once('password', 'input.js-password-field', context).forEach(function (value) { var $mainInput = $(value); var $mainInputParent = $mainInput.parent().addClass(cssClasses.passwordParent); var $passwordWidget = $mainInput.closest('.js-form-type-password-confirm'); diff --git a/core/modules/user/user.libraries.yml b/core/modules/user/user.libraries.yml index 0e6e9533a2e..0aecebe9164 100644 --- a/core/modules/user/user.libraries.yml +++ b/core/modules/user/user.libraries.yml @@ -9,7 +9,7 @@ drupal.user: dependencies: - core/jquery - core/drupal - - core/jquery.once + - core/once drupal.user.admin: version: VERSION @@ -23,7 +23,7 @@ drupal.user.permissions: user.permissions.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal - core/drupalSettings - user/drupal.user.admin diff --git a/core/modules/user/user.permissions.es6.js b/core/modules/user/user.permissions.es6.js index 31f0e2a9966..ae22cbb5e3d 100644 --- a/core/modules/user/user.permissions.es6.js +++ b/core/modules/user/user.permissions.es6.js @@ -14,62 +14,59 @@ */ Drupal.behaviors.permissions = { attach(context) { - const self = this; - $('table#permissions') - .once('permissions') - .each(function () { - // On a site with many roles and permissions, this behavior initially - // has to perform thousands of DOM manipulations to inject checkboxes - // and hide them. By detaching the table from the DOM, all operations - // can be performed without triggering internal layout and re-rendering - // processes in the browser. - const $table = $(this); - let $ancestor; - let method; - if ($table.prev().length) { - $ancestor = $table.prev(); - method = 'after'; - } else { - $ancestor = $table.parent(); - method = 'append'; - } - $table.detach(); + once('permissions', 'table#permissions').forEach((table) => { + // On a site with many roles and permissions, this behavior initially + // has to perform thousands of DOM manipulations to inject checkboxes + // and hide them. By detaching the table from the DOM, all operations + // can be performed without triggering internal layout and re-rendering + // processes in the browser. + const $table = $(table); + let $ancestor; + let method; + if ($table.prev().length) { + $ancestor = $table.prev(); + method = 'after'; + } else { + $ancestor = $table.parent(); + method = 'append'; + } + $table.detach(); - // Create dummy checkboxes. We use dummy checkboxes instead of reusing - // the existing checkboxes here because new checkboxes don't alter the - // submitted form. If we'd automatically check existing checkboxes, the - // permission table would be polluted with redundant entries. This - // is deliberate, but desirable when we automatically check them. - const $dummy = $(Drupal.theme('checkbox')) - .removeClass('form-checkbox') - .addClass('dummy-checkbox js-dummy-checkbox') - .attr('disabled', 'disabled') - .attr('checked', 'checked') - .attr( - 'title', - Drupal.t( - 'This permission is inherited from the authenticated user role.', - ), - ) - .hide(); + // Create dummy checkboxes. We use dummy checkboxes instead of reusing + // the existing checkboxes here because new checkboxes don't alter the + // submitted form. If we'd automatically check existing checkboxes, the + // permission table would be polluted with redundant entries. This is + // deliberate, but desirable when we automatically check them. + const $dummy = $(Drupal.theme('checkbox')) + .removeClass('form-checkbox') + .addClass('dummy-checkbox js-dummy-checkbox') + .attr('disabled', 'disabled') + .attr('checked', 'checked') + .attr( + 'title', + Drupal.t( + 'This permission is inherited from the authenticated user role.', + ), + ) + .hide(); - $table - .find('input[type="checkbox"]') - .not('.js-rid-anonymous, .js-rid-authenticated') - .addClass('real-checkbox js-real-checkbox') - .after($dummy); + $table + .find('input[type="checkbox"]') + .not('.js-rid-anonymous, .js-rid-authenticated') + .addClass('real-checkbox js-real-checkbox') + .after($dummy); - // Initialize the authenticated user checkbox. - $table - .find('input[type=checkbox].js-rid-authenticated') - .on('click.permissions', self.toggle) - // .triggerHandler() cannot be used here, as it only affects the first - // element. - .each(self.toggle); + // Initialize the authenticated user checkbox. + $table + .find('input[type=checkbox].js-rid-authenticated') + .on('click.permissions', this.toggle) + // .triggerHandler() cannot be used here, as it only affects the first + // element. + .each(this.toggle); - // Re-insert the table into the DOM. - $ancestor[method]($table); - }); + // Re-insert the table into the DOM. + $ancestor[method]($table); + }); }, /** diff --git a/core/modules/user/user.permissions.js b/core/modules/user/user.permissions.js index f28e9f17106..e6d4ea4691a 100644 --- a/core/modules/user/user.permissions.js +++ b/core/modules/user/user.permissions.js @@ -8,9 +8,10 @@ (function ($, Drupal) { Drupal.behaviors.permissions = { attach: function attach(context) { - var self = this; - $('table#permissions').once('permissions').each(function () { - var $table = $(this); + var _this = this; + + once('permissions', 'table#permissions').forEach(function (table) { + var $table = $(table); var $ancestor; var method; @@ -25,7 +26,7 @@ $table.detach(); var $dummy = $(Drupal.theme('checkbox')).removeClass('form-checkbox').addClass('dummy-checkbox js-dummy-checkbox').attr('disabled', 'disabled').attr('checked', 'checked').attr('title', Drupal.t('This permission is inherited from the authenticated user role.')).hide(); $table.find('input[type="checkbox"]').not('.js-rid-anonymous, .js-rid-authenticated').addClass('real-checkbox js-real-checkbox').after($dummy); - $table.find('input[type=checkbox].js-rid-authenticated').on('click.permissions', self.toggle).each(self.toggle); + $table.find('input[type=checkbox].js-rid-authenticated').on('click.permissions', _this.toggle).each(_this.toggle); $ancestor[method]($table); }); }, diff --git a/core/modules/views/js/ajax_view.es6.js b/core/modules/views/js/ajax_view.es6.js index 5367f83cc96..9423bb1d641 100644 --- a/core/modules/views/js/ajax_view.es6.js +++ b/core/modules/views/js/ajax_view.es6.js @@ -105,17 +105,18 @@ '-', )}-${settings.view_display_id.replace(/_/g, '-')}`, ); - this.$exposed_form - .once('exposed-form') - .each($.proxy(this.attachExposedFormAjax, this)); + once('exposed-form', this.$exposed_form).forEach( + $.proxy(this.attachExposedFormAjax, this), + ); // Add the ajax to pagers. - this.$view - // Don't attach to nested views. Doing so would attach multiple behaviors - // to a given element. - .filter($.proxy(this.filterNestedViews, this)) - .once('ajax-pager') - .each($.proxy(this.attachPagerAjax, this)); + once( + 'ajax-pager', + this.$view + // Don't attach to nested views. Doing so would attach multiple behaviors + // to a given element. + .filter($.proxy(this.filterNestedViews, this)), + ).forEach($.proxy(this.attachPagerAjax, this)); // Add a trigger to update this view specifically. In order to trigger a // refresh use the following code. diff --git a/core/modules/views/js/ajax_view.js b/core/modules/views/js/ajax_view.js index f1e2e0121ab..225836f4f8b 100644 --- a/core/modules/views/js/ajax_view.js +++ b/core/modules/views/js/ajax_view.js @@ -67,8 +67,8 @@ }; this.settings = settings; this.$exposed_form = $("form#views-exposed-form-".concat(settings.view_name.replace(/_/g, '-'), "-").concat(settings.view_display_id.replace(/_/g, '-'))); - this.$exposed_form.once('exposed-form').each($.proxy(this.attachExposedFormAjax, this)); - this.$view.filter($.proxy(this.filterNestedViews, this)).once('ajax-pager').each($.proxy(this.attachPagerAjax, this)); + once('exposed-form', this.$exposed_form).forEach($.proxy(this.attachExposedFormAjax, this)); + once('ajax-pager', this.$view.filter($.proxy(this.filterNestedViews, this))).forEach($.proxy(this.attachPagerAjax, this)); var selfSettings = $.extend({}, this.element_settings, { event: 'RefreshView', base: this.selector, diff --git a/core/modules/views/views.libraries.yml b/core/modules/views/views.libraries.yml index 640492d7190..fe5827f2ee2 100644 --- a/core/modules/views/views.libraries.yml +++ b/core/modules/views/views.libraries.yml @@ -13,6 +13,6 @@ views.ajax: - core/jquery - core/drupal - core/drupalSettings - - core/jquery.once + - core/once - core/jquery.form - core/drupal.ajax diff --git a/core/modules/views_ui/js/ajax.es6.js b/core/modules/views_ui/js/ajax.es6.js index 748fa7946e6..56035376950 100644 --- a/core/modules/views_ui/js/ajax.es6.js +++ b/core/modules/views_ui/js/ajax.es6.js @@ -44,19 +44,22 @@ // Identify the button that was clicked so that .ajaxSubmit() can use it. // We need to do this for both .click() and .mousedown() since JavaScript // code might trigger either behavior. - const $submitButtons = $form - .find('input[type=submit].js-form-submit, button.js-form-submit') - .once('views-ajax-submit'); + const $submitButtons = $( + once( + 'views-ajax-submit', + $form.find('input[type=submit].js-form-submit, button.js-form-submit'), + ), + ); $submitButtons.on('click mousedown', function () { this.form.clk = this; }); - $form.once('views-ajax-submit').each(function () { - const $form = $(this); + once('views-ajax-submit', $form).forEach((form) => { + const $form = $(form); const elementSettings = { url: response.url, event: 'submit', base: $form.attr('id'), - element: this, + element: form, }; const ajaxForm = Drupal.ajax(elementSettings); ajaxForm.$form = $form; @@ -166,13 +169,14 @@ */ Drupal.behaviors.livePreview = { attach(context) { - $('input#edit-displays-live-preview', context) - .once('views-ajax') - .on('click', function () { + $(once('views-ajax', 'input#edit-displays-live-preview', context)).on( + 'click', + function () { if ($(this).is(':checked')) { $('#preview-submit').trigger('click'); } - }); + }, + ); }, }; @@ -186,15 +190,13 @@ */ Drupal.behaviors.syncPreviewDisplay = { attach(context) { - $('#views-tabset a') - .once('views-ajax') - .on('click', function () { - const href = $(this).attr('href'); - // Cut of #views-tabset. - const displayId = href.substr(11); - // Set the form element. - $('#views-live-preview #preview-display-id').val(displayId); - }); + $(once('views-ajax', '#views-tabset a')).on('click', function () { + const href = $(this).attr('href'); + // Cut of #views-tabset. + const displayId = href.substr(11); + // Set the form element. + $('#views-live-preview #preview-display-id').val(displayId); + }); }, }; @@ -214,58 +216,56 @@ progress: { type: 'fullscreen' }, }; // Bind AJAX behaviors to all items showing the class. - $('a.views-ajax-link', context) - .once('views-ajax') - .each(function () { - const elementSettings = baseElementSettings; - elementSettings.base = $(this).attr('id'); - elementSettings.element = this; - // Set the URL to go to the anchor. - if ($(this).attr('href')) { - elementSettings.url = $(this).attr('href'); - } - Drupal.ajax(elementSettings); - }); + once('views-ajax', 'a.views-ajax-link', context).forEach((link) => { + const $link = $(link); + const elementSettings = baseElementSettings; + elementSettings.base = $link.attr('id'); + elementSettings.element = link; + // Set the URL to go to the anchor. + if ($link.attr('href')) { + elementSettings.url = $link.attr('href'); + } + Drupal.ajax(elementSettings); + }); - $('div#views-live-preview a') - .once('views-ajax') - .each(function () { - // We don't bind to links without a URL. - if (!$(this).attr('href')) { - return true; - } + once('views-ajax', 'div#views-live-preview a').forEach((link) => { + const $link = $(link); + // We don't bind to links without a URL. + if (!$link.attr('href')) { + return true; + } - const elementSettings = baseElementSettings; - // Set the URL to go to the anchor. - elementSettings.url = $(this).attr('href'); - if ( - Drupal.Views.getPath(elementSettings.url).substring(0, 21) !== - 'admin/structure/views' - ) { - return true; - } + const elementSettings = baseElementSettings; + // Set the URL to go to the anchor. + elementSettings.url = $link.attr('href'); + if ( + Drupal.Views.getPath(elementSettings.url).substring(0, 21) !== + 'admin/structure/views' + ) { + return true; + } - elementSettings.wrapper = 'views-preview-wrapper'; - elementSettings.method = 'replaceWith'; - elementSettings.base = $(this).attr('id'); - elementSettings.element = this; - Drupal.ajax(elementSettings); - }); + elementSettings.wrapper = 'views-preview-wrapper'; + elementSettings.method = 'replaceWith'; + elementSettings.base = link.id; + elementSettings.element = link; + Drupal.ajax(elementSettings); + }); // Within a live preview, make exposed widget form buttons re-trigger the // Preview button. // @todo Revisit this after fixing Views UI to display a Preview outside // of the main Edit form. - $('div#views-live-preview input[type=submit]') - .once('views-ajax') - .each(function (event) { - $(this).on('click', function () { + once('views-ajax', 'div#views-live-preview input[type=submit]').forEach( + (submit) => { + const $submit = $(submit); + $submit.on('click', function () { this.form.clk = this; return true; }); const elementSettings = baseElementSettings; // Set the URL to go to the anchor. - elementSettings.url = $(this.form).attr('action'); + elementSettings.url = $(submit.form).attr('action'); if ( Drupal.Views.getPath(elementSettings.url).substring(0, 21) !== 'admin/structure/views' @@ -276,11 +276,12 @@ elementSettings.wrapper = 'views-preview-wrapper'; elementSettings.method = 'replaceWith'; elementSettings.event = 'click'; - elementSettings.base = $(this).attr('id'); - elementSettings.element = this; + elementSettings.base = submit.id; + elementSettings.element = submit; Drupal.ajax(elementSettings); - }); + }, + ); }, }; })(jQuery, Drupal, drupalSettings); diff --git a/core/modules/views_ui/js/ajax.js b/core/modules/views_ui/js/ajax.js index e233b41b6c5..8de29e68202 100644 --- a/core/modules/views_ui/js/ajax.js +++ b/core/modules/views_ui/js/ajax.js @@ -13,17 +13,17 @@ Drupal.AjaxCommands.prototype.viewsSetForm = function (ajax, response, status) { var $form = $('.js-views-ui-dialog form'); - var $submitButtons = $form.find('input[type=submit].js-form-submit, button.js-form-submit').once('views-ajax-submit'); + var $submitButtons = $(once('views-ajax-submit', $form.find('input[type=submit].js-form-submit, button.js-form-submit'))); $submitButtons.on('click mousedown', function () { this.form.clk = this; }); - $form.once('views-ajax-submit').each(function () { - var $form = $(this); + once('views-ajax-submit', $form).forEach(function (form) { + var $form = $(form); var elementSettings = { url: response.url, event: 'submit', base: $form.attr('id'), - element: this + element: form }; var ajaxForm = Drupal.ajax(elementSettings); ajaxForm.$form = $form; @@ -59,7 +59,7 @@ Drupal.behaviors.livePreview = { attach: function attach(context) { - $('input#edit-displays-live-preview', context).once('views-ajax').on('click', function () { + $(once('views-ajax', 'input#edit-displays-live-preview', context)).on('click', function () { if ($(this).is(':checked')) { $('#preview-submit').trigger('click'); } @@ -68,7 +68,7 @@ }; Drupal.behaviors.syncPreviewDisplay = { attach: function attach(context) { - $('#views-tabset a').once('views-ajax').on('click', function () { + $(once('views-ajax', '#views-tabset a')).on('click', function () { var href = $(this).attr('href'); var displayId = href.substr(11); $('#views-live-preview #preview-display-id').val(displayId); @@ -84,24 +84,27 @@ type: 'fullscreen' } }; - $('a.views-ajax-link', context).once('views-ajax').each(function () { + once('views-ajax', 'a.views-ajax-link', context).forEach(function (link) { + var $link = $(link); var elementSettings = baseElementSettings; - elementSettings.base = $(this).attr('id'); - elementSettings.element = this; + elementSettings.base = $link.attr('id'); + elementSettings.element = link; - if ($(this).attr('href')) { - elementSettings.url = $(this).attr('href'); + if ($link.attr('href')) { + elementSettings.url = $link.attr('href'); } Drupal.ajax(elementSettings); }); - $('div#views-live-preview a').once('views-ajax').each(function () { - if (!$(this).attr('href')) { + once('views-ajax', 'div#views-live-preview a').forEach(function (link) { + var $link = $(link); + + if (!$link.attr('href')) { return true; } var elementSettings = baseElementSettings; - elementSettings.url = $(this).attr('href'); + elementSettings.url = $link.attr('href'); if (Drupal.Views.getPath(elementSettings.url).substring(0, 21) !== 'admin/structure/views') { return true; @@ -109,17 +112,18 @@ elementSettings.wrapper = 'views-preview-wrapper'; elementSettings.method = 'replaceWith'; - elementSettings.base = $(this).attr('id'); - elementSettings.element = this; + elementSettings.base = link.id; + elementSettings.element = link; Drupal.ajax(elementSettings); }); - $('div#views-live-preview input[type=submit]').once('views-ajax').each(function (event) { - $(this).on('click', function () { + once('views-ajax', 'div#views-live-preview input[type=submit]').forEach(function (submit) { + var $submit = $(submit); + $submit.on('click', function () { this.form.clk = this; return true; }); var elementSettings = baseElementSettings; - elementSettings.url = $(this.form).attr('action'); + elementSettings.url = $(submit.form).attr('action'); if (Drupal.Views.getPath(elementSettings.url).substring(0, 21) !== 'admin/structure/views') { return true; @@ -128,8 +132,8 @@ elementSettings.wrapper = 'views-preview-wrapper'; elementSettings.method = 'replaceWith'; elementSettings.event = 'click'; - elementSettings.base = $(this).attr('id'); - elementSettings.element = this; + elementSettings.base = submit.id; + elementSettings.element = submit; Drupal.ajax(elementSettings); }); } diff --git a/core/modules/views_ui/js/dialog.views.es6.js b/core/modules/views_ui/js/dialog.views.es6.js index 5612d248afe..b5cbb91fbb5 100644 --- a/core/modules/views_ui/js/dialog.views.es6.js +++ b/core/modules/views_ui/js/dialog.views.es6.js @@ -41,24 +41,23 @@ */ Drupal.behaviors.viewsModalContent = { attach(context) { - $('body') - .once('viewsDialog') - .on( - 'dialogContentResize.viewsDialog', - '.ui-dialog-content', - handleDialogResize, - ); + $(once('viewsDialog', 'body')).on( + 'dialogContentResize.viewsDialog', + '.ui-dialog-content', + handleDialogResize, + ); // When expanding details, make sure the modal is resized. - $(context) - .find('.scroll') - .once('detailsUpdate') - .on('click', 'summary', (e) => { + $(once('detailsUpdate', '.scroll', context)).on( + 'click', + 'summary', + (e) => { $(e.currentTarget).trigger('dialogContentResize'); - }); + }, + ); }, detach(context, settings, trigger) { if (trigger === 'unload') { - $('body').removeOnce('viewsDialog').off('.viewsDialog'); + $(once.remove('viewsDialog', 'body')).off('.viewsDialog'); } }, }; diff --git a/core/modules/views_ui/js/dialog.views.js b/core/modules/views_ui/js/dialog.views.js index 18739a94ee5..625f4798aca 100644 --- a/core/modules/views_ui/js/dialog.views.js +++ b/core/modules/views_ui/js/dialog.views.js @@ -32,14 +32,14 @@ Drupal.behaviors.viewsModalContent = { attach: function attach(context) { - $('body').once('viewsDialog').on('dialogContentResize.viewsDialog', '.ui-dialog-content', handleDialogResize); - $(context).find('.scroll').once('detailsUpdate').on('click', 'summary', function (e) { + $(once('viewsDialog', 'body')).on('dialogContentResize.viewsDialog', '.ui-dialog-content', handleDialogResize); + $(once('detailsUpdate', '.scroll', context)).on('click', 'summary', function (e) { $(e.currentTarget).trigger('dialogContentResize'); }); }, detach: function detach(context, settings, trigger) { if (trigger === 'unload') { - $('body').removeOnce('viewsDialog').off('.viewsDialog'); + $(once.remove('viewsDialog', 'body')).off('.viewsDialog'); } } }; diff --git a/core/modules/views_ui/js/views-admin.es6.js b/core/modules/views_ui/js/views-admin.es6.js index 21e98f61667..e27b3997190 100644 --- a/core/modules/views_ui/js/views-admin.es6.js +++ b/core/modules/views_ui/js/views-admin.es6.js @@ -265,7 +265,7 @@ if (!$context.is('form[id^="views-ui-add-handler-form"]')) { $form = $context.find('form[id^="views-ui-add-handler-form"]'); } - if ($form.once('views-ui-add-handler-form').length) { + if (once('views-ui-add-handler-form', $form).length) { // If we we have an unprocessed views-ui-add-handler-form, let's // instantiate. new Drupal.viewsUi.AddItemForm($form); @@ -361,12 +361,15 @@ Drupal.behaviors.viewsUiRenderAddViewButton = { attach(context) { // Build the add display menu and pull the display input buttons into it. - const $menu = $(context) - .find('#views-display-menu-tabs') - .once('views-ui-render-add-view-button'); - if (!$menu.length) { + const menu = once( + 'views-ui-render-add-view-button', + '#views-display-menu-tabs', + context, + ); + if (!menu.length) { return; } + const $menu = $(menu); const $addDisplayDropdown = $( `<li class="add"><a href="#"><span class="icon add"></span>${Drupal.t( @@ -451,7 +454,7 @@ $form = $context.find('form[id^="views-ui-add-handler-form"]'); } // Make sure we don't add more than one event handler to the same form. - if ($form.once('views-ui-filter-options').length) { + if (once('views-ui-filter-options', $form).length) { new Drupal.viewsUi.OptionsSearch($form); } }, @@ -618,13 +621,13 @@ // Executes an initial preview. if ( - $('#edit-displays-live-preview') - .once('edit-displays-live-preview') - .is(':checked') + $(once('edit-displays-live-preview', '#edit-displays-live-preview')).is( + ':checked', + ) ) { - $('#preview-submit') - .once('edit-displays-live-preview') - .trigger('click'); + $(once('edit-displays-live-preview', '#preview-submit')).trigger( + 'click', + ); } }, }; @@ -701,13 +704,15 @@ // next to the filters in each group, and bind a handler so that they change // based on the values of the operator dropdown within that group. this.redrawOperatorLabels(); - $table - .find('.views-group-title select') - .once('views-rearrange-filter-handler') - .on( - 'change.views-rearrange-filter-handler', - $.proxy(this, 'redrawOperatorLabels'), - ); + $( + once( + 'views-rearrange-filter-handler', + $table.find('.views-group-title select'), + ), + ).on( + 'change.views-rearrange-filter-handler', + $.proxy(this, 'redrawOperatorLabels'), + ); // Bind handlers so that when a "Remove" link is clicked, we: // - Update the rowspans of cells containing an operator dropdown (since @@ -715,9 +720,12 @@ // - Redraw the operator labels next to the filters in the group (since the // filter that is currently displayed last in each group is not supposed // to have a label display next to it). - $table - .find('a.views-groups-remove-link') - .once('views-rearrange-filter-handler') + $( + once( + 'views-rearrange-filter-handler', + $table.find('a.views-groups-remove-link'), + ), + ) .on( 'click.views-rearrange-filter-handler', $.proxy(this, 'updateRowspans'), @@ -740,12 +748,15 @@ // Since Drupal does not provide a theme function for this markup this is // the best we can do. $( - `<ul class="action-links"><li><a id="views-add-group-link" href="#">${this.addGroupButton.val()}</a></li></ul>`, + once( + 'views-rearrange-filter-handler', + // When the link is clicked, dynamically click the hidden form + // button for adding a new filter group. + $( + `<ul class="action-links"><li><a id="views-add-group-link" href="#">${this.addGroupButton.val()}</a></li></ul>`, + ).prependTo(this.table.parent()), + ), ) - .prependTo(this.table.parent()) - // When the link is clicked, dynamically click the hidden form button - // for adding a new filter group. - .once('views-rearrange-filter-handler') .find('#views-add-group-link') .on( 'click.views-rearrange-filter-handler', @@ -760,19 +771,21 @@ const $removeGroupButton = $(this.removeGroupButtons[i]); const buttonId = $removeGroupButton.attr('id'); $( - `<a href="#" class="views-remove-group-link">${Drupal.t( - 'Remove group', - )}</a>`, - ) - .insertBefore($removeGroupButton) - // When the link is clicked, dynamically click the corresponding form - // button. - .once('views-rearrange-filter-handler') - .on( - 'click.views-rearrange-filter-handler', - { buttonId }, - $.proxy(this, 'clickRemoveGroupButton'), - ); + once( + 'views-rearrange-filter-handler', + // When the link is clicked, dynamically click the corresponding form + // button. + $( + `<a href="#" class="views-remove-group-link">${Drupal.t( + 'Remove group', + )}</a>`, + ).insertBefore($removeGroupButton), + ), + ).on( + 'click.views-rearrange-filter-handler', + { buttonId }, + $.proxy(this, 'clickRemoveGroupButton'), + ); } }, @@ -810,8 +823,9 @@ let newRow; let titleRow; - const titleRows = $('tr.views-group-title').once( + const titleRows = once( 'duplicateGroupsOperator', + 'tr.views-group-title', ); if (!titleRows.length) { @@ -1077,19 +1091,20 @@ */ Drupal.behaviors.viewsFilterConfigSelectAll = { attach(context) { - const $context = $(context); - - const $selectAll = $context - .find('.js-form-item-options-value-all') - .once('filterConfigSelectAll'); - const $selectAllCheckbox = $selectAll.find('input[type=checkbox]'); - const $checkboxes = $selectAll - .closest('.form-checkboxes') - .find( - '.js-form-type-checkbox:not(.js-form-item-options-value-all) input[type="checkbox"]', - ); + const selectAll = once( + 'filterConfigSelectAll', + '.js-form-item-options-value-all', + context, + ); - if ($selectAll.length) { + if (selectAll.length) { + const $selectAll = $(selectAll); + const $selectAllCheckbox = $selectAll.find('input[type=checkbox]'); + const $checkboxes = $selectAll + .closest('.form-checkboxes') + .find( + '.js-form-type-checkbox:not(.js-form-item-options-value-all) input[type="checkbox"]', + ); // Show the select all checkbox. $selectAll.show(); $selectAllCheckbox.on('click', function () { @@ -1117,9 +1132,7 @@ */ Drupal.behaviors.viewsRemoveIconClass = { attach(context) { - $(context) - .find('.dropbutton') - .once('dropbutton-icon') + $(once('dropbutton-icon', '.dropbutton', context)) .find('.icon') .removeClass('icon'); }, @@ -1135,14 +1148,10 @@ */ Drupal.behaviors.viewsUiCheckboxify = { attach(context, settings) { - const $buttons = $( + const buttons = once( + 'views-ui-checkboxify', '[data-drupal-selector="edit-options-expose-button-button"], [data-drupal-selector="edit-options-group-button-button"]', - ).once('views-ui-checkboxify'); - const length = $buttons.length; - let i; - for (i = 0; i < length; i++) { - new Drupal.viewsUi.Checkboxifier($buttons[i]); - } + ).forEach((button) => new Drupal.viewsUi.Checkboxifier(button)); }, }; @@ -1185,7 +1194,7 @@ * * @constructor * - * @param {HTMLElement} button + * @param {Element} button * The DOM object representing the button to be checkboxified. */ Drupal.viewsUi.Checkboxifier = function (button) { @@ -1220,37 +1229,39 @@ */ Drupal.behaviors.viewsUiOverrideSelect = { attach(context) { - $(context) - .find('[data-drupal-selector="edit-override-dropdown"]') - .once('views-ui-override-button-text') - .each(function () { - // Closures! :( - const $context = $(context); - const $submit = $context.find('[id^=edit-submit]'); - const oldValue = $submit.val(); - - $submit - .once('views-ui-override-button-text') - .on('mouseup', function () { - $(this).val(oldValue); - return true; - }); - - $(this) - .on('change', function () { - const $this = $(this); - if ($this.val() === 'default') { - $submit.val(Drupal.t('Apply (all displays)')); - } else if ($this.val() === 'default_revert') { - $submit.val(Drupal.t('Revert to default')); - } else { - $submit.val(Drupal.t('Apply (this display)')); - } - const $dialog = $context.closest('.ui-dialog-content'); - $dialog.trigger('dialogButtonsChange'); - }) - .trigger('change'); - }); + once( + 'views-ui-override-button-text', + '[data-drupal-selector="edit-override-dropdown"]', + context, + ).forEach((dropdown) => { + // Closures! :( + const $context = $(context); + const $submit = $context.find('[id^=edit-submit]'); + const oldValue = $submit.val(); + + $(once('views-ui-override-button-text', $submit)).on( + 'mouseup', + function () { + $(this).val(oldValue); + return true; + }, + ); + + $(dropdown) + .on('change', function () { + const $this = $(this); + if ($this.val() === 'default') { + $submit.val(Drupal.t('Apply (all displays)')); + } else if ($this.val() === 'default_revert') { + $submit.val(Drupal.t('Revert to default')); + } else { + $submit.val(Drupal.t('Apply (this display)')); + } + const $dialog = $context.closest('.ui-dialog-content'); + $dialog.trigger('dialogButtonsChange'); + }) + .trigger('change'); + }); }, }; @@ -1267,27 +1278,27 @@ const $context = $(context); // Handle handler deletion by looking for the hidden checkbox and hiding // the row. - $context - .find('a.views-remove-link') - .once('views') - .on('click', function (event) { + $(once('views', 'a.views-remove-link', context)).on( + 'click', + function (event) { const id = $(this).attr('id').replace('views-remove-link-', ''); $context.find(`#views-row-${id}`).hide(); $context.find(`#views-removed-${id}`).prop('checked', true); event.preventDefault(); - }); + }, + ); // Handle display deletion by looking for the hidden checkbox and hiding // the row. - $context - .find('a.display-remove-link') - .once('display') - .on('click', function (event) { + $(once('display', 'a.display-remove-link', context)).on( + 'click', + function (event) { const id = $(this).attr('id').replace('display-remove-link-', ''); $context.find(`#display-row-${id}`).hide(); $context.find(`#display-removed-${id}`).prop('checked', true); event.preventDefault(); - }); + }, + ); }, }; @@ -1310,15 +1321,18 @@ ) { return; } - const $context = $(context); - const $table = $context - .find('#views-rearrange-filters') - .once('views-rearrange-filters'); - const $operator = $context - .find('.js-form-item-filter-groups-operator') - .once('views-rearrange-filters'); - if ($table.length) { - new Drupal.viewsUi.RearrangeFilterHandler($table, $operator); + const table = once( + 'views-rearrange-filters', + '#views-rearrange-filters', + context, + ); + const operator = once( + 'views-rearrange-filters', + '.js-form-item-filter-groups-operator', + context, + ); + if (table.length) { + new Drupal.viewsUi.RearrangeFilterHandler($(table), $(operator)); } }, }; diff --git a/core/modules/views_ui/js/views-admin.js b/core/modules/views_ui/js/views-admin.js index 0bcca18d239..e6dd88e8243 100644 --- a/core/modules/views_ui/js/views-admin.js +++ b/core/modules/views_ui/js/views-admin.js @@ -113,7 +113,7 @@ $form = $context.find('form[id^="views-ui-add-handler-form"]'); } - if ($form.once('views-ui-add-handler-form').length) { + if (once('views-ui-add-handler-form', $form).length) { new Drupal.viewsUi.AddItemForm($form); } } @@ -159,12 +159,13 @@ Drupal.behaviors.viewsUiRenderAddViewButton = { attach: function attach(context) { - var $menu = $(context).find('#views-display-menu-tabs').once('views-ui-render-add-view-button'); + var menu = once('views-ui-render-add-view-button', '#views-display-menu-tabs', context); - if (!$menu.length) { + if (!menu.length) { return; } + var $menu = $(menu); var $addDisplayDropdown = $("<li class=\"add\"><a href=\"#\"><span class=\"icon add\"></span>".concat(Drupal.t('Add'), "</a><ul class=\"action-list\" style=\"display:none;\"></ul></li>")); var $displayButtons = $menu.nextAll('input.add-display').detach(); $displayButtons.appendTo($addDisplayDropdown.find('.action-list')).wrap('<li>').parent().eq(0).addClass('first').end().eq(-1).addClass('last'); @@ -206,7 +207,7 @@ $form = $context.find('form[id^="views-ui-add-handler-form"]'); } - if ($form.once('views-ui-filter-options').length) { + if (once('views-ui-filter-options', $form).length) { new Drupal.viewsUi.OptionsSearch($form); } } @@ -291,8 +292,8 @@ $('#preview-args').parent().hide(); } - if ($('#edit-displays-live-preview').once('edit-displays-live-preview').is(':checked')) { - $('#preview-submit').once('edit-displays-live-preview').trigger('click'); + if ($(once('edit-displays-live-preview', '#edit-displays-live-preview')).is(':checked')) { + $(once('edit-displays-live-preview', '#preview-submit')).trigger('click'); } } }; @@ -313,20 +314,20 @@ this.modifyTableDrag(); this.redrawOperatorLabels(); - $table.find('.views-group-title select').once('views-rearrange-filter-handler').on('change.views-rearrange-filter-handler', $.proxy(this, 'redrawOperatorLabels')); - $table.find('a.views-groups-remove-link').once('views-rearrange-filter-handler').on('click.views-rearrange-filter-handler', $.proxy(this, 'updateRowspans')).on('click.views-rearrange-filter-handler', $.proxy(this, 'redrawOperatorLabels')); + $(once('views-rearrange-filter-handler', $table.find('.views-group-title select'))).on('change.views-rearrange-filter-handler', $.proxy(this, 'redrawOperatorLabels')); + $(once('views-rearrange-filter-handler', $table.find('a.views-groups-remove-link'))).on('click.views-rearrange-filter-handler', $.proxy(this, 'updateRowspans')).on('click.views-rearrange-filter-handler', $.proxy(this, 'redrawOperatorLabels')); }; $.extend(Drupal.viewsUi.RearrangeFilterHandler.prototype, { insertAddRemoveFilterGroupLinks: function insertAddRemoveFilterGroupLinks() { - $("<ul class=\"action-links\"><li><a id=\"views-add-group-link\" href=\"#\">".concat(this.addGroupButton.val(), "</a></li></ul>")).prependTo(this.table.parent()).once('views-rearrange-filter-handler').find('#views-add-group-link').on('click.views-rearrange-filter-handler', $.proxy(this, 'clickAddGroupButton')); + $(once('views-rearrange-filter-handler', $("<ul class=\"action-links\"><li><a id=\"views-add-group-link\" href=\"#\">".concat(this.addGroupButton.val(), "</a></li></ul>")).prependTo(this.table.parent()))).find('#views-add-group-link').on('click.views-rearrange-filter-handler', $.proxy(this, 'clickAddGroupButton')); var length = this.removeGroupButtons.length; var i; for (i = 0; i < length; i++) { var $removeGroupButton = $(this.removeGroupButtons[i]); var buttonId = $removeGroupButton.attr('id'); - $("<a href=\"#\" class=\"views-remove-group-link\">".concat(Drupal.t('Remove group'), "</a>")).insertBefore($removeGroupButton).once('views-rearrange-filter-handler').on('click.views-rearrange-filter-handler', { + $(once('views-rearrange-filter-handler', $("<a href=\"#\" class=\"views-remove-group-link\">".concat(Drupal.t('Remove group'), "</a>")).insertBefore($removeGroupButton))).on('click.views-rearrange-filter-handler', { buttonId: buttonId }, $.proxy(this, 'clickRemoveGroupButton')); } @@ -342,7 +343,7 @@ duplicateGroupsOperator: function duplicateGroupsOperator() { var newRow; var titleRow; - var titleRows = $('tr.views-group-title').once('duplicateGroupsOperator'); + var titleRows = once('duplicateGroupsOperator', 'tr.views-group-title'); if (!titleRows.length) { return this.operator; @@ -476,12 +477,12 @@ }); Drupal.behaviors.viewsFilterConfigSelectAll = { attach: function attach(context) { - var $context = $(context); - var $selectAll = $context.find('.js-form-item-options-value-all').once('filterConfigSelectAll'); - var $selectAllCheckbox = $selectAll.find('input[type=checkbox]'); - var $checkboxes = $selectAll.closest('.form-checkboxes').find('.js-form-type-checkbox:not(.js-form-item-options-value-all) input[type="checkbox"]'); + var selectAll = once('filterConfigSelectAll', '.js-form-item-options-value-all', context); - if ($selectAll.length) { + if (selectAll.length) { + var $selectAll = $(selectAll); + var $selectAllCheckbox = $selectAll.find('input[type=checkbox]'); + var $checkboxes = $selectAll.closest('.form-checkboxes').find('.js-form-type-checkbox:not(.js-form-item-options-value-all) input[type="checkbox"]'); $selectAll.show(); $selectAllCheckbox.on('click', function () { $checkboxes.prop('checked', $(this).is(':checked')); @@ -496,18 +497,14 @@ }; Drupal.behaviors.viewsRemoveIconClass = { attach: function attach(context) { - $(context).find('.dropbutton').once('dropbutton-icon').find('.icon').removeClass('icon'); + $(once('dropbutton-icon', '.dropbutton', context)).find('.icon').removeClass('icon'); } }; Drupal.behaviors.viewsUiCheckboxify = { attach: function attach(context, settings) { - var $buttons = $('[data-drupal-selector="edit-options-expose-button-button"], [data-drupal-selector="edit-options-group-button-button"]').once('views-ui-checkboxify'); - var length = $buttons.length; - var i; - - for (i = 0; i < length; i++) { - new Drupal.viewsUi.Checkboxifier($buttons[i]); - } + var buttons = once('views-ui-checkboxify', '[data-drupal-selector="edit-options-expose-button-button"], [data-drupal-selector="edit-options-group-button-button"]').forEach(function (button) { + return new Drupal.viewsUi.Checkboxifier(button); + }); } }; Drupal.behaviors.viewsUiChangeDefaultWidget = { @@ -545,15 +542,15 @@ Drupal.behaviors.viewsUiOverrideSelect = { attach: function attach(context) { - $(context).find('[data-drupal-selector="edit-override-dropdown"]').once('views-ui-override-button-text').each(function () { + once('views-ui-override-button-text', '[data-drupal-selector="edit-override-dropdown"]', context).forEach(function (dropdown) { var $context = $(context); var $submit = $context.find('[id^=edit-submit]'); var oldValue = $submit.val(); - $submit.once('views-ui-override-button-text').on('mouseup', function () { + $(once('views-ui-override-button-text', $submit)).on('mouseup', function () { $(this).val(oldValue); return true; }); - $(this).on('change', function () { + $(dropdown).on('change', function () { var $this = $(this); if ($this.val() === 'default') { @@ -573,13 +570,13 @@ Drupal.behaviors.viewsUiHandlerRemoveLink = { attach: function attach(context) { var $context = $(context); - $context.find('a.views-remove-link').once('views').on('click', function (event) { + $(once('views', 'a.views-remove-link', context)).on('click', function (event) { var id = $(this).attr('id').replace('views-remove-link-', ''); $context.find("#views-row-".concat(id)).hide(); $context.find("#views-removed-".concat(id)).prop('checked', true); event.preventDefault(); }); - $context.find('a.display-remove-link').once('display').on('click', function (event) { + $(once('display', 'a.display-remove-link', context)).on('click', function (event) { var id = $(this).attr('id').replace('display-remove-link-', ''); $context.find("#display-row-".concat(id)).hide(); $context.find("#display-removed-".concat(id)).prop('checked', true); @@ -593,12 +590,11 @@ return; } - var $context = $(context); - var $table = $context.find('#views-rearrange-filters').once('views-rearrange-filters'); - var $operator = $context.find('.js-form-item-filter-groups-operator').once('views-rearrange-filters'); + var table = once('views-rearrange-filters', '#views-rearrange-filters', context); + var operator = once('views-rearrange-filters', '.js-form-item-filter-groups-operator', context); - if ($table.length) { - new Drupal.viewsUi.RearrangeFilterHandler($table, $operator); + if (table.length) { + new Drupal.viewsUi.RearrangeFilterHandler($(table), $(operator)); } } }; diff --git a/core/modules/views_ui/js/views_ui.listing.es6.js b/core/modules/views_ui/js/views_ui.listing.es6.js index 7ef913182e9..a3ba5604e38 100644 --- a/core/modules/views_ui/js/views_ui.listing.es6.js +++ b/core/modules/views_ui/js/views_ui.listing.es6.js @@ -18,8 +18,11 @@ */ Drupal.behaviors.viewTableFilterByText = { attach(context, settings) { - const $input = $('input.views-filter-text').once('views-filter-text'); - const $table = $($input.attr('data-table')); + const [input] = once('views-filter-text', 'input.views-filter-text'); + if (!input) { + return; + } + const $table = $(input.getAttribute('data-table')); let $rows; function filterViewList(e) { @@ -44,7 +47,7 @@ if ($table.length) { $rows = $table.find('tbody tr'); - $input.on('keyup', filterViewList); + $(input).on('keyup', filterViewList); } }, }; diff --git a/core/modules/views_ui/js/views_ui.listing.js b/core/modules/views_ui/js/views_ui.listing.js index 06369cc9625..47b6ef747fc 100644 --- a/core/modules/views_ui/js/views_ui.listing.js +++ b/core/modules/views_ui/js/views_ui.listing.js @@ -5,11 +5,30 @@ * @preserve **/ +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } + +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } + +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } + +function _iterableToArrayLimit(arr, i) { var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]); if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + (function ($, Drupal) { Drupal.behaviors.viewTableFilterByText = { attach: function attach(context, settings) { - var $input = $('input.views-filter-text').once('views-filter-text'); - var $table = $($input.attr('data-table')); + var _once = once('views-filter-text', 'input.views-filter-text'), + _once2 = _slicedToArray(_once, 1), + input = _once2[0]; + + if (!input) { + return; + } + + var $table = $(input.getAttribute('data-table')); var $rows; function filterViewList(e) { @@ -31,7 +50,7 @@ if ($table.length) { $rows = $table.find('tbody tr'); - $input.on('keyup', filterViewList); + $(input).on('keyup', filterViewList); } } }; diff --git a/core/modules/views_ui/views_ui.libraries.yml b/core/modules/views_ui/views_ui.libraries.yml index 44b6832abdf..f78faf26fe6 100644 --- a/core/modules/views_ui/views_ui.libraries.yml +++ b/core/modules/views_ui/views_ui.libraries.yml @@ -8,7 +8,7 @@ views_ui.admin: - core/jquery - core/drupal - core/drupalSettings - - core/jquery.once + - core/once - core/jquery.form - core/drupal.form - core/drupal.ajax @@ -23,7 +23,7 @@ views_ui.listing: dependencies: - core/jquery - core/drupal - - core/jquery.once + - core/once - views_ui/admin.styling admin.styling: diff --git a/core/themes/claro/claro.libraries.yml b/core/themes/claro/claro.libraries.yml index 91b9c040852..f182132a670 100644 --- a/core/themes/claro/claro.libraries.yml +++ b/core/themes/claro/claro.libraries.yml @@ -114,7 +114,7 @@ drupal.nav-tabs: dependencies: - core/jquery - core/drupal - - core/jquery.once + - core/once - core/drupal.debounce - core/collapse @@ -124,7 +124,7 @@ drupal.responsive-detail: js/responsive-details.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/collapse claro.jquery.ui: @@ -286,6 +286,10 @@ media_library.ui: css/components/media-library.ui.css : {} js: js/media-library.ui.js: { weight: -1 } + dependencies: + - core/drupal + - core/jquery + - core/once progress: version: VERSION diff --git a/core/themes/claro/js/details.es6.js b/core/themes/claro/js/details.es6.js index fbac54177d4..05853d6915b 100644 --- a/core/themes/claro/js/details.es6.js +++ b/core/themes/claro/js/details.es6.js @@ -15,13 +15,16 @@ */ Drupal.behaviors.claroDetails = { attach(context) { - $(context) - .once('claroDetails') - .on('click', (event) => { + // The second argument of once() needs to be an instance of Element, but + // document is an instance of Document, replace it with the html Element. + $(once('claroDetails', context === document ? 'html' : context)).on( + 'click', + (event) => { if (event.target.nodeName === 'SUMMARY') { $(event.target).trigger('focus'); } - }); + }, + ); }, }; @@ -41,16 +44,16 @@ return; } - $(context) - .find('details .details-title') - .once('claroDetailsToggleShim') - .on('keypress', (event) => { + $(once('claroDetailsToggleShim', 'details .details-title', context)).on( + 'keypress', + (event) => { const keyCode = event.keyCode || event.charCode; if (keyCode === 32) { $(event.target).closest('summary').trigger('click'); event.preventDefault(); } - }); + }, + ); }, }; diff --git a/core/themes/claro/js/details.js b/core/themes/claro/js/details.js index f9d12b91e23..853c99163fd 100644 --- a/core/themes/claro/js/details.js +++ b/core/themes/claro/js/details.js @@ -8,7 +8,7 @@ (function ($, Modernizr, Drupal) { Drupal.behaviors.claroDetails = { attach: function attach(context) { - $(context).once('claroDetails').on('click', function (event) { + $(once('claroDetails', context === document ? 'html' : context)).on('click', function (event) { if (event.target.nodeName === 'SUMMARY') { $(event.target).trigger('focus'); } @@ -21,7 +21,7 @@ return; } - $(context).find('details .details-title').once('claroDetailsToggleShim').on('keypress', function (event) { + $(once('claroDetailsToggleShim', 'details .details-title', context)).on('keypress', function (event) { var keyCode = event.keyCode || event.charCode; if (keyCode === 32) { diff --git a/core/themes/claro/js/media-library.ui.es6.js b/core/themes/claro/js/media-library.ui.es6.js index 88213945581..8eee2ad1fe1 100644 --- a/core/themes/claro/js/media-library.ui.es6.js +++ b/core/themes/claro/js/media-library.ui.es6.js @@ -17,9 +17,12 @@ // has been added to the Media Library dialog. // @todo replace with theme function override in // https://drupal.org/node/3134526 - $(window) - .once('media-library-selection-info-claro-event') - .on('dialog:aftercreate', (event, dialog, $element, settings) => { + if (!once('media-library-selection-info-claro-event', 'html').length) { + return; + } + $(window).on( + 'dialog:aftercreate', + (event, dialog, $element, settings) => { // Since the dialog HTML is not part of the context, we can't use // context here. const moveCounter = ($selectedCount, $buttonPane) => { @@ -62,7 +65,8 @@ subtree: true, }); } - }); + }, + ); }, }; })(jQuery, Drupal, window); diff --git a/core/themes/claro/js/media-library.ui.js b/core/themes/claro/js/media-library.ui.js index ddf44a4e452..2a8e8a08b9e 100644 --- a/core/themes/claro/js/media-library.ui.js +++ b/core/themes/claro/js/media-library.ui.js @@ -8,7 +8,11 @@ (function ($, Drupal, window) { Drupal.behaviors.MediaLibraryItemSelectionClaro = { attach: function attach() { - $(window).once('media-library-selection-info-claro-event').on('dialog:aftercreate', function (event, dialog, $element, settings) { + if (!once('media-library-selection-info-claro-event', 'html').length) { + return; + } + + $(window).on('dialog:aftercreate', function (event, dialog, $element, settings) { var moveCounter = function moveCounter($selectedCount, $buttonPane) { var $moveSelectedCount = $selectedCount.detach(); $buttonPane.prepend($moveSelectedCount); diff --git a/core/themes/claro/js/nav-tabs.es6.js b/core/themes/claro/js/nav-tabs.es6.js index d0ae77abda8..1601e788b68 100644 --- a/core/themes/claro/js/nav-tabs.es6.js +++ b/core/themes/claro/js/nav-tabs.es6.js @@ -6,7 +6,7 @@ * added to the main element, and a target element is included. */ (($, Drupal) => { - function init(i, tab) { + function init(tab) { const $tab = $(tab); const $target = $tab.find('[data-drupal-nav-tabs-target]'); const $active = $target.find('.js-active-tab'); @@ -69,6 +69,7 @@ $tab.on('click.tabs', '[data-drupal-nav-tabs-trigger]', openMenu); $(window) + // @todo use a media query event listener https://www.drupal.org/project/drupal/issues/3225621 .on('resize.tabs', Drupal.debounce(toggleCollapsed, 150)) .trigger('resize.tabs'); } @@ -77,12 +78,11 @@ */ Drupal.behaviors.navTabs = { attach(context) { - $(context) - .find('[data-drupal-nav-tabs].is-collapsible') - .once('nav-tabs') - .each((i, value) => { - $(value).each(init); - }); + once( + 'nav-tabs', + '[data-drupal-nav-tabs].is-collapsible', + context, + ).forEach(init); }, }; })(jQuery, Drupal); diff --git a/core/themes/claro/js/nav-tabs.js b/core/themes/claro/js/nav-tabs.js index 232e53449f8..92e46558326 100644 --- a/core/themes/claro/js/nav-tabs.js +++ b/core/themes/claro/js/nav-tabs.js @@ -6,7 +6,7 @@ **/ (function ($, Drupal) { - function init(i, tab) { + function init(tab) { var $tab = $(tab); var $target = $tab.find('[data-drupal-nav-tabs-target]'); var $active = $target.find('.js-active-tab'); @@ -66,9 +66,7 @@ Drupal.behaviors.navTabs = { attach: function attach(context) { - $(context).find('[data-drupal-nav-tabs].is-collapsible').once('nav-tabs').each(function (i, value) { - $(value).each(init); - }); + once('nav-tabs', '[data-drupal-nav-tabs].is-collapsible', context).forEach(init); } }; })(jQuery, Drupal);
\ No newline at end of file diff --git a/core/themes/claro/js/responsive-details.es6.js b/core/themes/claro/js/responsive-details.es6.js index 0543b747ad6..6daf4f235a6 100644 --- a/core/themes/claro/js/responsive-details.es6.js +++ b/core/themes/claro/js/responsive-details.es6.js @@ -14,12 +14,13 @@ */ Drupal.behaviors.responsiveDetails = { attach(context) { - const $details = $(context).find('details').once('responsive-details'); + const details = once('responsive-details', 'details', context); - if (!$details.length) { + if (!details.length) { return; } + const $details = $(details); const $summaries = $details.find('> summary'); function detailsToggle(matches) { diff --git a/core/themes/claro/js/responsive-details.js b/core/themes/claro/js/responsive-details.js index 2e65d2eb1cd..ec59b2afac2 100644 --- a/core/themes/claro/js/responsive-details.js +++ b/core/themes/claro/js/responsive-details.js @@ -8,12 +8,13 @@ (function ($, Drupal) { Drupal.behaviors.responsiveDetails = { attach: function attach(context) { - var $details = $(context).find('details').once('responsive-details'); + var details = once('responsive-details', 'details', context); - if (!$details.length) { + if (!details.length) { return; } + var $details = $(details); var $summaries = $details.find('> summary'); function detailsToggle(matches) { diff --git a/core/themes/claro/js/tabledrag.es6.js b/core/themes/claro/js/tabledrag.es6.js index 529dfe32ff1..b6a9d331116 100644 --- a/core/themes/claro/js/tabledrag.es6.js +++ b/core/themes/claro/js/tabledrag.es6.js @@ -73,7 +73,7 @@ * * @todo this may be removable as part of https://drupal.org/node/3083044 */ - const createItemWrapBoundaries = (index, row) => { + const createItemWrapBoundaries = (row) => { const $row = $(row); const $firstCell = $row .find('td:first-of-type') @@ -99,11 +99,12 @@ // Find each row in a draggable table and process it with // createItemWrapBoundaries(). Object.keys(settings.tableDrag || {}).forEach((base) => { - $(context) - .find(`#${base}`) - .find('> tr.draggable, > tbody > tr.draggable') - .once('claroTabledrag') - .each(createItemWrapBoundaries); + once( + 'claroTabledrag', + $(context) + .find(`#${base}`) + .find('> tr.draggable, > tbody > tr.draggable'), + ).forEach(createItemWrapBoundaries); }); }, }; diff --git a/core/themes/claro/js/tabledrag.js b/core/themes/claro/js/tabledrag.js index ac7c8cc979e..3beafe0c779 100644 --- a/core/themes/claro/js/tabledrag.js +++ b/core/themes/claro/js/tabledrag.js @@ -8,7 +8,7 @@ (function ($, Drupal) { Drupal.behaviors.claroTableDrag = { attach: function attach(context, settings) { - var createItemWrapBoundaries = function createItemWrapBoundaries(index, row) { + var createItemWrapBoundaries = function createItemWrapBoundaries(row) { var $row = $(row); var $firstCell = $row.find('td:first-of-type').eq(0).wrapInner(Drupal.theme('tableDragCellContentWrapper')).wrapInner($(Drupal.theme('tableDragCellItemsWrapper')).addClass('js-tabledrag-cell-content')); var $targetElem = $firstCell.find('.js-tabledrag-cell-content'); @@ -16,7 +16,7 @@ }; Object.keys(settings.tableDrag || {}).forEach(function (base) { - $(context).find("#".concat(base)).find('> tr.draggable, > tbody > tr.draggable').once('claroTabledrag').each(createItemWrapBoundaries); + once('claroTabledrag', $(context).find("#".concat(base)).find('> tr.draggable, > tbody > tr.draggable')).forEach(createItemWrapBoundaries); }); } }; diff --git a/core/themes/claro/js/vertical-tabs.es6.js b/core/themes/claro/js/vertical-tabs.es6.js index cb424fce5b4..32e7591780d 100644 --- a/core/themes/claro/js/vertical-tabs.es6.js +++ b/core/themes/claro/js/vertical-tabs.es6.js @@ -96,18 +96,14 @@ /** * Binds a listener to handle fragment link clicks and URL hash changes. */ - $('body') - .once('vertical-tabs-fragments') - .on( - 'formFragmentLinkClickOrHashChange.verticalTabs', - handleFragmentLinkClickOrHashChange, - ); + $(once('vertical-tabs-fragments', 'body')).on( + 'formFragmentLinkClickOrHashChange.verticalTabs', + handleFragmentLinkClickOrHashChange, + ); - $(context) - .find('[data-vertical-tabs-panes]') - .once('vertical-tabs') - .each(function initializeVerticalTabs() { - const $this = $(this).addClass('vertical-tabs__items--processed'); + once('vertical-tabs', '[data-vertical-tabs-panes]', context).forEach( + (panes) => { + const $this = $(panes).addClass('vertical-tabs__items--processed'); const focusID = $this.find(':hidden.vertical-tabs__active-tab').val(); let tabFocus; @@ -164,7 +160,8 @@ if (tabFocus.length) { tabFocus.data('verticalTab').focus(false); } - }); + }, + ); }, }; diff --git a/core/themes/claro/js/vertical-tabs.js b/core/themes/claro/js/vertical-tabs.js index 8618af2d1ee..16f9cdc4d32 100644 --- a/core/themes/claro/js/vertical-tabs.js +++ b/core/themes/claro/js/vertical-tabs.js @@ -14,9 +14,9 @@ Drupal.behaviors.claroVerticalTabs = { attach: function attach(context) { - $('body').once('vertical-tabs-fragments').on('formFragmentLinkClickOrHashChange.verticalTabs', handleFragmentLinkClickOrHashChange); - $(context).find('[data-vertical-tabs-panes]').once('vertical-tabs').each(function initializeVerticalTabs() { - var $this = $(this).addClass('vertical-tabs__items--processed'); + $(once('vertical-tabs-fragments', 'body')).on('formFragmentLinkClickOrHashChange.verticalTabs', handleFragmentLinkClickOrHashChange); + once('vertical-tabs', '[data-vertical-tabs-panes]', context).forEach(function (panes) { + var $this = $(panes).addClass('vertical-tabs__items--processed'); var focusID = $this.find(':hidden.vertical-tabs__active-tab').val(); var tabFocus; var $details = $this.find('> details'); diff --git a/core/themes/seven/js/nav-tabs.es6.js b/core/themes/seven/js/nav-tabs.es6.js index 27817c5a8ec..7393f35f2a9 100644 --- a/core/themes/seven/js/nav-tabs.es6.js +++ b/core/themes/seven/js/nav-tabs.es6.js @@ -6,7 +6,7 @@ * added to the main element, and a target element is included. */ (function ($, Drupal) { - function init(i, tab) { + function init(tab) { const $tab = $(tab); const $target = $tab.find('[data-drupal-nav-tabs-target]'); const isCollapsible = $tab.hasClass('is-collapsible'); @@ -42,12 +42,9 @@ */ Drupal.behaviors.navTabs = { attach(context, settings) { - const $tabs = $(context).find('[data-drupal-nav-tabs]'); - if ($tabs.length) { - const notSmartPhone = window.matchMedia('(min-width: 300px)'); - if (notSmartPhone.matches) { - $tabs.once('nav-tabs').each(init); - } + const notSmartPhone = window.matchMedia('(min-width: 300px)'); + if (notSmartPhone.matches) { + once('nav-tabs', '[data-drupal-nav-tabs]', context).forEach(init); } }, }; diff --git a/core/themes/seven/js/nav-tabs.js b/core/themes/seven/js/nav-tabs.js index 84a6939f948..029a4be8198 100644 --- a/core/themes/seven/js/nav-tabs.js +++ b/core/themes/seven/js/nav-tabs.js @@ -6,7 +6,7 @@ **/ (function ($, Drupal) { - function init(i, tab) { + function init(tab) { var $tab = $(tab); var $target = $tab.find('[data-drupal-nav-tabs-target]'); var isCollapsible = $tab.hasClass('is-collapsible'); @@ -37,14 +37,10 @@ Drupal.behaviors.navTabs = { attach: function attach(context, settings) { - var $tabs = $(context).find('[data-drupal-nav-tabs]'); + var notSmartPhone = window.matchMedia('(min-width: 300px)'); - if ($tabs.length) { - var notSmartPhone = window.matchMedia('(min-width: 300px)'); - - if (notSmartPhone.matches) { - $tabs.once('nav-tabs').each(init); - } + if (notSmartPhone.matches) { + once('nav-tabs', '[data-drupal-nav-tabs]', context).forEach(init); } } }; diff --git a/core/themes/seven/js/responsive-details.es6.js b/core/themes/seven/js/responsive-details.es6.js index f0535344f96..38140fb86bd 100644 --- a/core/themes/seven/js/responsive-details.es6.js +++ b/core/themes/seven/js/responsive-details.es6.js @@ -14,12 +14,13 @@ */ Drupal.behaviors.responsiveDetails = { attach(context) { - const $details = $(context).find('details').once('responsive-details'); + const details = once('responsive-details', 'details', context); - if (!$details.length) { + if (!details.length) { return; } + const $details = $(details); const $summaries = $details.find('> summary'); function detailsToggle(matches) { diff --git a/core/themes/seven/js/responsive-details.js b/core/themes/seven/js/responsive-details.js index 2e65d2eb1cd..ec59b2afac2 100644 --- a/core/themes/seven/js/responsive-details.js +++ b/core/themes/seven/js/responsive-details.js @@ -8,12 +8,13 @@ (function ($, Drupal) { Drupal.behaviors.responsiveDetails = { attach: function attach(context) { - var $details = $(context).find('details').once('responsive-details'); + var details = once('responsive-details', 'details', context); - if (!$details.length) { + if (!details.length) { return; } + var $details = $(details); var $summaries = $details.find('> summary'); function detailsToggle(matches) { diff --git a/core/themes/seven/seven.libraries.yml b/core/themes/seven/seven.libraries.yml index 060c0002960..a4a687e3fd0 100644 --- a/core/themes/seven/seven.libraries.yml +++ b/core/themes/seven/seven.libraries.yml @@ -106,7 +106,7 @@ drupal.nav-tabs: dependencies: - core/jquery - core/drupal - - core/jquery.once + - core/once - core/drupal.debounce - core/collapse @@ -116,7 +116,7 @@ drupal.responsive-detail: js/responsive-details.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/collapse vertical-tabs: |