diff options
author | Alex Pott <alex.a.pott@googlemail.com> | 2017-05-19 23:12:53 +0100 |
---|---|---|
committer | Alex Pott <alex.a.pott@googlemail.com> | 2017-05-19 23:12:53 +0100 |
commit | 8287017e034bc323dec1d86b3f37a804aa082d2d (patch) | |
tree | ebd8ff908859b0e1cc4319392da94e8f68033321 /core/modules/contextual/js/contextual.es6.js | |
parent | 9a0e9a649ac8078ce6e5f6089749a1115bdda06b (diff) | |
download | drupal-8287017e034bc323dec1d86b3f37a804aa082d2d.tar.gz drupal-8287017e034bc323dec1d86b3f37a804aa082d2d.zip |
Issue #2818825 by drpal, nod_, droplet, cilefen: Rename all JS files to *.es6.js and compile them
Diffstat (limited to 'core/modules/contextual/js/contextual.es6.js')
-rw-r--r-- | core/modules/contextual/js/contextual.es6.js | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/core/modules/contextual/js/contextual.es6.js b/core/modules/contextual/js/contextual.es6.js new file mode 100644 index 000000000000..558ea105cc2f --- /dev/null +++ b/core/modules/contextual/js/contextual.es6.js @@ -0,0 +1,256 @@ +/** + * @file + * Attaches behaviors for the Contextual module. + */ + +(function ($, Drupal, drupalSettings, _, Backbone, JSON, storage) { + + 'use strict'; + + var 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. + var cachedPermissionsHash = storage.getItem('Drupal.contextual.permissionsHash'); + var permissionsHash = drupalSettings.user.permissionsHash; + if (cachedPermissionsHash !== permissionsHash) { + if (typeof permissionsHash === 'string') { + _.chain(storage).keys().each(function (key) { + if (key.substring(0, 18) === 'Drupal.contextual.') { + storage.removeItem(key); + } + }); + } + storage.setItem('Drupal.contextual.permissionsHash', permissionsHash); + } + + /** + * 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) { + var $region = $contextual.closest('.contextual-region'); + var 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. + var destination = 'destination=' + Drupal.encodePath(drupalSettings.path.currentPath); + $contextual.find('.contextual-links a').each(function () { + var url = this.getAttribute('href'); + var glue = (url.indexOf('?') === -1) ? '?' : '&'; + this.setAttribute('href', url + glue + destination); + }); + + // Create a model and the appropriate views. + var model = new contextual.StateModel({ + title: $region.find('h2').eq(0).text().trim() + }); + var viewOptions = $.extend({el: $contextual, model: 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: 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', { + $el: $contextual, + $region: $region, + model: model + }); + + // Fix visual collisions between contextual link triggers. + adjustIfNestedAndOverlapping($contextual); + } + + /** + * 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) { + var $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. + var firstTop = $contextuals.eq(0).offset().top; + var secondTop = $contextuals.eq(1).offset().top; + if (firstTop === secondTop) { + var $nestedContextual = $contextuals.eq(1); + + // Retrieve height of nested contextual link. + var height = 0; + var $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}); + } + } + + /** + * 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: function (context) { + var $context = $(context); + + // Find all contextual links placeholders, if any. + var $placeholders = $context.find('[data-contextual-id]').once('contextual-render'); + if ($placeholders.length === 0) { + return; + } + + // Collect the IDs for all contextual links placeholders. + var ids = []; + $placeholders.each(function () { + ids.push($(this).attr('data-contextual-id')); + }); + + // Update all contextual links placeholders whose HTML is cached. + var uncachedIDs = _.filter(ids, function initIfCached(contextualID) { + var html = storage.getItem('Drupal.contextual.' + contextualID); + 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(function () { + initContextual($context.find('[data-contextual-id="' + contextualID + '"]'), html); + }); + return false; + } + return true; + }); + + // 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}, + dataType: 'json', + success: function (results) { + _.each(results, function (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 (var i = 0; i < $placeholders.length; i++) { + initContextual($placeholders.eq(i), html); + } + } + }); + } + }); + } + } + }; + + /** + * Namespace for contextual related functionality. + * + * @namespace + */ + Drupal.contextual = { + + /** + * The {@link Drupal.contextual.View} instances associated with each list + * element of contextual links. + * + * @type {Array} + */ + views: [], + + /** + * The {@link Drupal.contextual.RegionView} instances associated with each + * contextual region element. + * + * @type {Array} + */ + regionViews: [] + }; + + /** + * A Backbone.Collection of {@link Drupal.contextual.StateModel} instances. + * + * @type {Backbone.Collection} + */ + 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>'; + }; + +})(jQuery, Drupal, drupalSettings, _, Backbone, window.JSON, window.sessionStorage); |