diff options
author | catch <catch@35733.no-reply.drupal.org> | 2022-09-09 07:26:42 +0100 |
---|---|---|
committer | catch <catch@35733.no-reply.drupal.org> | 2022-09-09 07:26:42 +0100 |
commit | 8aa8ce1ffbcca9c727f46e58c714e1d351f7ef88 (patch) | |
tree | 27be6908992c340ba0b4c0bd3f4339670aa71e90 /core/modules/contextual/js | |
parent | 09f8f13d8a72b8e482cc689fcd10f023df41b899 (diff) | |
download | drupal-8aa8ce1ffbcca9c727f46e58c714e1d351f7ef88.tar.gz drupal-8aa8ce1ffbcca9c727f46e58c714e1d351f7ef88.zip |
Issue #3278415 by nod_, lauriii, catch, Wim Leers, longwave, xjm, claudiu.cristea: Remove usages of the JavaScript ES6 build step, the build step itself, and associated dev dependencies
Diffstat (limited to 'core/modules/contextual/js')
20 files changed, 974 insertions, 1570 deletions
diff --git a/core/modules/contextual/js/contextual.es6.js b/core/modules/contextual/js/contextual.es6.js deleted file mode 100644 index b5fe7d094fb..00000000000 --- a/core/modules/contextual/js/contextual.es6.js +++ /dev/null @@ -1,321 +0,0 @@ -/** - * @file - * Attaches behaviors for the Contextual module. - */ - -(function ($, Drupal, drupalSettings, _, Backbone, JSON, storage) { - const options = $.extend( - drupalSettings.contextual, - // Merge strings on top of drupalSettings so that they are not mutable. - { - strings: { - open: Drupal.t('Open'), - close: Drupal.t('Close'), - }, - }, - ); - - // Clear the cached contextual links whenever the current user's set of - // permissions changes. - const cachedPermissionsHash = storage.getItem( - 'Drupal.contextual.permissionsHash', - ); - const permissionsHash = drupalSettings.user.permissionsHash; - if (cachedPermissionsHash !== permissionsHash) { - if (typeof permissionsHash === 'string') { - _.chain(storage) - .keys() - .each((key) => { - if (key.substring(0, 18) === 'Drupal.contextual.') { - storage.removeItem(key); - } - }); - } - storage.setItem('Drupal.contextual.permissionsHash', permissionsHash); - } - - /** - * Determines if a contextual link is nested & overlapping, if so: adjusts it. - * - * This only deals with two levels of nesting; deeper levels are not touched. - * - * @param {jQuery} $contextual - * A contextual links placeholder DOM element, containing the actual - * contextual links as rendered by the server. - */ - function adjustIfNestedAndOverlapping($contextual) { - const $contextuals = $contextual - // @todo confirm that .closest() is not sufficient - .parents('.contextual-region') - .eq(-1) - .find('.contextual'); - - // Early-return when there's no nesting. - if ($contextuals.length <= 1) { - return; - } - - // If the two contextual links overlap, then we move the second one. - const firstTop = $contextuals.eq(0).offset().top; - const secondTop = $contextuals.eq(1).offset().top; - if (firstTop === secondTop) { - const $nestedContextual = $contextuals.eq(1); - - // Retrieve height of nested contextual link. - let height = 0; - const $trigger = $nestedContextual.find('.trigger'); - // Elements with the .visually-hidden class have no dimensions, so this - // class must be temporarily removed to the calculate the height. - $trigger.removeClass('visually-hidden'); - height = $nestedContextual.height(); - $trigger.addClass('visually-hidden'); - - // Adjust nested contextual link's position. - $nestedContextual.css({ top: $nestedContextual.position().top + height }); - } - } - - /** - * Initializes a contextual link: updates its DOM, sets up model and views. - * - * @param {jQuery} $contextual - * A contextual links placeholder DOM element, containing the actual - * contextual links as rendered by the server. - * @param {string} html - * The server-side rendered HTML for this contextual link. - */ - function initContextual($contextual, html) { - const $region = $contextual.closest('.contextual-region'); - const contextual = Drupal.contextual; - - $contextual - // Update the placeholder to contain its rendered contextual links. - .html(html) - // Use the placeholder as a wrapper with a specific class to provide - // positioning and behavior attachment context. - .addClass('contextual') - // Ensure a trigger element exists before the actual contextual links. - .prepend(Drupal.theme('contextualTrigger')); - - // Set the destination parameter on each of the contextual links. - const destination = `destination=${Drupal.encodePath( - Drupal.url(drupalSettings.path.currentPath), - )}`; - $contextual.find('.contextual-links a').each(function () { - const url = this.getAttribute('href'); - const glue = url.indexOf('?') === -1 ? '?' : '&'; - this.setAttribute('href', url + glue + destination); - }); - - let title = ''; - const $regionHeading = $region.find('h2'); - if ($regionHeading.length) { - title = $regionHeading[0].textContent.trim(); - } - // Create a model and the appropriate views. - const model = new contextual.StateModel({ - title, - }); - const viewOptions = $.extend({ el: $contextual, model }, options); - contextual.views.push({ - visual: new contextual.VisualView(viewOptions), - aural: new contextual.AuralView(viewOptions), - keyboard: new contextual.KeyboardView(viewOptions), - }); - contextual.regionViews.push( - new contextual.RegionView($.extend({ el: $region, model }, options)), - ); - - // Add the model to the collection. This must happen after the views have - // been associated with it, otherwise collection change event handlers can't - // trigger the model change event handler in its views. - contextual.collection.add(model); - - // Let other JavaScript react to the adding of a new contextual link. - $(document).trigger( - 'drupalContextualLinkAdded', - Drupal.deprecatedProperty({ - target: { - $el: $contextual, - $region, - model, - }, - deprecatedProperty: 'model', - message: - 'The model property is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no replacement.', - }), - ); - - // Fix visual collisions between contextual link triggers. - adjustIfNestedAndOverlapping($contextual); - } - - /** - * Attaches outline behavior for regions associated with contextual links. - * - * Events - * Contextual triggers an event that can be used by other scripts. - * - drupalContextualLinkAdded: Triggered when a contextual link is added. - * - * @type {Drupal~behavior} - * - * @prop {Drupal~behaviorAttach} attach - * Attaches the outline behavior to the right context. - */ - Drupal.behaviors.contextual = { - attach(context) { - const $context = $(context); - - // Find all contextual links placeholders, if any. - let $placeholders = $( - once('contextual-render', '[data-contextual-id]', context), - ); - if ($placeholders.length === 0) { - return; - } - - // Collect the IDs for all contextual links placeholders. - const ids = []; - $placeholders.each(function () { - ids.push({ - id: $(this).attr('data-contextual-id'), - token: $(this).attr('data-contextual-token'), - }); - }); - - const uncachedIDs = []; - const uncachedTokens = []; - ids.forEach((contextualID) => { - const html = storage.getItem(`Drupal.contextual.${contextualID.id}`); - if (html && html.length) { - // Initialize after the current execution cycle, to make the AJAX - // request for retrieving the uncached contextual links as soon as - // possible, but also to ensure that other Drupal behaviors have had - // the chance to set up an event listener on the Backbone collection - // Drupal.contextual.collection. - window.setTimeout(() => { - initContextual( - $context - .find(`[data-contextual-id="${contextualID.id}"]:empty`) - .eq(0), - html, - ); - }); - return; - } - uncachedIDs.push(contextualID.id); - uncachedTokens.push(contextualID.token); - }); - - // Perform an AJAX request to let the server render the contextual links - // for each of the placeholders. - if (uncachedIDs.length > 0) { - $.ajax({ - url: Drupal.url('contextual/render'), - type: 'POST', - data: { 'ids[]': uncachedIDs, 'tokens[]': uncachedTokens }, - dataType: 'json', - success(results) { - _.each(results, (html, contextualID) => { - // Store the metadata. - storage.setItem(`Drupal.contextual.${contextualID}`, html); - // If the rendered contextual links are empty, then the current - // user does not have permission to access the associated links: - // don't render anything. - if (html.length > 0) { - // Update the placeholders to contain its rendered contextual - // links. Usually there will only be one placeholder, but it's - // possible for multiple identical placeholders exist on the - // page (probably because the same content appears more than - // once). - $placeholders = $context.find( - `[data-contextual-id="${contextualID}"]`, - ); - - // Initialize the contextual links. - for (let i = 0; i < $placeholders.length; i++) { - initContextual($placeholders.eq(i), html); - } - } - }); - }, - }); - } - }, - }; - - /** - * Namespace for contextual related functionality. - * - * @namespace - * - * @private - */ - Drupal.contextual = { - /** - * The {@link Drupal.contextual.View} instances associated with each list - * element of contextual links. - * - * @type {Array} - * - * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no - * replacement. - */ - views: [], - - /** - * The {@link Drupal.contextual.RegionView} instances associated with each - * contextual region element. - * - * @type {Array} - * - * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no - * replacement. - */ - regionViews: [], - }; - - /** - * A Backbone.Collection of {@link Drupal.contextual.StateModel} instances. - * - * @type {Backbone.Collection} - * - * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no - * replacement. - */ - Drupal.contextual.collection = new Backbone.Collection([], { - model: Drupal.contextual.StateModel, - }); - - /** - * A trigger is an interactive element often bound to a click handler. - * - * @return {string} - * A string representing a DOM fragment. - */ - Drupal.theme.contextualTrigger = function () { - return '<button class="trigger visually-hidden focusable" type="button"></button>'; - }; - - /** - * Bind Ajax contextual links when 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) => { - Drupal.ajax.bindAjaxLinks(data.$el[0]); - }); -})( - jQuery, - Drupal, - drupalSettings, - _, - Backbone, - window.JSON, - window.sessionStorage, -); diff --git a/core/modules/contextual/js/contextual.js b/core/modules/contextual/js/contextual.js index f4abf7ec157..b5fe7d094fb 100644 --- a/core/modules/contextual/js/contextual.js +++ b/core/modules/contextual/js/contextual.js @@ -1,175 +1,321 @@ /** -* DO NOT EDIT THIS FILE. -* See the following change record for more information, -* https://www.drupal.org/node/2815083 -* @preserve -**/ + * @file + * Attaches behaviors for the Contextual module. + */ (function ($, Drupal, drupalSettings, _, Backbone, JSON, storage) { - const options = $.extend(drupalSettings.contextual, { - strings: { - open: Drupal.t('Open'), - close: Drupal.t('Close') - } - }); - const cachedPermissionsHash = storage.getItem('Drupal.contextual.permissionsHash'); - const permissionsHash = drupalSettings.user.permissionsHash; + const options = $.extend( + drupalSettings.contextual, + // Merge strings on top of drupalSettings so that they are not mutable. + { + strings: { + open: Drupal.t('Open'), + close: Drupal.t('Close'), + }, + }, + ); + // Clear the cached contextual links whenever the current user's set of + // permissions changes. + const cachedPermissionsHash = storage.getItem( + 'Drupal.contextual.permissionsHash', + ); + const permissionsHash = drupalSettings.user.permissionsHash; if (cachedPermissionsHash !== permissionsHash) { if (typeof permissionsHash === 'string') { - _.chain(storage).keys().each(key => { - if (key.substring(0, 18) === 'Drupal.contextual.') { - storage.removeItem(key); - } - }); + _.chain(storage) + .keys() + .each((key) => { + if (key.substring(0, 18) === 'Drupal.contextual.') { + storage.removeItem(key); + } + }); } - storage.setItem('Drupal.contextual.permissionsHash', permissionsHash); } + /** + * Determines if a contextual link is nested & overlapping, if so: adjusts it. + * + * This only deals with two levels of nesting; deeper levels are not touched. + * + * @param {jQuery} $contextual + * A contextual links placeholder DOM element, containing the actual + * contextual links as rendered by the server. + */ function adjustIfNestedAndOverlapping($contextual) { - const $contextuals = $contextual.parents('.contextual-region').eq(-1).find('.contextual'); + const $contextuals = $contextual + // @todo confirm that .closest() is not sufficient + .parents('.contextual-region') + .eq(-1) + .find('.contextual'); + // Early-return when there's no nesting. if ($contextuals.length <= 1) { return; } + // If the two contextual links overlap, then we move the second one. const firstTop = $contextuals.eq(0).offset().top; const secondTop = $contextuals.eq(1).offset().top; - if (firstTop === secondTop) { const $nestedContextual = $contextuals.eq(1); + + // Retrieve height of nested contextual link. let height = 0; const $trigger = $nestedContextual.find('.trigger'); + // Elements with the .visually-hidden class have no dimensions, so this + // class must be temporarily removed to the calculate the height. $trigger.removeClass('visually-hidden'); height = $nestedContextual.height(); $trigger.addClass('visually-hidden'); - $nestedContextual.css({ - top: $nestedContextual.position().top + height - }); + + // Adjust nested contextual link's position. + $nestedContextual.css({ top: $nestedContextual.position().top + height }); } } + /** + * Initializes a contextual link: updates its DOM, sets up model and views. + * + * @param {jQuery} $contextual + * A contextual links placeholder DOM element, containing the actual + * contextual links as rendered by the server. + * @param {string} html + * The server-side rendered HTML for this contextual link. + */ function initContextual($contextual, html) { const $region = $contextual.closest('.contextual-region'); const contextual = Drupal.contextual; - $contextual.html(html).addClass('contextual').prepend(Drupal.theme('contextualTrigger')); - const destination = `destination=${Drupal.encodePath(Drupal.url(drupalSettings.path.currentPath))}`; + + $contextual + // Update the placeholder to contain its rendered contextual links. + .html(html) + // Use the placeholder as a wrapper with a specific class to provide + // positioning and behavior attachment context. + .addClass('contextual') + // Ensure a trigger element exists before the actual contextual links. + .prepend(Drupal.theme('contextualTrigger')); + + // Set the destination parameter on each of the contextual links. + const destination = `destination=${Drupal.encodePath( + Drupal.url(drupalSettings.path.currentPath), + )}`; $contextual.find('.contextual-links a').each(function () { const url = this.getAttribute('href'); const glue = url.indexOf('?') === -1 ? '?' : '&'; this.setAttribute('href', url + glue + destination); }); + let title = ''; const $regionHeading = $region.find('h2'); - if ($regionHeading.length) { title = $regionHeading[0].textContent.trim(); } - + // Create a model and the appropriate views. const model = new contextual.StateModel({ - title + title, }); - const viewOptions = $.extend({ - el: $contextual, - model - }, options); + const viewOptions = $.extend({ el: $contextual, model }, options); contextual.views.push({ visual: new contextual.VisualView(viewOptions), aural: new contextual.AuralView(viewOptions), - keyboard: new contextual.KeyboardView(viewOptions) + keyboard: new contextual.KeyboardView(viewOptions), }); - contextual.regionViews.push(new contextual.RegionView($.extend({ - el: $region, - model - }, options))); + contextual.regionViews.push( + new contextual.RegionView($.extend({ el: $region, model }, options)), + ); + + // Add the model to the collection. This must happen after the views have + // been associated with it, otherwise collection change event handlers can't + // trigger the model change event handler in its views. contextual.collection.add(model); - $(document).trigger('drupalContextualLinkAdded', Drupal.deprecatedProperty({ - target: { - $el: $contextual, - $region, - model - }, - deprecatedProperty: 'model', - message: 'The model property is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no replacement.' - })); + + // Let other JavaScript react to the adding of a new contextual link. + $(document).trigger( + 'drupalContextualLinkAdded', + Drupal.deprecatedProperty({ + target: { + $el: $contextual, + $region, + model, + }, + deprecatedProperty: 'model', + message: + 'The model property is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no replacement.', + }), + ); + + // Fix visual collisions between contextual link triggers. adjustIfNestedAndOverlapping($contextual); } + /** + * Attaches outline behavior for regions associated with contextual links. + * + * Events + * Contextual triggers an event that can be used by other scripts. + * - drupalContextualLinkAdded: Triggered when a contextual link is added. + * + * @type {Drupal~behavior} + * + * @prop {Drupal~behaviorAttach} attach + * Attaches the outline behavior to the right context. + */ Drupal.behaviors.contextual = { attach(context) { const $context = $(context); - let $placeholders = $(once('contextual-render', '[data-contextual-id]', context)); + // Find all contextual links placeholders, if any. + let $placeholders = $( + once('contextual-render', '[data-contextual-id]', context), + ); if ($placeholders.length === 0) { return; } + // Collect the IDs for all contextual links placeholders. const ids = []; $placeholders.each(function () { ids.push({ id: $(this).attr('data-contextual-id'), - token: $(this).attr('data-contextual-token') + token: $(this).attr('data-contextual-token'), }); }); + const uncachedIDs = []; const uncachedTokens = []; - ids.forEach(contextualID => { + ids.forEach((contextualID) => { const html = storage.getItem(`Drupal.contextual.${contextualID.id}`); - if (html && html.length) { + // Initialize after the current execution cycle, to make the AJAX + // request for retrieving the uncached contextual links as soon as + // possible, but also to ensure that other Drupal behaviors have had + // the chance to set up an event listener on the Backbone collection + // Drupal.contextual.collection. window.setTimeout(() => { - initContextual($context.find(`[data-contextual-id="${contextualID.id}"]:empty`).eq(0), html); + initContextual( + $context + .find(`[data-contextual-id="${contextualID.id}"]:empty`) + .eq(0), + html, + ); }); return; } - uncachedIDs.push(contextualID.id); uncachedTokens.push(contextualID.token); }); + // Perform an AJAX request to let the server render the contextual links + // for each of the placeholders. if (uncachedIDs.length > 0) { $.ajax({ url: Drupal.url('contextual/render'), type: 'POST', - data: { - 'ids[]': uncachedIDs, - 'tokens[]': uncachedTokens - }, + data: { 'ids[]': uncachedIDs, 'tokens[]': uncachedTokens }, dataType: 'json', - success(results) { _.each(results, (html, contextualID) => { + // Store the metadata. storage.setItem(`Drupal.contextual.${contextualID}`, html); - + // If the rendered contextual links are empty, then the current + // user does not have permission to access the associated links: + // don't render anything. if (html.length > 0) { - $placeholders = $context.find(`[data-contextual-id="${contextualID}"]`); + // Update the placeholders to contain its rendered contextual + // links. Usually there will only be one placeholder, but it's + // possible for multiple identical placeholders exist on the + // page (probably because the same content appears more than + // once). + $placeholders = $context.find( + `[data-contextual-id="${contextualID}"]`, + ); + // Initialize the contextual links. for (let i = 0; i < $placeholders.length; i++) { initContextual($placeholders.eq(i), html); } } }); - } - + }, }); } - } - + }, }; + + /** + * Namespace for contextual related functionality. + * + * @namespace + * + * @private + */ Drupal.contextual = { + /** + * The {@link Drupal.contextual.View} instances associated with each list + * element of contextual links. + * + * @type {Array} + * + * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no + * replacement. + */ views: [], - regionViews: [] + + /** + * The {@link Drupal.contextual.RegionView} instances associated with each + * contextual region element. + * + * @type {Array} + * + * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no + * replacement. + */ + regionViews: [], }; + + /** + * A Backbone.Collection of {@link Drupal.contextual.StateModel} instances. + * + * @type {Backbone.Collection} + * + * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no + * replacement. + */ Drupal.contextual.collection = new Backbone.Collection([], { - model: Drupal.contextual.StateModel + model: Drupal.contextual.StateModel, }); + /** + * A trigger is an interactive element often bound to a click handler. + * + * @return {string} + * A string representing a DOM fragment. + */ Drupal.theme.contextualTrigger = function () { return '<button class="trigger visually-hidden focusable" type="button"></button>'; }; + /** + * Bind Ajax contextual links when 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) => { Drupal.ajax.bindAjaxLinks(data.$el[0]); }); -})(jQuery, Drupal, drupalSettings, _, Backbone, window.JSON, window.sessionStorage);
\ No newline at end of file +})( + jQuery, + Drupal, + drupalSettings, + _, + Backbone, + window.JSON, + window.sessionStorage, +); diff --git a/core/modules/contextual/js/contextual.toolbar.es6.js b/core/modules/contextual/js/contextual.toolbar.es6.js deleted file mode 100644 index 2cbac3e139c..00000000000 --- a/core/modules/contextual/js/contextual.toolbar.es6.js +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @file - * Attaches behaviors for the Contextual module's edit toolbar tab. - */ - -(function ($, Drupal, Backbone) { - const strings = { - tabbingReleased: Drupal.t( - 'Tabbing is no longer constrained by the Contextual module.', - ), - tabbingConstrained: Drupal.t( - 'Tabbing is constrained to a set of @contextualsCount and the edit mode toggle.', - ), - pressEsc: Drupal.t('Press the esc key to exit.'), - }; - - /** - * Initializes a contextual link: updates its DOM, sets up model and views. - * - * @param {HTMLElement} context - * A contextual links DOM element as rendered by the server. - */ - function initContextualToolbar(context) { - if (!Drupal.contextual || !Drupal.contextual.collection) { - return; - } - - const contextualToolbar = Drupal.contextualToolbar; - contextualToolbar.model = new contextualToolbar.StateModel( - { - // Checks whether localStorage indicates we should start in edit mode - // rather than view mode. - // @see Drupal.contextualToolbar.VisualView.persist - isViewing: - localStorage.getItem('Drupal.contextualToolbar.isViewing') !== - 'false', - }, - { - contextualCollection: Drupal.contextual.collection, - }, - ); - - const viewOptions = { - el: $('.toolbar .toolbar-bar .contextual-toolbar-tab'), - model: contextualToolbar.model, - strings, - }; - new contextualToolbar.VisualView(viewOptions); - new contextualToolbar.AuralView(viewOptions); - } - - /** - * Attaches contextual's edit toolbar tab behavior. - * - * @type {Drupal~behavior} - * - * @prop {Drupal~behaviorAttach} attach - * Attaches contextual toolbar behavior on a contextualToolbar-init event. - */ - Drupal.behaviors.contextualToolbar = { - attach(context) { - if (once('contextualToolbar-init', 'body').length) { - initContextualToolbar(context); - } - }, - }; - - /** - * Namespace for the contextual toolbar. - * - * @namespace - * - * @private - */ - Drupal.contextualToolbar = { - /** - * The {@link Drupal.contextualToolbar.StateModel} instance. - * - * @type {?Drupal.contextualToolbar.StateModel} - * - * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is - * no replacement. - */ - model: null, - }; -})(jQuery, Drupal, Backbone); diff --git a/core/modules/contextual/js/contextual.toolbar.js b/core/modules/contextual/js/contextual.toolbar.js index 4a5673a6e27..2cbac3e139c 100644 --- a/core/modules/contextual/js/contextual.toolbar.js +++ b/core/modules/contextual/js/contextual.toolbar.js @@ -1,46 +1,86 @@ /** -* DO NOT EDIT THIS FILE. -* See the following change record for more information, -* https://www.drupal.org/node/2815083 -* @preserve -**/ + * @file + * Attaches behaviors for the Contextual module's edit toolbar tab. + */ (function ($, Drupal, Backbone) { const strings = { - tabbingReleased: Drupal.t('Tabbing is no longer constrained by the Contextual module.'), - tabbingConstrained: Drupal.t('Tabbing is constrained to a set of @contextualsCount and the edit mode toggle.'), - pressEsc: Drupal.t('Press the esc key to exit.') + tabbingReleased: Drupal.t( + 'Tabbing is no longer constrained by the Contextual module.', + ), + tabbingConstrained: Drupal.t( + 'Tabbing is constrained to a set of @contextualsCount and the edit mode toggle.', + ), + pressEsc: Drupal.t('Press the esc key to exit.'), }; + /** + * Initializes a contextual link: updates its DOM, sets up model and views. + * + * @param {HTMLElement} context + * A contextual links DOM element as rendered by the server. + */ function initContextualToolbar(context) { if (!Drupal.contextual || !Drupal.contextual.collection) { return; } const contextualToolbar = Drupal.contextualToolbar; - contextualToolbar.model = new contextualToolbar.StateModel({ - isViewing: localStorage.getItem('Drupal.contextualToolbar.isViewing') !== 'false' - }, { - contextualCollection: Drupal.contextual.collection - }); + contextualToolbar.model = new contextualToolbar.StateModel( + { + // Checks whether localStorage indicates we should start in edit mode + // rather than view mode. + // @see Drupal.contextualToolbar.VisualView.persist + isViewing: + localStorage.getItem('Drupal.contextualToolbar.isViewing') !== + 'false', + }, + { + contextualCollection: Drupal.contextual.collection, + }, + ); + const viewOptions = { el: $('.toolbar .toolbar-bar .contextual-toolbar-tab'), model: contextualToolbar.model, - strings + strings, }; new contextualToolbar.VisualView(viewOptions); new contextualToolbar.AuralView(viewOptions); } + /** + * Attaches contextual's edit toolbar tab behavior. + * + * @type {Drupal~behavior} + * + * @prop {Drupal~behaviorAttach} attach + * Attaches contextual toolbar behavior on a contextualToolbar-init event. + */ Drupal.behaviors.contextualToolbar = { attach(context) { if (once('contextualToolbar-init', 'body').length) { initContextualToolbar(context); } - } - + }, }; + + /** + * Namespace for the contextual toolbar. + * + * @namespace + * + * @private + */ Drupal.contextualToolbar = { - model: null + /** + * The {@link Drupal.contextualToolbar.StateModel} instance. + * + * @type {?Drupal.contextualToolbar.StateModel} + * + * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is + * no replacement. + */ + model: null, }; -})(jQuery, Drupal, Backbone);
\ No newline at end of file +})(jQuery, Drupal, Backbone); diff --git a/core/modules/contextual/js/models/StateModel.es6.js b/core/modules/contextual/js/models/StateModel.es6.js deleted file mode 100644 index 09fe8ed4eec..00000000000 --- a/core/modules/contextual/js/models/StateModel.es6.js +++ /dev/null @@ -1,130 +0,0 @@ -/** - * @file - * A Backbone Model for the state of a contextual link's trigger, list & region. - */ - -(function (Drupal, Backbone) { - /** - * Models the state of a contextual link's trigger, list & region. - * - * @constructor - * - * @augments Backbone.Model - * - * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no - * replacement. - */ - Drupal.contextual.StateModel = Backbone.Model.extend( - /** @lends Drupal.contextual.StateModel# */ { - /** - * @type {object} - * - * @prop {string} title - * @prop {bool} regionIsHovered - * @prop {bool} hasFocus - * @prop {bool} isOpen - * @prop {bool} isLocked - */ - defaults: /** @lends Drupal.contextual.StateModel# */ { - /** - * The title of the entity to which these contextual links apply. - * - * @type {string} - */ - title: '', - - /** - * Represents if the contextual region is being hovered. - * - * @type {bool} - */ - regionIsHovered: false, - - /** - * Represents if the contextual trigger or options have focus. - * - * @type {bool} - */ - hasFocus: false, - - /** - * Represents if the contextual options for an entity are available to - * be selected (i.e. whether the list of options is visible). - * - * @type {bool} - */ - isOpen: false, - - /** - * When the model is locked, the trigger remains active. - * - * @type {bool} - */ - isLocked: false, - }, - - /** - * Opens or closes the contextual link. - * - * If it is opened, then also give focus. - * - * @return {Drupal.contextual.StateModel} - * The current contextual state model. - */ - toggleOpen() { - const newIsOpen = !this.get('isOpen'); - this.set('isOpen', newIsOpen); - if (newIsOpen) { - this.focus(); - } - return this; - }, - - /** - * Closes this contextual link. - * - * Does not call blur() because we want to allow a contextual link to have - * focus, yet be closed for example when hovering. - * - * @return {Drupal.contextual.StateModel} - * The current contextual state model. - */ - close() { - this.set('isOpen', false); - return this; - }, - - /** - * Gives focus to this contextual link. - * - * Also closes + removes focus from every other contextual link. - * - * @return {Drupal.contextual.StateModel} - * The current contextual state model. - */ - focus() { - this.set('hasFocus', true); - const cid = this.cid; - this.collection.each((model) => { - if (model.cid !== cid) { - model.close().blur(); - } - }); - return this; - }, - - /** - * Removes focus from this contextual link, unless it is open. - * - * @return {Drupal.contextual.StateModel} - * The current contextual state model. - */ - blur() { - if (!this.get('isOpen')) { - this.set('hasFocus', false); - } - return this; - }, - }, - ); -})(Drupal, Backbone); diff --git a/core/modules/contextual/js/models/StateModel.js b/core/modules/contextual/js/models/StateModel.js index a132a7c1fb2..09fe8ed4eec 100644 --- a/core/modules/contextual/js/models/StateModel.js +++ b/core/modules/contextual/js/models/StateModel.js @@ -1,54 +1,130 @@ /** -* DO NOT EDIT THIS FILE. -* See the following change record for more information, -* https://www.drupal.org/node/2815083 -* @preserve -**/ + * @file + * A Backbone Model for the state of a contextual link's trigger, list & region. + */ (function (Drupal, Backbone) { - Drupal.contextual.StateModel = Backbone.Model.extend({ - defaults: { - title: '', - regionIsHovered: false, - hasFocus: false, - isOpen: false, - isLocked: false - }, + /** + * Models the state of a contextual link's trigger, list & region. + * + * @constructor + * + * @augments Backbone.Model + * + * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no + * replacement. + */ + Drupal.contextual.StateModel = Backbone.Model.extend( + /** @lends Drupal.contextual.StateModel# */ { + /** + * @type {object} + * + * @prop {string} title + * @prop {bool} regionIsHovered + * @prop {bool} hasFocus + * @prop {bool} isOpen + * @prop {bool} isLocked + */ + defaults: /** @lends Drupal.contextual.StateModel# */ { + /** + * The title of the entity to which these contextual links apply. + * + * @type {string} + */ + title: '', - toggleOpen() { - const newIsOpen = !this.get('isOpen'); - this.set('isOpen', newIsOpen); + /** + * Represents if the contextual region is being hovered. + * + * @type {bool} + */ + regionIsHovered: false, - if (newIsOpen) { - this.focus(); - } + /** + * Represents if the contextual trigger or options have focus. + * + * @type {bool} + */ + hasFocus: false, - return this; - }, + /** + * Represents if the contextual options for an entity are available to + * be selected (i.e. whether the list of options is visible). + * + * @type {bool} + */ + isOpen: false, - close() { - this.set('isOpen', false); - return this; - }, + /** + * When the model is locked, the trigger remains active. + * + * @type {bool} + */ + isLocked: false, + }, - focus() { - this.set('hasFocus', true); - const cid = this.cid; - this.collection.each(model => { - if (model.cid !== cid) { - model.close().blur(); + /** + * Opens or closes the contextual link. + * + * If it is opened, then also give focus. + * + * @return {Drupal.contextual.StateModel} + * The current contextual state model. + */ + toggleOpen() { + const newIsOpen = !this.get('isOpen'); + this.set('isOpen', newIsOpen); + if (newIsOpen) { + this.focus(); } - }); - return this; - }, + return this; + }, - blur() { - if (!this.get('isOpen')) { - this.set('hasFocus', false); - } + /** + * Closes this contextual link. + * + * Does not call blur() because we want to allow a contextual link to have + * focus, yet be closed for example when hovering. + * + * @return {Drupal.contextual.StateModel} + * The current contextual state model. + */ + close() { + this.set('isOpen', false); + return this; + }, - return this; - } + /** + * Gives focus to this contextual link. + * + * Also closes + removes focus from every other contextual link. + * + * @return {Drupal.contextual.StateModel} + * The current contextual state model. + */ + focus() { + this.set('hasFocus', true); + const cid = this.cid; + this.collection.each((model) => { + if (model.cid !== cid) { + model.close().blur(); + } + }); + return this; + }, - }); -})(Drupal, Backbone);
\ No newline at end of file + /** + * Removes focus from this contextual link, unless it is open. + * + * @return {Drupal.contextual.StateModel} + * The current contextual state model. + */ + blur() { + if (!this.get('isOpen')) { + this.set('hasFocus', false); + } + return this; + }, + }, + ); +})(Drupal, Backbone); diff --git a/core/modules/contextual/js/toolbar/models/StateModel.es6.js b/core/modules/contextual/js/toolbar/models/StateModel.es6.js deleted file mode 100644 index 07ab5dba471..00000000000 --- a/core/modules/contextual/js/toolbar/models/StateModel.es6.js +++ /dev/null @@ -1,126 +0,0 @@ -/** - * @file - * A Backbone Model for the state of Contextual module's edit toolbar tab. - */ - -(function (Drupal, Backbone) { - /** - * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no - * replacement. - */ - Drupal.contextualToolbar.StateModel = Backbone.Model.extend( - /** @lends Drupal.contextualToolbar.StateModel# */ { - /** - * @type {object} - * - * @prop {bool} isViewing - * @prop {bool} isVisible - * @prop {number} contextualCount - * @prop {Drupal~TabbingContext} tabbingContext - */ - defaults: /** @lends Drupal.contextualToolbar.StateModel# */ { - /** - * Indicates whether the toggle is currently in "view" or "edit" mode. - * - * @type {bool} - */ - isViewing: true, - - /** - * Indicates whether the toggle should be visible or hidden. Automatically - * calculated, depends on contextualCount. - * - * @type {bool} - */ - isVisible: false, - - /** - * Tracks how many contextual links exist on the page. - * - * @type {number} - */ - contextualCount: 0, - - /** - * A TabbingContext object as returned by {@link Drupal~TabbingManager}: - * the set of tabbable elements when edit mode is enabled. - * - * @type {?Drupal~TabbingContext} - */ - tabbingContext: null, - }, - - /** - * Models the state of the edit mode toggle. - * - * @constructs - * - * @augments Backbone.Model - * - * @param {object} attrs - * Attributes for the backbone model. - * @param {object} options - * An object with the following option: - * @param {Backbone.collection} options.contextualCollection - * The collection of {@link Drupal.contextual.StateModel} models that - * represent the contextual links on the page. - */ - initialize(attrs, options) { - // Respond to new/removed contextual links. - this.listenTo( - options.contextualCollection, - 'reset remove add', - this.countContextualLinks, - ); - this.listenTo( - options.contextualCollection, - 'add', - this.lockNewContextualLinks, - ); - - // Automatically determine visibility. - this.listenTo(this, 'change:contextualCount', this.updateVisibility); - - // Whenever edit mode is toggled, lock all contextual links. - this.listenTo(this, 'change:isViewing', (model, isViewing) => { - options.contextualCollection.each((contextualModel) => { - contextualModel.set('isLocked', !isViewing); - }); - }); - }, - - /** - * Tracks the number of contextual link models in the collection. - * - * @param {Drupal.contextual.StateModel} contextualModel - * The contextual links model that was added or removed. - * @param {Backbone.Collection} contextualCollection - * The collection of contextual link models. - */ - countContextualLinks(contextualModel, contextualCollection) { - this.set('contextualCount', contextualCollection.length); - }, - - /** - * Lock newly added contextual links if edit mode is enabled. - * - * @param {Drupal.contextual.StateModel} contextualModel - * The contextual links model that was added. - * @param {Backbone.Collection} [contextualCollection] - * The collection of contextual link models. - */ - lockNewContextualLinks(contextualModel, contextualCollection) { - if (!this.get('isViewing')) { - contextualModel.set('isLocked', true); - } - }, - - /** - * Automatically updates visibility of the view/edit mode toggle. - */ - updateVisibility() { - this.set('isVisible', this.get('contextualCount') > 0); - }, - }, - ); -})(Drupal, Backbone); diff --git a/core/modules/contextual/js/toolbar/models/StateModel.js b/core/modules/contextual/js/toolbar/models/StateModel.js index f6dedcf0502..07ab5dba471 100644 --- a/core/modules/contextual/js/toolbar/models/StateModel.js +++ b/core/modules/contextual/js/toolbar/models/StateModel.js @@ -1,43 +1,126 @@ /** -* DO NOT EDIT THIS FILE. -* See the following change record for more information, -* https://www.drupal.org/node/2815083 -* @preserve -**/ + * @file + * A Backbone Model for the state of Contextual module's edit toolbar tab. + */ (function (Drupal, Backbone) { - Drupal.contextualToolbar.StateModel = Backbone.Model.extend({ - defaults: { - isViewing: true, - isVisible: false, - contextualCount: 0, - tabbingContext: null - }, + /** + * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no + * replacement. + */ + Drupal.contextualToolbar.StateModel = Backbone.Model.extend( + /** @lends Drupal.contextualToolbar.StateModel# */ { + /** + * @type {object} + * + * @prop {bool} isViewing + * @prop {bool} isVisible + * @prop {number} contextualCount + * @prop {Drupal~TabbingContext} tabbingContext + */ + defaults: /** @lends Drupal.contextualToolbar.StateModel# */ { + /** + * Indicates whether the toggle is currently in "view" or "edit" mode. + * + * @type {bool} + */ + isViewing: true, - initialize(attrs, options) { - this.listenTo(options.contextualCollection, 'reset remove add', this.countContextualLinks); - this.listenTo(options.contextualCollection, 'add', this.lockNewContextualLinks); - this.listenTo(this, 'change:contextualCount', this.updateVisibility); - this.listenTo(this, 'change:isViewing', (model, isViewing) => { - options.contextualCollection.each(contextualModel => { - contextualModel.set('isLocked', !isViewing); - }); - }); - }, + /** + * Indicates whether the toggle should be visible or hidden. Automatically + * calculated, depends on contextualCount. + * + * @type {bool} + */ + isVisible: false, - countContextualLinks(contextualModel, contextualCollection) { - this.set('contextualCount', contextualCollection.length); - }, + /** + * Tracks how many contextual links exist on the page. + * + * @type {number} + */ + contextualCount: 0, - lockNewContextualLinks(contextualModel, contextualCollection) { - if (!this.get('isViewing')) { - contextualModel.set('isLocked', true); - } - }, + /** + * A TabbingContext object as returned by {@link Drupal~TabbingManager}: + * the set of tabbable elements when edit mode is enabled. + * + * @type {?Drupal~TabbingContext} + */ + tabbingContext: null, + }, + + /** + * Models the state of the edit mode toggle. + * + * @constructs + * + * @augments Backbone.Model + * + * @param {object} attrs + * Attributes for the backbone model. + * @param {object} options + * An object with the following option: + * @param {Backbone.collection} options.contextualCollection + * The collection of {@link Drupal.contextual.StateModel} models that + * represent the contextual links on the page. + */ + initialize(attrs, options) { + // Respond to new/removed contextual links. + this.listenTo( + options.contextualCollection, + 'reset remove add', + this.countContextualLinks, + ); + this.listenTo( + options.contextualCollection, + 'add', + this.lockNewContextualLinks, + ); - updateVisibility() { - this.set('isVisible', this.get('contextualCount') > 0); - } + // Automatically determine visibility. + this.listenTo(this, 'change:contextualCount', this.updateVisibility); - }); -})(Drupal, Backbone);
\ No newline at end of file + // Whenever edit mode is toggled, lock all contextual links. + this.listenTo(this, 'change:isViewing', (model, isViewing) => { + options.contextualCollection.each((contextualModel) => { + contextualModel.set('isLocked', !isViewing); + }); + }); + }, + + /** + * Tracks the number of contextual link models in the collection. + * + * @param {Drupal.contextual.StateModel} contextualModel + * The contextual links model that was added or removed. + * @param {Backbone.Collection} contextualCollection + * The collection of contextual link models. + */ + countContextualLinks(contextualModel, contextualCollection) { + this.set('contextualCount', contextualCollection.length); + }, + + /** + * Lock newly added contextual links if edit mode is enabled. + * + * @param {Drupal.contextual.StateModel} contextualModel + * The contextual links model that was added. + * @param {Backbone.Collection} [contextualCollection] + * The collection of contextual link models. + */ + lockNewContextualLinks(contextualModel, contextualCollection) { + if (!this.get('isViewing')) { + contextualModel.set('isLocked', true); + } + }, + + /** + * Automatically updates visibility of the view/edit mode toggle. + */ + updateVisibility() { + this.set('isVisible', this.get('contextualCount') > 0); + }, + }, + ); +})(Drupal, Backbone); diff --git a/core/modules/contextual/js/toolbar/views/AuralView.es6.js b/core/modules/contextual/js/toolbar/views/AuralView.es6.js deleted file mode 100644 index 45449de62bd..00000000000 --- a/core/modules/contextual/js/toolbar/views/AuralView.es6.js +++ /dev/null @@ -1,122 +0,0 @@ -/** - * @file - * A Backbone View that provides the aural view of the edit mode toggle. - */ - -(function ($, Drupal, Backbone, _) { - /** - * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no - * replacement. - */ - Drupal.contextualToolbar.AuralView = Backbone.View.extend( - /** @lends Drupal.contextualToolbar.AuralView# */ { - /** - * Tracks whether the tabbing constraint announcement has been read once. - * - * @type {bool} - */ - announcedOnce: false, - - /** - * Renders the aural view of the edit mode toggle (screen reader support). - * - * @constructs - * - * @augments Backbone.View - * - * @param {object} options - * Options for the view. - */ - initialize(options) { - this.options = options; - - this.listenTo(this.model, 'change', this.render); - this.listenTo(this.model, 'change:isViewing', this.manageTabbing); - - $(document).on('keyup', _.bind(this.onKeypress, this)); - this.manageTabbing(); - }, - - /** - * {@inheritdoc} - * - * @return {Drupal.contextualToolbar.AuralView} - * The current contextual toolbar aural view. - */ - render() { - // Render the state. - this.$el - .find('button') - .attr('aria-pressed', !this.model.get('isViewing')); - - return this; - }, - - /** - * Limits tabbing to the contextual links and edit mode toolbar tab. - */ - manageTabbing() { - let tabbingContext = this.model.get('tabbingContext'); - // Always release an existing tabbing context. - if (tabbingContext) { - // Only announce release when the context was active. - if (tabbingContext.active) { - Drupal.announce(this.options.strings.tabbingReleased); - } - tabbingContext.release(); - } - // Create a new tabbing context when edit mode is enabled. - if (!this.model.get('isViewing')) { - tabbingContext = Drupal.tabbingManager.constrain( - $('.contextual-toolbar-tab, .contextual'), - ); - this.model.set('tabbingContext', tabbingContext); - this.announceTabbingConstraint(); - this.announcedOnce = true; - } - }, - - /** - * Announces the current tabbing constraint. - */ - announceTabbingConstraint() { - const strings = this.options.strings; - Drupal.announce( - Drupal.formatString(strings.tabbingConstrained, { - '@contextualsCount': Drupal.formatPlural( - Drupal.contextual.collection.length, - '@count contextual link', - '@count contextual links', - ), - }), - ); - Drupal.announce(strings.pressEsc); - }, - - /** - * Responds to esc and tab key press events. - * - * @param {jQuery.Event} event - * The keypress event. - */ - onKeypress(event) { - // The first tab key press is tracked so that an announcement about - // tabbing constraints can be raised if edit mode is enabled when the page - // is loaded. - if ( - !this.announcedOnce && - event.keyCode === 9 && - !this.model.get('isViewing') - ) { - this.announceTabbingConstraint(); - // Set announce to true so that this conditional block won't run again. - this.announcedOnce = true; - } - // Respond to the ESC key. Exit out of edit mode. - if (event.keyCode === 27) { - this.model.set('isViewing', true); - } - }, - }, - ); -})(jQuery, Drupal, Backbone, _); diff --git a/core/modules/contextual/js/toolbar/views/AuralView.js b/core/modules/contextual/js/toolbar/views/AuralView.js index 59890d57999..45449de62bd 100644 --- a/core/modules/contextual/js/toolbar/views/AuralView.js +++ b/core/modules/contextual/js/toolbar/views/AuralView.js @@ -1,64 +1,122 @@ /** -* DO NOT EDIT THIS FILE. -* See the following change record for more information, -* https://www.drupal.org/node/2815083 -* @preserve -**/ + * @file + * A Backbone View that provides the aural view of the edit mode toggle. + */ (function ($, Drupal, Backbone, _) { - Drupal.contextualToolbar.AuralView = Backbone.View.extend({ - announcedOnce: false, + /** + * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no + * replacement. + */ + Drupal.contextualToolbar.AuralView = Backbone.View.extend( + /** @lends Drupal.contextualToolbar.AuralView# */ { + /** + * Tracks whether the tabbing constraint announcement has been read once. + * + * @type {bool} + */ + announcedOnce: false, - initialize(options) { - this.options = options; - this.listenTo(this.model, 'change', this.render); - this.listenTo(this.model, 'change:isViewing', this.manageTabbing); - $(document).on('keyup', _.bind(this.onKeypress, this)); - this.manageTabbing(); - }, - - render() { - this.$el.find('button').attr('aria-pressed', !this.model.get('isViewing')); - return this; - }, + /** + * Renders the aural view of the edit mode toggle (screen reader support). + * + * @constructs + * + * @augments Backbone.View + * + * @param {object} options + * Options for the view. + */ + initialize(options) { + this.options = options; - manageTabbing() { - let tabbingContext = this.model.get('tabbingContext'); + this.listenTo(this.model, 'change', this.render); + this.listenTo(this.model, 'change:isViewing', this.manageTabbing); - if (tabbingContext) { - if (tabbingContext.active) { - Drupal.announce(this.options.strings.tabbingReleased); - } - - tabbingContext.release(); - } + $(document).on('keyup', _.bind(this.onKeypress, this)); + this.manageTabbing(); + }, - if (!this.model.get('isViewing')) { - tabbingContext = Drupal.tabbingManager.constrain($('.contextual-toolbar-tab, .contextual')); - this.model.set('tabbingContext', tabbingContext); - this.announceTabbingConstraint(); - this.announcedOnce = true; - } - }, + /** + * {@inheritdoc} + * + * @return {Drupal.contextualToolbar.AuralView} + * The current contextual toolbar aural view. + */ + render() { + // Render the state. + this.$el + .find('button') + .attr('aria-pressed', !this.model.get('isViewing')); - announceTabbingConstraint() { - const strings = this.options.strings; - Drupal.announce(Drupal.formatString(strings.tabbingConstrained, { - '@contextualsCount': Drupal.formatPlural(Drupal.contextual.collection.length, '@count contextual link', '@count contextual links') - })); - Drupal.announce(strings.pressEsc); - }, + return this; + }, - onKeypress(event) { - if (!this.announcedOnce && event.keyCode === 9 && !this.model.get('isViewing')) { - this.announceTabbingConstraint(); - this.announcedOnce = true; - } + /** + * Limits tabbing to the contextual links and edit mode toolbar tab. + */ + manageTabbing() { + let tabbingContext = this.model.get('tabbingContext'); + // Always release an existing tabbing context. + if (tabbingContext) { + // Only announce release when the context was active. + if (tabbingContext.active) { + Drupal.announce(this.options.strings.tabbingReleased); + } + tabbingContext.release(); + } + // Create a new tabbing context when edit mode is enabled. + if (!this.model.get('isViewing')) { + tabbingContext = Drupal.tabbingManager.constrain( + $('.contextual-toolbar-tab, .contextual'), + ); + this.model.set('tabbingContext', tabbingContext); + this.announceTabbingConstraint(); + this.announcedOnce = true; + } + }, - if (event.keyCode === 27) { - this.model.set('isViewing', true); - } - } + /** + * Announces the current tabbing constraint. + */ + announceTabbingConstraint() { + const strings = this.options.strings; + Drupal.announce( + Drupal.formatString(strings.tabbingConstrained, { + '@contextualsCount': Drupal.formatPlural( + Drupal.contextual.collection.length, + '@count contextual link', + '@count contextual links', + ), + }), + ); + Drupal.announce(strings.pressEsc); + }, - }); -})(jQuery, Drupal, Backbone, _);
\ No newline at end of file + /** + * Responds to esc and tab key press events. + * + * @param {jQuery.Event} event + * The keypress event. + */ + onKeypress(event) { + // The first tab key press is tracked so that an announcement about + // tabbing constraints can be raised if edit mode is enabled when the page + // is loaded. + if ( + !this.announcedOnce && + event.keyCode === 9 && + !this.model.get('isViewing') + ) { + this.announceTabbingConstraint(); + // Set announce to true so that this conditional block won't run again. + this.announcedOnce = true; + } + // Respond to the ESC key. Exit out of edit mode. + if (event.keyCode === 27) { + this.model.set('isViewing', true); + } + }, + }, + ); +})(jQuery, Drupal, Backbone, _); diff --git a/core/modules/contextual/js/toolbar/views/VisualView.es6.js b/core/modules/contextual/js/toolbar/views/VisualView.es6.js deleted file mode 100644 index b939af8b25b..00000000000 --- a/core/modules/contextual/js/toolbar/views/VisualView.es6.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @file - * A Backbone View that provides the visual view of the edit mode toggle. - */ - -(function (Drupal, Backbone) { - /** - * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no - * replacement. - */ - Drupal.contextualToolbar.VisualView = Backbone.View.extend( - /** @lends Drupal.contextualToolbar.VisualView# */ { - /** - * Events for the Backbone view. - * - * @return {object} - * A mapping of events to be used in the view. - */ - events() { - // Prevents delay and simulated mouse events. - const touchEndToClick = function (event) { - event.preventDefault(); - event.target.click(); - }; - - return { - click() { - this.model.set('isViewing', !this.model.get('isViewing')); - }, - touchend: touchEndToClick, - }; - }, - - /** - * Renders the visual view of the edit mode toggle. - * - * Listens to mouse & touch and handles edit mode toggle interactions. - * - * @constructs - * - * @augments Backbone.View - */ - initialize() { - this.listenTo(this.model, 'change', this.render); - this.listenTo(this.model, 'change:isViewing', this.persist); - }, - - /** - * {@inheritdoc} - * - * @return {Drupal.contextualToolbar.VisualView} - * The current contextual toolbar visual view. - */ - render() { - // Render the visibility. - this.$el.toggleClass('hidden', !this.model.get('isVisible')); - // Render the state. - this.$el - .find('button') - .toggleClass('is-active', !this.model.get('isViewing')); - - return this; - }, - - /** - * Model change handler; persists the isViewing value to localStorage. - * - * `isViewing === true` is the default, so only stores in localStorage when - * it's not the default value (i.e. false). - * - * @param {Drupal.contextualToolbar.StateModel} model - * A {@link Drupal.contextualToolbar.StateModel} model. - * @param {bool} isViewing - * The value of the isViewing attribute in the model. - */ - persist(model, isViewing) { - if (!isViewing) { - localStorage.setItem('Drupal.contextualToolbar.isViewing', 'false'); - } else { - localStorage.removeItem('Drupal.contextualToolbar.isViewing'); - } - }, - }, - ); -})(Drupal, Backbone); diff --git a/core/modules/contextual/js/toolbar/views/VisualView.js b/core/modules/contextual/js/toolbar/views/VisualView.js index 556c439eee8..b939af8b25b 100644 --- a/core/modules/contextual/js/toolbar/views/VisualView.js +++ b/core/modules/contextual/js/toolbar/views/VisualView.js @@ -1,45 +1,85 @@ /** -* DO NOT EDIT THIS FILE. -* See the following change record for more information, -* https://www.drupal.org/node/2815083 -* @preserve -**/ + * @file + * A Backbone View that provides the visual view of the edit mode toggle. + */ (function (Drupal, Backbone) { - Drupal.contextualToolbar.VisualView = Backbone.View.extend({ - events() { - const touchEndToClick = function (event) { - event.preventDefault(); - event.target.click(); - }; + /** + * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no + * replacement. + */ + Drupal.contextualToolbar.VisualView = Backbone.View.extend( + /** @lends Drupal.contextualToolbar.VisualView# */ { + /** + * Events for the Backbone view. + * + * @return {object} + * A mapping of events to be used in the view. + */ + events() { + // Prevents delay and simulated mouse events. + const touchEndToClick = function (event) { + event.preventDefault(); + event.target.click(); + }; - return { - click() { - this.model.set('isViewing', !this.model.get('isViewing')); - }, + return { + click() { + this.model.set('isViewing', !this.model.get('isViewing')); + }, + touchend: touchEndToClick, + }; + }, - touchend: touchEndToClick - }; - }, + /** + * Renders the visual view of the edit mode toggle. + * + * Listens to mouse & touch and handles edit mode toggle interactions. + * + * @constructs + * + * @augments Backbone.View + */ + initialize() { + this.listenTo(this.model, 'change', this.render); + this.listenTo(this.model, 'change:isViewing', this.persist); + }, - initialize() { - this.listenTo(this.model, 'change', this.render); - this.listenTo(this.model, 'change:isViewing', this.persist); - }, + /** + * {@inheritdoc} + * + * @return {Drupal.contextualToolbar.VisualView} + * The current contextual toolbar visual view. + */ + render() { + // Render the visibility. + this.$el.toggleClass('hidden', !this.model.get('isVisible')); + // Render the state. + this.$el + .find('button') + .toggleClass('is-active', !this.model.get('isViewing')); - render() { - this.$el.toggleClass('hidden', !this.model.get('isVisible')); - this.$el.find('button').toggleClass('is-active', !this.model.get('isViewing')); - return this; - }, + return this; + }, - persist(model, isViewing) { - if (!isViewing) { - localStorage.setItem('Drupal.contextualToolbar.isViewing', 'false'); - } else { - localStorage.removeItem('Drupal.contextualToolbar.isViewing'); - } - } - - }); -})(Drupal, Backbone);
\ No newline at end of file + /** + * Model change handler; persists the isViewing value to localStorage. + * + * `isViewing === true` is the default, so only stores in localStorage when + * it's not the default value (i.e. false). + * + * @param {Drupal.contextualToolbar.StateModel} model + * A {@link Drupal.contextualToolbar.StateModel} model. + * @param {bool} isViewing + * The value of the isViewing attribute in the model. + */ + persist(model, isViewing) { + if (!isViewing) { + localStorage.setItem('Drupal.contextualToolbar.isViewing', 'false'); + } else { + localStorage.removeItem('Drupal.contextualToolbar.isViewing'); + } + }, + }, + ); +})(Drupal, Backbone); diff --git a/core/modules/contextual/js/views/AuralView.es6.js b/core/modules/contextual/js/views/AuralView.es6.js deleted file mode 100644 index 1e317242c1e..00000000000 --- a/core/modules/contextual/js/views/AuralView.es6.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @file - * A Backbone View that provides the aural view of a contextual link. - */ - -(function (Drupal, Backbone) { - /** - * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no - * replacement. - */ - Drupal.contextual.AuralView = Backbone.View.extend( - /** @lends Drupal.contextual.AuralView# */ { - /** - * Renders the aural view of a contextual link (i.e. screen reader support). - * - * @constructs - * - * @augments Backbone.View - * - * @param {object} options - * Options for the view. - */ - initialize(options) { - this.options = options; - - this.listenTo(this.model, 'change', this.render); - - // Initial render. - this.render(); - }, - - /** - * {@inheritdoc} - */ - render() { - const isOpen = this.model.get('isOpen'); - - // Set the hidden property of the links. - this.$el.find('.contextual-links').prop('hidden', !isOpen); - - // Update the view of the trigger. - const $trigger = this.$el.find('.trigger'); - $trigger - .each((index, element) => { - element.textContent = Drupal.t( - '@action @title configuration options', - { - '@action': !isOpen - ? this.options.strings.open - : this.options.strings.close, - '@title': this.model.get('title'), - }, - ); - }) - .attr('aria-pressed', isOpen); - }, - }, - ); -})(Drupal, Backbone); diff --git a/core/modules/contextual/js/views/AuralView.js b/core/modules/contextual/js/views/AuralView.js index 49c8dcb265e..1e317242c1e 100644 --- a/core/modules/contextual/js/views/AuralView.js +++ b/core/modules/contextual/js/views/AuralView.js @@ -1,29 +1,59 @@ /** -* DO NOT EDIT THIS FILE. -* See the following change record for more information, -* https://www.drupal.org/node/2815083 -* @preserve -**/ + * @file + * A Backbone View that provides the aural view of a contextual link. + */ (function (Drupal, Backbone) { - Drupal.contextual.AuralView = Backbone.View.extend({ - initialize(options) { - this.options = options; - this.listenTo(this.model, 'change', this.render); - this.render(); - }, + /** + * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no + * replacement. + */ + Drupal.contextual.AuralView = Backbone.View.extend( + /** @lends Drupal.contextual.AuralView# */ { + /** + * Renders the aural view of a contextual link (i.e. screen reader support). + * + * @constructs + * + * @augments Backbone.View + * + * @param {object} options + * Options for the view. + */ + initialize(options) { + this.options = options; + + this.listenTo(this.model, 'change', this.render); + + // Initial render. + this.render(); + }, - render() { - const isOpen = this.model.get('isOpen'); - this.$el.find('.contextual-links').prop('hidden', !isOpen); - const $trigger = this.$el.find('.trigger'); - $trigger.each((index, element) => { - element.textContent = Drupal.t('@action @title configuration options', { - '@action': !isOpen ? this.options.strings.open : this.options.strings.close, - '@title': this.model.get('title') - }); - }).attr('aria-pressed', isOpen); - } + /** + * {@inheritdoc} + */ + render() { + const isOpen = this.model.get('isOpen'); - }); -})(Drupal, Backbone);
\ No newline at end of file + // Set the hidden property of the links. + this.$el.find('.contextual-links').prop('hidden', !isOpen); + + // Update the view of the trigger. + const $trigger = this.$el.find('.trigger'); + $trigger + .each((index, element) => { + element.textContent = Drupal.t( + '@action @title configuration options', + { + '@action': !isOpen + ? this.options.strings.open + : this.options.strings.close, + '@title': this.model.get('title'), + }, + ); + }) + .attr('aria-pressed', isOpen); + }, + }, + ); +})(Drupal, Backbone); diff --git a/core/modules/contextual/js/views/KeyboardView.es6.js b/core/modules/contextual/js/views/KeyboardView.es6.js deleted file mode 100644 index d7bb101835c..00000000000 --- a/core/modules/contextual/js/views/KeyboardView.es6.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @file - * A Backbone View that provides keyboard interaction for a contextual link. - */ - -(function (Drupal, Backbone) { - /** - * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no - * replacement. - */ - Drupal.contextual.KeyboardView = Backbone.View.extend( - /** @lends Drupal.contextual.KeyboardView# */ { - /** - * @type {object} - */ - events: { - 'focus .trigger': 'focus', - 'focus .contextual-links a': 'focus', - 'blur .trigger': function () { - this.model.blur(); - }, - 'blur .contextual-links a': function () { - // Set up a timeout to allow a user to tab between the trigger and the - // contextual links without the menu dismissing. - const that = this; - this.timer = window.setTimeout(() => { - that.model.close().blur(); - }, 150); - }, - }, - - /** - * Provides keyboard interaction for a contextual link. - * - * @constructs - * - * @augments Backbone.View - */ - initialize() { - /** - * The timer is used to create a delay before dismissing the contextual - * links on blur. This is only necessary when keyboard users tab into - * contextual links without edit mode (i.e. without TabbingManager). - * That means that if we decide to disable tabbing of contextual links - * without edit mode, all this timer logic can go away. - * - * @type {NaN|number} - */ - this.timer = NaN; - }, - - /** - * Sets focus on the model; Clears the timer that dismisses the links. - */ - focus() { - // Clear the timeout that might have been set by blurring a link. - window.clearTimeout(this.timer); - this.model.focus(); - }, - }, - ); -})(Drupal, Backbone); diff --git a/core/modules/contextual/js/views/KeyboardView.js b/core/modules/contextual/js/views/KeyboardView.js index 3f10479b351..d7bb101835c 100644 --- a/core/modules/contextual/js/views/KeyboardView.js +++ b/core/modules/contextual/js/views/KeyboardView.js @@ -1,34 +1,62 @@ /** -* DO NOT EDIT THIS FILE. -* See the following change record for more information, -* https://www.drupal.org/node/2815083 -* @preserve -**/ + * @file + * A Backbone View that provides keyboard interaction for a contextual link. + */ (function (Drupal, Backbone) { - Drupal.contextual.KeyboardView = Backbone.View.extend({ - events: { - 'focus .trigger': 'focus', - 'focus .contextual-links a': 'focus', - 'blur .trigger': function () { - this.model.blur(); + /** + * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no + * replacement. + */ + Drupal.contextual.KeyboardView = Backbone.View.extend( + /** @lends Drupal.contextual.KeyboardView# */ { + /** + * @type {object} + */ + events: { + 'focus .trigger': 'focus', + 'focus .contextual-links a': 'focus', + 'blur .trigger': function () { + this.model.blur(); + }, + 'blur .contextual-links a': function () { + // Set up a timeout to allow a user to tab between the trigger and the + // contextual links without the menu dismissing. + const that = this; + this.timer = window.setTimeout(() => { + that.model.close().blur(); + }, 150); + }, }, - 'blur .contextual-links a': function () { - const that = this; - this.timer = window.setTimeout(() => { - that.model.close().blur(); - }, 150); - } - }, - - initialize() { - this.timer = NaN; - }, - focus() { - window.clearTimeout(this.timer); - this.model.focus(); - } + /** + * Provides keyboard interaction for a contextual link. + * + * @constructs + * + * @augments Backbone.View + */ + initialize() { + /** + * The timer is used to create a delay before dismissing the contextual + * links on blur. This is only necessary when keyboard users tab into + * contextual links without edit mode (i.e. without TabbingManager). + * That means that if we decide to disable tabbing of contextual links + * without edit mode, all this timer logic can go away. + * + * @type {NaN|number} + */ + this.timer = NaN; + }, - }); -})(Drupal, Backbone);
\ No newline at end of file + /** + * Sets focus on the model; Clears the timer that dismisses the links. + */ + focus() { + // Clear the timeout that might have been set by blurring a link. + window.clearTimeout(this.timer); + this.model.focus(); + }, + }, + ); +})(Drupal, Backbone); diff --git a/core/modules/contextual/js/views/RegionView.es6.js b/core/modules/contextual/js/views/RegionView.es6.js deleted file mode 100644 index 08ec5880bea..00000000000 --- a/core/modules/contextual/js/views/RegionView.es6.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @file - * A Backbone View that renders the visual view of a contextual region element. - */ - -(function (Drupal, Backbone) { - /** - * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no - * replacement. - */ - Drupal.contextual.RegionView = Backbone.View.extend( - /** @lends Drupal.contextual.RegionView# */ { - /** - * Events for the Backbone view. - * - * @return {object} - * A mapping of events to be used in the view. - */ - events() { - // Used for tracking the presence of touch events. When true, the - // mousemove and mouseenter event handlers are effectively disabled. - // This is used instead of preventDefault() on touchstart as some - // touchstart events are not cancelable. - let touchStart = false; - return { - touchstart() { - // Set to true so the mouseenter and mouseleave events that follow - // know to not execute any hover related logic. - touchStart = true; - }, - mouseenter() { - if (!touchStart) { - this.model.set('regionIsHovered', true); - } - }, - mouseleave() { - if (!touchStart) { - this.model.close().blur().set('regionIsHovered', false); - } - }, - mousemove() { - // Because there are scenarios where there are both touchscreens - // and pointer devices, the touchStart flag should be set back to - // false after mouseenter and mouseleave complete. It will be set to - // true if another touchstart event occurs. - touchStart = false; - }, - }; - }, - - /** - * Renders the visual view of a contextual region element. - * - * @constructs - * - * @augments Backbone.View - */ - initialize() { - this.listenTo(this.model, 'change:hasFocus', this.render); - }, - - /** - * {@inheritdoc} - * - * @return {Drupal.contextual.RegionView} - * The current contextual region view. - */ - render() { - this.$el.toggleClass('focus', this.model.get('hasFocus')); - - return this; - }, - }, - ); -})(Drupal, Backbone); diff --git a/core/modules/contextual/js/views/RegionView.js b/core/modules/contextual/js/views/RegionView.js index 7edac95a36e..08ec5880bea 100644 --- a/core/modules/contextual/js/views/RegionView.js +++ b/core/modules/contextual/js/views/RegionView.js @@ -1,46 +1,75 @@ /** -* DO NOT EDIT THIS FILE. -* See the following change record for more information, -* https://www.drupal.org/node/2815083 -* @preserve -**/ + * @file + * A Backbone View that renders the visual view of a contextual region element. + */ (function (Drupal, Backbone) { - Drupal.contextual.RegionView = Backbone.View.extend({ - events() { - let touchStart = false; - return { - touchstart() { - touchStart = true; - }, + /** + * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no + * replacement. + */ + Drupal.contextual.RegionView = Backbone.View.extend( + /** @lends Drupal.contextual.RegionView# */ { + /** + * Events for the Backbone view. + * + * @return {object} + * A mapping of events to be used in the view. + */ + events() { + // Used for tracking the presence of touch events. When true, the + // mousemove and mouseenter event handlers are effectively disabled. + // This is used instead of preventDefault() on touchstart as some + // touchstart events are not cancelable. + let touchStart = false; + return { + touchstart() { + // Set to true so the mouseenter and mouseleave events that follow + // know to not execute any hover related logic. + touchStart = true; + }, + mouseenter() { + if (!touchStart) { + this.model.set('regionIsHovered', true); + } + }, + mouseleave() { + if (!touchStart) { + this.model.close().blur().set('regionIsHovered', false); + } + }, + mousemove() { + // Because there are scenarios where there are both touchscreens + // and pointer devices, the touchStart flag should be set back to + // false after mouseenter and mouseleave complete. It will be set to + // true if another touchstart event occurs. + touchStart = false; + }, + }; + }, - mouseenter() { - if (!touchStart) { - this.model.set('regionIsHovered', true); - } - }, + /** + * Renders the visual view of a contextual region element. + * + * @constructs + * + * @augments Backbone.View + */ + initialize() { + this.listenTo(this.model, 'change:hasFocus', this.render); + }, - mouseleave() { - if (!touchStart) { - this.model.close().blur().set('regionIsHovered', false); - } - }, + /** + * {@inheritdoc} + * + * @return {Drupal.contextual.RegionView} + * The current contextual region view. + */ + render() { + this.$el.toggleClass('focus', this.model.get('hasFocus')); - mousemove() { - touchStart = false; - } - - }; - }, - - initialize() { - this.listenTo(this.model, 'change:hasFocus', this.render); + return this; + }, }, - - render() { - this.$el.toggleClass('focus', this.model.get('hasFocus')); - return this; - } - - }); -})(Drupal, Backbone);
\ No newline at end of file + ); +})(Drupal, Backbone); diff --git a/core/modules/contextual/js/views/VisualView.es6.js b/core/modules/contextual/js/views/VisualView.es6.js deleted file mode 100644 index 7f984cc8170..00000000000 --- a/core/modules/contextual/js/views/VisualView.es6.js +++ /dev/null @@ -1,109 +0,0 @@ -/** - * @file - * A Backbone View that provides the visual view of a contextual link. - */ - -(function (Drupal, Backbone) { - /** - * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no - * replacement. - */ - Drupal.contextual.VisualView = Backbone.View.extend( - /** @lends Drupal.contextual.VisualView# */ { - /** - * Events for the Backbone view. - * - * @return {object} - * A mapping of events to be used in the view. - */ - events() { - // Prevents delay and simulated mouse events. - const touchEndToClick = function (event) { - event.preventDefault(); - event.target.click(); - }; - - // Used for tracking the presence of touch events. When true, the - // mousemove and mouseenter event handlers are effectively disabled. - // This is used instead of preventDefault() on touchstart as some - // touchstart events are not cancelable. - let touchStart = false; - - return { - touchstart() { - // Set to true so the mouseenter events that follows knows to not - // execute any hover related logic. - touchStart = true; - }, - mouseenter() { - // We only want mouse hover events on non-touch. - if (!touchStart) { - this.model.focus(); - } - }, - mousemove() { - // Because there are scenarios where there are both touchscreens - // and pointer devices, the touchStart flag should be set back to - // false after mouseenter and mouseleave complete. It will be set to - // true if another touchstart event occurs. - touchStart = false; - }, - 'click .trigger': function () { - this.model.toggleOpen(); - }, - 'touchend .trigger': touchEndToClick, - 'click .contextual-links a': function () { - this.model.close().blur(); - }, - 'touchend .contextual-links a': touchEndToClick, - }; - }, - - /** - * Renders the visual view of a contextual link. Listens to mouse & touch. - * - * @constructs - * - * @augments Backbone.View - */ - initialize() { - this.listenTo(this.model, 'change', this.render); - }, - - /** - * {@inheritdoc} - * - * @return {Drupal.contextual.VisualView} - * The current contextual visual view. - */ - render() { - const isOpen = this.model.get('isOpen'); - // The trigger should be visible when: - // - the mouse hovered over the region, - // - the trigger is locked, - // - and for as long as the contextual menu is open. - const isVisible = - this.model.get('isLocked') || - this.model.get('regionIsHovered') || - isOpen; - - this.$el - // The open state determines if the links are visible. - .toggleClass('open', isOpen) - // Update the visibility of the trigger. - .find('.trigger') - .toggleClass('visually-hidden', !isVisible); - - // Nested contextual region handling: hide any nested contextual triggers. - if ('isOpen' in this.model.changed) { - this.$el - .closest('.contextual-region') - .find('.contextual .trigger:not(:first)') - .toggle(!isOpen); - } - - return this; - }, - }, - ); -})(Drupal, Backbone); diff --git a/core/modules/contextual/js/views/VisualView.js b/core/modules/contextual/js/views/VisualView.js index d571ac02373..7f984cc8170 100644 --- a/core/modules/contextual/js/views/VisualView.js +++ b/core/modules/contextual/js/views/VisualView.js @@ -1,60 +1,109 @@ /** -* DO NOT EDIT THIS FILE. -* See the following change record for more information, -* https://www.drupal.org/node/2815083 -* @preserve -**/ + * @file + * A Backbone View that provides the visual view of a contextual link. + */ (function (Drupal, Backbone) { - Drupal.contextual.VisualView = Backbone.View.extend({ - events() { - const touchEndToClick = function (event) { - event.preventDefault(); - event.target.click(); - }; - - let touchStart = false; - return { - touchstart() { - touchStart = true; - }, - - mouseenter() { - if (!touchStart) { - this.model.focus(); - } - }, - - mousemove() { - touchStart = false; - }, - - 'click .trigger': function () { - this.model.toggleOpen(); - }, - 'touchend .trigger': touchEndToClick, - 'click .contextual-links a': function () { - this.model.close().blur(); - }, - 'touchend .contextual-links a': touchEndToClick - }; - }, + /** + * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. There is no + * replacement. + */ + Drupal.contextual.VisualView = Backbone.View.extend( + /** @lends Drupal.contextual.VisualView# */ { + /** + * Events for the Backbone view. + * + * @return {object} + * A mapping of events to be used in the view. + */ + events() { + // Prevents delay and simulated mouse events. + const touchEndToClick = function (event) { + event.preventDefault(); + event.target.click(); + }; - initialize() { - this.listenTo(this.model, 'change', this.render); - }, + // Used for tracking the presence of touch events. When true, the + // mousemove and mouseenter event handlers are effectively disabled. + // This is used instead of preventDefault() on touchstart as some + // touchstart events are not cancelable. + let touchStart = false; + + return { + touchstart() { + // Set to true so the mouseenter events that follows knows to not + // execute any hover related logic. + touchStart = true; + }, + mouseenter() { + // We only want mouse hover events on non-touch. + if (!touchStart) { + this.model.focus(); + } + }, + mousemove() { + // Because there are scenarios where there are both touchscreens + // and pointer devices, the touchStart flag should be set back to + // false after mouseenter and mouseleave complete. It will be set to + // true if another touchstart event occurs. + touchStart = false; + }, + 'click .trigger': function () { + this.model.toggleOpen(); + }, + 'touchend .trigger': touchEndToClick, + 'click .contextual-links a': function () { + this.model.close().blur(); + }, + 'touchend .contextual-links a': touchEndToClick, + }; + }, - render() { - const isOpen = this.model.get('isOpen'); - const isVisible = this.model.get('isLocked') || this.model.get('regionIsHovered') || isOpen; - this.$el.toggleClass('open', isOpen).find('.trigger').toggleClass('visually-hidden', !isVisible); + /** + * Renders the visual view of a contextual link. Listens to mouse & touch. + * + * @constructs + * + * @augments Backbone.View + */ + initialize() { + this.listenTo(this.model, 'change', this.render); + }, - if ('isOpen' in this.model.changed) { - this.$el.closest('.contextual-region').find('.contextual .trigger:not(:first)').toggle(!isOpen); - } + /** + * {@inheritdoc} + * + * @return {Drupal.contextual.VisualView} + * The current contextual visual view. + */ + render() { + const isOpen = this.model.get('isOpen'); + // The trigger should be visible when: + // - the mouse hovered over the region, + // - the trigger is locked, + // - and for as long as the contextual menu is open. + const isVisible = + this.model.get('isLocked') || + this.model.get('regionIsHovered') || + isOpen; - return this; - } + this.$el + // The open state determines if the links are visible. + .toggleClass('open', isOpen) + // Update the visibility of the trigger. + .find('.trigger') + .toggleClass('visually-hidden', !isVisible); - }); -})(Drupal, Backbone);
\ No newline at end of file + // Nested contextual region handling: hide any nested contextual triggers. + if ('isOpen' in this.model.changed) { + this.$el + .closest('.contextual-region') + .find('.contextual .trigger:not(:first)') + .toggle(!isOpen); + } + + return this; + }, + }, + ); +})(Drupal, Backbone); |