Issue #3390549 by finnsky, nod_, smustgrave, larowlan, catch, bnjmnm: Get rid of jQuery in dialog events

(cherry picked from commit 99af345889)
merge-requests/7375/merge
Dave Long 2024-05-01 16:39:19 +01:00
parent ed377f9af3
commit 66faba3a71
No known key found for this signature in database
GPG Key ID: ED52AE211E142771
13 changed files with 221 additions and 142 deletions

View File

@ -549,6 +549,7 @@ drupal.debounce:
drupal.dialog: drupal.dialog:
version: VERSION version: VERSION
js: js:
misc/dialog/dialog-deprecation.js: {}
misc/dialog/dialog.js: {} misc/dialog/dialog.js: {}
misc/dialog/dialog.position.js: {} misc/dialog/dialog.position.js: {}
misc/dialog/dialog.jquery-ui.js: {} misc/dialog/dialog.jquery-ui.js: {}
@ -582,6 +583,7 @@ drupal.dialog:
- core/drupal.debounce - core/drupal.debounce
- core/drupal.displace - core/drupal.displace
- core/tabbable.jquery.shim - core/tabbable.jquery.shim
- core/once
- core/drupal.jquery.position - core/drupal.jquery.position
drupal.dialog.ajax: drupal.dialog.ajax:

View File

@ -0,0 +1,40 @@
/**
* @file
* Maintains and deprecates Dialog jQuery events.
*/
(function ($, Drupal, once) {
if (once('drupal-dialog-deprecation-listener', 'html').length) {
const eventSpecial = {
handle($event) {
const $element = $($event.target);
const event = $event.originalEvent;
const dialog = event.dialog;
const dialogArguments = [$event, dialog, $element, event?.settings];
$event.handleObj.handler.apply(this, dialogArguments);
},
};
$.event.special['dialog:beforecreate'] = eventSpecial;
$.event.special['dialog:aftercreate'] = eventSpecial;
$.event.special['dialog:beforeclose'] = eventSpecial;
$.event.special['dialog:afterclose'] = eventSpecial;
const listenDialogEvent = (event) => {
const windowEvents = $._data(window, 'events');
const isWindowHasDialogListener = windowEvents[event.type];
if (isWindowHasDialogListener) {
Drupal.deprecationError({
message: `jQuery event ${event.type} is deprecated in 10.3.0 and is removed from Drupal:12.0.0. See https://www.drupal.org/node/3422670`,
});
}
};
[
'dialog:beforecreate',
'dialog:aftercreate',
'dialog:beforeclose',
'dialog:afterclose',
].forEach((e) => window.addEventListener(e, listenDialogEvent));
}
})(jQuery, Drupal, once);

View File

