Newer
Older
Alex Pott
committed
/**
* @file
* Drupal's Settings Tray library.
*
* @private
Alex Pott
committed
*/
(function ($, Drupal) {
Angie Byron
committed
const blockConfigureSelector = '[data-settings-tray-edit]';
const toggleEditSelector = '[data-drupal-settingstray="toggle"]';
const itemsToToggleSelector = '[data-off-canvas-main-canvas], #toolbar-bar, [data-drupal-settingstray="editable"] a, [data-drupal-settingstray="editable"] button';
const contextualItemsSelector = '[data-contextual-id] a, [data-contextual-id] button';
const quickEditItemSelector = '[data-quickedit-entity-id]';
Alex Pott
committed
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/**
* Prevent default click events except contextual links.
*
* In edit mode the default action of click events is suppressed.
*
* @param {jQuery.Event} event
* The click event.
*/
function preventClick(event) {
// Do not prevent contextual links.
if ($(event.target).closest('.contextual-links').length) {
return;
}
event.preventDefault();
}
/**
* Close any active toolbar tray before entering edit mode.
*/
function closeToolbarTrays() {
$(Drupal.toolbar.models.toolbarModel.get('activeTab')).trigger('click');
}
/**
* Disables the QuickEdit module editor if open.
*/
function disableQuickEdit() {
$('.quickedit-toolbar button.action-cancel').trigger('click');
}
/**
* Closes/removes off-canvas.
*/
function closeOffCanvas() {
$('.ui-dialog-off-canvas .ui-dialog-titlebar-close').trigger('click');
}
/**
* Gets all items that should be toggled with class during edit mode.
*
* @return {jQuery}
* Items that should be toggled.
*/
function getItemsToToggle() {
return $(itemsToToggleSelector).not(contextualItemsSelector);
}
/**
* Helper to switch edit mode state.
Alex Pott
committed
*
* @param {boolean} editMode
* True enable edit mode, false disable edit mode.
Alex Pott
committed
*/
function setEditModeState(editMode) {
if (!document.querySelector('[data-off-canvas-main-canvas]')) {
Angie Byron
committed
throw new Error('data-off-canvas-main-canvas is missing from settings-tray-page-wrapper.html.twig');
Alex Pott
committed
}
editMode = !!editMode;
const $editButton = $(toggleEditSelector);
let $editables;
Alex Pott
committed
// Turn on edit mode.
if (editMode) {
$editButton.text(Drupal.t('Editing'));
closeToolbarTrays();
Angie Byron
committed
$editables = $('[data-drupal-settingstray="editable"]').once('settingstray');
Alex Pott
committed
if ($editables.length) {
// Use event capture to prevent clicks on links.
document.querySelector('[data-off-canvas-main-canvas]').addEventListener('click', preventClick, true);
Angie Byron
committed
// When a click occurs try and find the settings-tray edit link
Alex Pott
committed
// and click it.
$editables
.not(contextualItemsSelector)
Angie Byron
committed
.on('click.settingstray', (e) => {
Alex Pott
committed
// Contextual links are allowed to function in Edit mode.
if ($(e.target).closest('.contextual').length || !localStorage.getItem('Drupal.contextualToolbar.isViewing')) {
return;
}
$(e.currentTarget).find(blockConfigureSelector).trigger('click');
disableQuickEdit();
});
$(quickEditItemSelector)
.not(contextualItemsSelector)
Angie Byron
committed
.on('click.settingstray', (e) => {
/**
* For all non-contextual links or the contextual QuickEdit link
* close the off-canvas dialog.
*/
Alex Pott
committed
if (!$(e.target).parent().hasClass('contextual') || $(e.target).parent().hasClass('quickedit')) {
closeOffCanvas();
}
// Do not trigger if target is quick edit link to avoid loop.
if ($(e.target).parent().hasClass('contextual') || $(e.target).parent().hasClass('quickedit')) {
return;
}
$(e.currentTarget).find('li.quickedit a').trigger('click');
});
}
}
// Disable edit mode.
else {
Angie Byron
committed
$editables = $('[data-drupal-settingstray="editable"]').removeOnce('settingstray');
Alex Pott
committed
if ($editables.length) {
document.querySelector('[data-off-canvas-main-canvas]').removeEventListener('click', preventClick, true);
Angie Byron
committed
$editables.off('.settingstray');
$(quickEditItemSelector).off('.settingstray');
Alex Pott
committed
}
$editButton.text(Drupal.t('Edit'));
closeOffCanvas();
disableQuickEdit();
}
Angie Byron
committed
getItemsToToggle().toggleClass('js-settings-tray-edit-mode', editMode);
Alex Pott
committed
$('.edit-mode-inactive').toggleClass('visually-hidden', editMode);
}
/**
Angie Byron
committed
* Helper to check the state of the settings-tray mode.
*
* @todo don't use a class for this.
*
* @return {boolean}
Angie Byron
committed
* State of the settings-tray edit mode.
*/
function isInEditMode() {
Angie Byron
committed
return $('#toolbar-bar').hasClass('js-settings-tray-edit-mode');
}
/**
* Helper to toggle Edit mode.
*/
function toggleEditMode() {
setEditModeState(!isInEditMode());
}
Angie Byron
committed
/**
* Prepares Ajax links to work with off-canvas and Settings Tray module.
*/
function prepareAjaxLinks() {
// Find all Ajax instances that use the 'off_canvas' renderer.
Drupal.ajax.instances
// If there is an element and the renderer is 'off_canvas' then we want
// to add our changes.
.filter(instance => instance && $(instance.element).attr('data-dialog-renderer') === 'off_canvas')
// Loop through all Ajax instances that use the 'off_canvas' renderer to
// set active editable ID.
.forEach((instance) => {
// Check to make sure existing dialogOptions aren't overridden.
if (!('dialogOptions' in instance.options.data)) {
instance.options.data.dialogOptions = {};
}
instance.options.data.dialogOptions.settingsTrayActiveEditableId = $(instance.element).parents('.settings-tray-editable').attr('id');
instance.progress = { type: 'fullscreen' };
});
}
/**
* Reacts to contextual links being added.
*
* @param {jQuery.Event} event
* The `drupalContextualLinkAdded` event.
* @param {object} data
* An object containing the data relevant to the event.
*
* @listens event:drupalContextualLinkAdded
*/
$(document).on('drupalContextualLinkAdded', (event, data) => {
Angie Byron
committed
/**
* When contextual links are add we need to set extra properties on the
* instances in Drupal.ajax.instances for them to work with Edit Mode.
*/
prepareAjaxLinks();
// When the first contextual link is added to the page set Edit Mode.
Angie Byron
committed
$('body').once('settings_tray.edit_mode_init').each(() => {
const editMode = localStorage.getItem('Drupal.contextualToolbar.isViewing') === 'false';
if (editMode) {
setEditModeState(true);
}
});
/**
catch
committed
* Bind a listener to all 'Quick edit' links for blocks. Click "Edit"
* button in toolbar to force Contextual Edit which starts Settings Tray
* edit mode also.
*/
data.$el.find(blockConfigureSelector)
Angie Byron
committed
.on('click.settingstray', () => {
if (!isInEditMode()) {
Angie Byron
committed
$(toggleEditSelector).trigger('click').trigger('click.settings_tray');
}
/**
* Always disable QuickEdit regardless of whether "EditMode" was just
* enabled.
*/
disableQuickEdit();
});
});
Angie Byron
committed
$(document).on('keyup.settingstray', (e) => {
if (isInEditMode() && e.keyCode === 27) {
Drupal.announce(
Drupal.t('Exited edit mode.'),
);
toggleEditMode();
}
});
Alex Pott
committed
/**
catch
committed
* Toggle the js-settings-tray-edit-mode class on items that we want to
* disable while in edit mode.
Alex Pott
committed
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
Angie Byron
committed
* Toggle the js-settings-tray-edit-mode class.
Alex Pott
committed
*/
Drupal.behaviors.toggleEditMode = {
attach() {
Angie Byron
committed
$(toggleEditSelector).once('settingstray').on('click.settingstray', toggleEditMode);
},
Alex Pott
committed
};
// Manage Active editable class on opening and closing of the dialog.
$(window).on({
'dialog:beforecreate': (event, dialog, $element, settings) => {
Alex Pott
committed
if ($element.is('#drupal-off-canvas')) {
Angie Byron
committed
$('body .settings-tray-active-editable').removeClass('settings-tray-active-editable');
const $activeElement = $(`#${settings.settingsTrayActiveEditableId}`);
Alex Pott
committed
if ($activeElement.length) {
Angie Byron
committed
$activeElement.addClass('settings-tray-active-editable');
Alex Pott
committed
}
}
},
'dialog:beforeclose': (event, dialog, $element) => {
Alex Pott
committed
if ($element.is('#drupal-off-canvas')) {
Angie Byron
committed
$('body .settings-tray-active-editable').removeClass('settings-tray-active-editable');
Alex Pott
committed
}
},
Alex Pott
committed
});
}(jQuery, Drupal));