@ -270,7 +270,9 @@
* @param {object} [settings] * @param {object} [settings]
* Dialog settings. * Dialog settings.
*/ */
$(window).on('dialog:aftercreate', (e, dialog, $element, settings) => { window.addEventListener('dialog:aftercreate', (event) => {
const $element = $(event.target);
const dialog = event.dialog;
$element.on('click.dialog', '.dialog-cancel', (e) => { $element.on('click.dialog', '.dialog-cancel', (e) => {
dialog.close('cancel'); dialog.close('cancel');
e.preventDefault(); e.preventDefault();
@ -288,7 +290,8 @@
* @param {jQuery} $element * @param {jQuery} $element
* jQuery collection of the dialog element. * jQuery collection of the dialog element.
*/ */
$(window).on('dialog:beforeclose', (e, dialog, $element) => { window.addEventListener('dialog:beforeclose', (e) => {
const $element = $(e.target);
$element.off('.dialog'); $element.off('.dialog');
}); });

View File

@ -5,6 +5,14 @@
* @see http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#the-dialog-element * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#the-dialog-element
*/ */
class DrupalDialogEvent extends Event {
constructor(type, dialog, settings = null) {
super(`dialog:${type}`, { bubbles: true });
this.dialog = dialog;
this.settings = settings;
}
}
(function ($, Drupal, drupalSettings, bodyScrollLock) { (function ($, Drupal, drupalSettings, bodyScrollLock) {
/** /**
* Default dialog options. * Default dialog options.
@ -61,7 +69,10 @@
*/ */
Drupal.dialog = function (element, options) { Drupal.dialog = function (element, options) {
let undef; let undef;
const $element = $(element); const $element = $(element);
const domElement = $element.get(0);
const dialog = { const dialog = {
open: false, open: false,
returnValue: undef, returnValue: undef,
@ -70,28 +81,33 @@
function openDialog(settings) { function openDialog(settings) {
settings = $.extend({}, drupalSettings.dialog, options, settings); settings = $.extend({}, drupalSettings.dialog, options, settings);
// Trigger a global event to allow scripts to bind events to the dialog. // Trigger a global event to allow scripts to bind events to the dialog.
$(window).trigger('dialog:beforecreate', [dialog, $element, settings]); const event = new DrupalDialogEvent('beforecreate', dialog, settings);
$element.dialog(settings); domElement.dispatchEvent(event);
$element.dialog(event.settings);
dialog.open = true; dialog.open = true;
// Locks the body scroll only when it opens in modal. // Locks the body scroll only when it opens in modal.
if (settings.modal) { if (settings.modal) {
// Locks the body when the dialog opens. // Locks the body when the dialog opens.
bodyScrollLock.lock($element.get(0)); bodyScrollLock.lock(domElement);
} }
$(window).trigger('dialog:aftercreate', [dialog, $element, settings]); domElement.dispatchEvent(
new DrupalDialogEvent('aftercreate', dialog, settings),
);
} }
function closeDialog(value) { function closeDialog(value) {
$(window).trigger('dialog:beforeclose', [dialog, $element]); domElement.dispatchEvent(new DrupalDialogEvent('beforeclose', dialog));
// Unlocks the body when the dialog closes. // Unlocks the body when the dialog closes.
bodyScrollLock.clearBodyLocks(); bodyScrollLock.clearBodyLocks();
$element.dialog('close'); $element.dialog('close');
dialog.returnValue = value; dialog.returnValue = value;
dialog.open = false; dialog.open = false;
$(window).trigger('dialog:afterclose', [dialog, $element]);
domElement.dispatchEvent(new DrupalDialogEvent('afterclose', dialog));
} }
dialog.show = () => { dialog.show = () => {

View File

@ -113,28 +113,30 @@
.trigger('dialogContentResize'); .trigger('dialogContentResize');
} }
$(window).on({ window.addEventListener('dialog:aftercreate', (e) => {
'dialog:aftercreate': function (event, dialog, $element, settings) { const autoResize = debounce(resetSize, 20);
const autoResize = debounce(resetSize, 20); const $element = $(e.target);
const eventData = { settings, $element }; const { settings } = e;
if (settings.autoResize === true || settings.autoResize === 'true') { const eventData = { settings, $element };
const uiDialog = $element
.dialog('option', { resizable: false, draggable: false }) if (settings.autoResize === true || settings.autoResize === 'true') {
.dialog('widget'); const uiDialog = $element
uiDialog[0].style.position = 'fixed'; .dialog('option', { resizable: false, draggable: false })
$(window) .dialog('widget');
.on('resize.dialogResize scroll.dialogResize', eventData, autoResize) uiDialog[0].style.position = 'fixed';
.trigger('resize.dialogResize'); $(window)
$(document).on( .on('resize.dialogResize scroll.dialogResize', eventData, autoResize)
'drupalViewportOffsetChange.dialogResize', .trigger('resize.dialogResize');
eventData, $(document).on(
autoResize, 'drupalViewportOffsetChange.dialogResize',
); eventData,
} autoResize,
}, );
'dialog:beforeclose': function (event, dialog, $element) { }
$(window).off('.dialogResize'); });
$(document).off('.dialogResize');
}, window.addEventListener('dialog:beforeclose', () => {
$(window).off('.dialogResize');
$(document).off('.dialogResize');
}); });
})(jQuery, Drupal, drupalSettings, Drupal.debounce, Drupal.displace); })(jQuery, Drupal, drupalSettings, Drupal.debounce, Drupal.displace);

View File

@ -341,23 +341,39 @@
if (!once('off-canvas', 'html').length) { if (!once('off-canvas', 'html').length) {
return; return;
} }
$(window).on({
'dialog:beforecreate': (event, dialog, $element, settings) => { window.addEventListener('dialog:beforecreate', (e) => {
if (Drupal.offCanvas.isOffCanvas($element)) { const $element = $(e.target);
Drupal.offCanvas.beforeCreate({ dialog, $element, settings }); if (Drupal.offCanvas.isOffCanvas($element)) {
} Drupal.offCanvas.beforeCreate({
}, $element,
'dialog:aftercreate': (event, dialog, $element, settings) => { settings: e.settings,
if (Drupal.offCanvas.isOffCanvas($element)) { });
Drupal.offCanvas.render({ dialog, $element, settings }); }
Drupal.offCanvas.afterCreate({ $element, settings }); });
}
}, window.addEventListener('dialog:aftercreate', (e) => {
'dialog:beforeclose': (event, dialog, $element) => { const $element = $(e.target);
if (Drupal.offCanvas.isOffCanvas($element)) { if (Drupal.offCanvas.isOffCanvas($element)) {
Drupal.offCanvas.beforeClose({ dialog, $element }); Drupal.offCanvas.render({
} $element,
}, dialog: e.dialog,
settings: e.settings,
});
Drupal.offCanvas.afterCreate({
$element,
settings: e.settings,
});
}
});
window.addEventListener('dialog:beforeclose', (e) => {
const $element = $(e.target);
if (Drupal.offCanvas.isOffCanvas($element)) {
Drupal.offCanvas.beforeClose({
$element,
});
}
}); });
}, },
}; };

View File

@ -650,7 +650,7 @@
); );
// Respond to new dialogs that are opened by CKEditor, closing the AJAX loader. // Respond to new dialogs that are opened by CKEditor, closing the AJAX loader.
$(window).on('dialog:beforecreate', () => { window.addEventListener('dialog:beforecreate', () => {
const dialogLoading = document.querySelector('.ckeditor5-dialog-loading'); const dialogLoading = document.querySelector('.ckeditor5-dialog-loading');
if (dialogLoading) { if (dialogLoading) {
@ -673,7 +673,7 @@
}); });
// Respond to dialogs that are closed, removing the current save handler. // Respond to dialogs that are closed, removing the current save handler.
$(window).on('dialog:afterclose', () => { window.addEventListener('dialog:afterclose', () => {
if (Drupal.ckeditor5.saveCallback) { if (Drupal.ckeditor5.saveCallback) {
Drupal.ckeditor5.saveCallback = null; Drupal.ckeditor5.saveCallback = null;
} }

View File

@ -219,7 +219,8 @@
}; };
// After a dialog opens, highlight element that the dialog is acting on. // After a dialog opens, highlight element that the dialog is acting on.
$(window).on('dialog:aftercreate', (event, dialog, $element) => { window.addEventListener('dialog:aftercreate', (e) => {
const $element = $(e.target);
if (Drupal.offCanvas.isOffCanvas($element)) { if (Drupal.offCanvas.isOffCanvas($element)) {
// Start by removing any existing highlighted elements. // Start by removing any existing highlighted elements.
$('.is-layout-builder-highlighted').removeClass( $('.is-layout-builder-highlighted').removeClass(
@ -309,7 +310,8 @@
}); });
} }
$(window).on('dialog:afterclose', (event, dialog, $element) => { window.addEventListener('dialog:afterclose', (e) => {
const $element = $(e.target);
if (Drupal.offCanvas.isOffCanvas($element)) { if (Drupal.offCanvas.isOffCanvas($element)) {
// Remove the highlight from all elements. // Remove the highlight from all elements.
$('.is-layout-builder-highlighted').removeClass( $('.is-layout-builder-highlighted').removeClass(

View File

@ -382,7 +382,7 @@
if (!once('media-library-selection-info', 'html').length) { if (!once('media-library-selection-info', 'html').length) {
return; return;
} }
$(window).on('dialog:aftercreate', () => { window.addEventListener('dialog:aftercreate', () => {
// Since the dialog HTML is not part of the context, we can't use // Since the dialog HTML is not part of the context, we can't use
// context here. // context here.
const $buttonPane = $( const $buttonPane = $(
@ -410,7 +410,7 @@
if (!once('media-library-clear-selection', 'html').length) { if (!once('media-library-clear-selection', 'html').length) {
return; return;
} }
$(window).on('dialog:afterclose', () => { window.addEventListener('dialog:afterclose', () => {
Drupal.MediaLibrary.currentSelection = []; Drupal.MediaLibrary.currentSelection = [];
}); });
}, },

View File

@ -237,24 +237,22 @@
}; };
// Manage Active editable class on opening and closing of the dialog. // Manage Active editable class on opening and closing of the dialog.
$(window).on({ window.addEventListener('dialog:beforecreate', (e) => {
'dialog:beforecreate': (event, dialog, $element, settings) => { if (e.target.id === 'drupal-off-canvas') {
if ($element[0].id === 'drupal-off-canvas') { $('body .settings-tray-active-editable').removeClass(
$('body .settings-tray-active-editable').removeClass( 'settings-tray-active-editable',
'settings-tray-active-editable', );
); const $activeElement = $(`#${e.settings.settingsTrayActiveEditableId}`);
const $activeElement = $(`#${settings.settingsTrayActiveEditableId}`); if ($activeElement.length) {
if ($activeElement.length) { $activeElement.addClass('settings-tray-active-editable');
$activeElement.addClass('settings-tray-active-editable');
}
} }
}, }
'dialog:beforeclose': (event, dialog, $element) => { });
if ($element[0].id === 'drupal-off-canvas') { window.addEventListener('dialog:beforeclose', (e) => {
$('body .settings-tray-active-editable').removeClass( if (e.target.id === 'drupal-off-canvas') {
'settings-tray-active-editable', $('body .settings-tray-active-editable').removeClass(
); 'settings-tray-active-editable',
} );
}, }
}); });
})(jQuery, Drupal); })(jQuery, Drupal);

View File

@ -205,34 +205,35 @@
}); });
} }
$(window).on({ window.addEventListener('dialog:aftercreate', (e) => {
'dialog:aftercreate': (event, dialog, $element, settings) => { const $element = $(e.target);
const toolbarBar = document.getElementById('toolbar-bar'); const { settings } = e;
if (toolbarBar) { const toolbarBar = document.getElementById('toolbar-bar');
toolbarBar.style.marginTop = '0'; if (toolbarBar) {
toolbarBar.style.marginTop = '0';
// When off-canvas is positioned in top, toolbar has to be moved down. // When off-canvas is positioned in top, toolbar has to be moved down.
if (settings.drupalOffCanvasPosition === 'top') { if (settings.drupalOffCanvasPosition === 'top') {
const height = Drupal.offCanvas const height = Drupal.offCanvas
.getContainer($element)
.outerHeight();
toolbarBar.style.marginTop = `${height}px`;
$element.on('dialogContentResize.off-canvas', () => {
const newHeight = Drupal.offCanvas
.getContainer($element) .getContainer($element)
.outerHeight(); .outerHeight();
toolbarBar.style.marginTop = `${height}px`; toolbarBar.style.marginTop = `${newHeight}px`;
});
}
}
});
$element.on('dialogContentResize.off-canvas', () => { window.addEventListener('dialog:beforeclose', () => {
const newHeight = Drupal.offCanvas const toolbarBar = document.getElementById('toolbar-bar');
.getContainer($element) if (toolbarBar) {
.outerHeight(); toolbarBar.style.marginTop = '0';
toolbarBar.style.marginTop = `${newHeight}px`; }
});
}
}
},
'dialog:beforeclose': () => {
const toolbarBar = document.getElementById('toolbar-bar');
if (toolbarBar) {
toolbarBar.style.marginTop = '0';
}
},
}); });
}); });

View File

@ -81,7 +81,8 @@
* @param {jQuery} $element * @param {jQuery} $element
* The jQuery collection of the dialog element. * The jQuery collection of the dialog element.
*/ */
$(window).on('dialog:aftercreate', (e, dialog, $element) => { window.addEventListener('dialog:aftercreate', (e) => {
const $element = $(e.target);
const $scroll = $element.find('.scroll'); const $scroll = $element.find('.scroll');
if ($scroll.length) { if ($scroll.length) {
bodyScrollLock.unlock($element.get(0)); bodyScrollLock.unlock($element.get(0));

View File

@ -20,53 +20,51 @@
if (!once('media-library-selection-info-claro-event', 'html').length) { if (!once('media-library-selection-info-claro-event', 'html').length) {
return; return;
} }
$(window).on( window.addEventListener('dialog:aftercreate', (e) => {
'dialog:aftercreate', const $element = $(e.target);
(event, dialog, $element, settings) => { // Since the dialog HTML is not part of the context, we can't use
// Since the dialog HTML is not part of the context, we can't use // context here.
// context here. const moveCounter = ($selectedCount, $buttonPane) => {
const moveCounter = ($selectedCount, $buttonPane) => { const $moveSelectedCount = $selectedCount.detach();
const $moveSelectedCount = $selectedCount.detach(); $buttonPane.prepend($moveSelectedCount);
$buttonPane.prepend($moveSelectedCount); };
};
const $buttonPane = $element const $buttonPane = $element
.closest('.media-library-widget-modal') .closest('.media-library-widget-modal')
.find('.ui-dialog-buttonpane'); .find('.ui-dialog-buttonpane');
if (!$buttonPane.length) { if (!$buttonPane.length) {
return; return;
} }
const $selectedCount = $buttonPane.find( const $selectedCount = $buttonPane.find(
'.js-media-library-selected-count', '.js-media-library-selected-count',
); );
// If the `selected` counter is already present, it can be moved from // If the `selected` counter is already present, it can be moved from
// the end of the button pane to the beginning. // the end of the button pane to the beginning.
if ($selectedCount.length) { if ($selectedCount.length) {
moveCounter($selectedCount, $buttonPane); moveCounter($selectedCount, $buttonPane);
} else { } else {
// If the `selected` counter is not yet present, create a mutation // If the `selected` counter is not yet present, create a mutation
// observer that checks for items added to the button pane. As soon // observer that checks for items added to the button pane. As soon
// as the counter is added, move it from the end of the button pane // as the counter is added, move it from the end of the button pane
// to the beginning. // to the beginning.
const selectedCountObserver = new MutationObserver(() => { const selectedCountObserver = new MutationObserver(() => {
const $selectedCountFind = $buttonPane.find( const $selectedCountFind = $buttonPane.find(
'.js-media-library-selected-count', '.js-media-library-selected-count',
); );
if ($selectedCountFind.length) { if ($selectedCountFind.length) {
moveCounter($selectedCountFind, $buttonPane); moveCounter($selectedCountFind, $buttonPane);
selectedCountObserver.disconnect(); selectedCountObserver.disconnect();
} }
}); });
selectedCountObserver.observe($buttonPane[0], { selectedCountObserver.observe($buttonPane[0], {
attributes: false, attributes: false,
childList: true, childList: true,
characterData: false, characterData: false,
subtree: true, subtree: true,
}); });
} }
}, });
);
}, },
}; };
})(jQuery, Drupal, window); })(jQuery, Drupal, window);