X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=web%2Fcore%2Fmodules%2Ftoolbar%2Fjs%2Ftoolbar.es6.js;fp=web%2Fcore%2Fmodules%2Ftoolbar%2Fjs%2Ftoolbar.es6.js;h=4fdf090fbedb47ef234b6e6f600da09bcc04d99b;hp=0000000000000000000000000000000000000000;hb=9917807b03b64faf00f6a1f29dcb6eafc454efa5;hpb=aea91e65e895364e460983b890e295aa5d5540a5 diff --git a/web/core/modules/toolbar/js/toolbar.es6.js b/web/core/modules/toolbar/js/toolbar.es6.js new file mode 100644 index 000000000..4fdf090fb --- /dev/null +++ b/web/core/modules/toolbar/js/toolbar.es6.js @@ -0,0 +1,260 @@ +/** + * @file + * Defines the behavior of the Drupal administration toolbar. + */ + +(function ($, Drupal, drupalSettings) { + // Merge run-time settings with the defaults. + const options = $.extend( + { + breakpoints: { + 'toolbar.narrow': '', + 'toolbar.standard': '', + 'toolbar.wide': '', + }, + }, + drupalSettings.toolbar, + // Merge strings on top of drupalSettings so that they are not mutable. + { + strings: { + horizontal: Drupal.t('Horizontal orientation'), + vertical: Drupal.t('Vertical orientation'), + }, + }, + ); + + /** + * Registers tabs with the toolbar. + * + * The Drupal toolbar allows modules to register top-level tabs. These may + * point directly to a resource or toggle the visibility of a tray. + * + * Modules register tabs with hook_toolbar(). + * + * @type {Drupal~behavior} + * + * @prop {Drupal~behaviorAttach} attach + * Attaches the toolbar rendering functionality to the toolbar element. + */ + Drupal.behaviors.toolbar = { + attach(context) { + // Verify that the user agent understands media queries. Complex admin + // toolbar layouts require media query support. + if (!window.matchMedia('only screen').matches) { + return; + } + // Process the administrative toolbar. + $(context).find('#toolbar-administration').once('toolbar').each(function () { + // Establish the toolbar models and views. + const model = Drupal.toolbar.models.toolbarModel = new Drupal.toolbar.ToolbarModel({ + locked: JSON.parse(localStorage.getItem('Drupal.toolbar.trayVerticalLocked')), + activeTab: document.getElementById(JSON.parse(localStorage.getItem('Drupal.toolbar.activeTabID'))), + height: $('#toolbar-administration').outerHeight(), + }); + + // Attach a listener to the configured media query breakpoints. + // Executes it before Drupal.toolbar.views to avoid extra rendering. + for (const label in options.breakpoints) { + if (options.breakpoints.hasOwnProperty(label)) { + const mq = options.breakpoints[label]; + const mql = Drupal.toolbar.mql[label] = window.matchMedia(mq); + // Curry the model and the label of the media query breakpoint to + // the mediaQueryChangeHandler function. + mql.addListener(Drupal.toolbar.mediaQueryChangeHandler.bind(null, model, label)); + // Fire the mediaQueryChangeHandler for each configured breakpoint + // so that they process once. + Drupal.toolbar.mediaQueryChangeHandler.call(null, model, label, mql); + } + } + + Drupal.toolbar.views.toolbarVisualView = new Drupal.toolbar.ToolbarVisualView({ + el: this, + model, + strings: options.strings, + }); + Drupal.toolbar.views.toolbarAuralView = new Drupal.toolbar.ToolbarAuralView({ + el: this, + model, + strings: options.strings, + }); + Drupal.toolbar.views.bodyVisualView = new Drupal.toolbar.BodyVisualView({ + el: this, + model, + }); + + // Force layout render to fix mobile view. Only needed on load, not + // for every media query match. + model.trigger('change:isFixed', model, model.get('isFixed')); + model.trigger('change:activeTray', model, model.get('activeTray')); + + // Render collapsible menus. + const menuModel = Drupal.toolbar.models.menuModel = new Drupal.toolbar.MenuModel(); + Drupal.toolbar.views.menuVisualView = new Drupal.toolbar.MenuVisualView({ + el: $(this).find('.toolbar-menu-administration').get(0), + model: menuModel, + strings: options.strings, + }); + + // Handle the resolution of Drupal.toolbar.setSubtrees. + // This is handled with a deferred so that the function may be invoked + // asynchronously. + Drupal.toolbar.setSubtrees.done((subtrees) => { + menuModel.set('subtrees', subtrees); + const theme = drupalSettings.ajaxPageState.theme; + localStorage.setItem(`Drupal.toolbar.subtrees.${theme}`, JSON.stringify(subtrees)); + // Indicate on the toolbarModel that subtrees are now loaded. + model.set('areSubtreesLoaded', true); + }); + + // Trigger an initial attempt to load menu subitems. This first attempt + // is made after the media query handlers have had an opportunity to + // process. The toolbar starts in the vertical orientation by default, + // unless the viewport is wide enough to accommodate a horizontal + // orientation. Thus we give the Toolbar a chance to determine if it + // should be set to horizontal orientation before attempting to load + // menu subtrees. + Drupal.toolbar.views.toolbarVisualView.loadSubtrees(); + + $(document) + // Update the model when the viewport offset changes. + .on('drupalViewportOffsetChange.toolbar', (event, offsets) => { + model.set('offsets', offsets); + }); + + // Broadcast model changes to other modules. + model + .on('change:orientation', (model, orientation) => { + $(document).trigger('drupalToolbarOrientationChange', orientation); + }) + .on('change:activeTab', (model, tab) => { + $(document).trigger('drupalToolbarTabChange', tab); + }) + .on('change:activeTray', (model, tray) => { + $(document).trigger('drupalToolbarTrayChange', tray); + }); + + // If the toolbar's orientation is horizontal and no active tab is + // defined then show the tray of the first toolbar tab by default (but + // not the first 'Home' toolbar tab). + if (Drupal.toolbar.models.toolbarModel.get('orientation') === 'horizontal' && Drupal.toolbar.models.toolbarModel.get('activeTab') === null) { + Drupal.toolbar.models.toolbarModel.set({ + activeTab: $('.toolbar-bar .toolbar-tab:not(.home-toolbar-tab) a').get(0), + }); + } + }); + }, + }; + + /** + * Toolbar methods of Backbone objects. + * + * @namespace + */ + Drupal.toolbar = { + + /** + * A hash of View instances. + * + * @type {object.} + */ + views: {}, + + /** + * A hash of Model instances. + * + * @type {object.} + */ + models: {}, + + /** + * A hash of MediaQueryList objects tracked by the toolbar. + * + * @type {object.} + */ + mql: {}, + + /** + * Accepts a list of subtree menu elements. + * + * A deferred object that is resolved by an inlined JavaScript callback. + * + * @type {jQuery.Deferred} + * + * @see toolbar_subtrees_jsonp(). + */ + setSubtrees: new $.Deferred(), + + /** + * Respond to configured narrow media query changes. + * + * @param {Drupal.toolbar.ToolbarModel} model + * A toolbar model + * @param {string} label + * Media query label. + * @param {object} mql + * A MediaQueryList object. + */ + mediaQueryChangeHandler(model, label, mql) { + switch (label) { + case 'toolbar.narrow': + model.set({ + isOriented: mql.matches, + isTrayToggleVisible: false, + }); + // If the toolbar doesn't have an explicit orientation yet, or if the + // narrow media query doesn't match then set the orientation to + // vertical. + if (!mql.matches || !model.get('orientation')) { + model.set({ orientation: 'vertical' }, { validate: true }); + } + break; + + case 'toolbar.standard': + model.set({ + isFixed: mql.matches, + }); + break; + + case 'toolbar.wide': + model.set({ + orientation: ((mql.matches && !model.get('locked')) ? 'horizontal' : 'vertical'), + }, { validate: true }); + // The tray orientation toggle visibility does not need to be + // validated. + model.set({ + isTrayToggleVisible: mql.matches, + }); + break; + + default: + break; + } + }, + }; + + /** + * A toggle is an interactive element often bound to a click handler. + * + * @return {string} + * A string representing a DOM fragment. + */ + Drupal.theme.toolbarOrientationToggle = function () { + return '
' + + '' + + '
'; + }; + + /** + * Ajax command to set the toolbar subtrees. + * + * @param {Drupal.Ajax} ajax + * {@link Drupal.Ajax} object created by {@link Drupal.ajax}. + * @param {object} response + * JSON response from the Ajax request. + * @param {number} [status] + * XMLHttpRequest status. + */ + Drupal.AjaxCommands.prototype.setToolbarSubtrees = function (ajax, response, status) { + Drupal.toolbar.setSubtrees.resolve(response.subtrees); + }; +}(jQuery, Drupal, drupalSettings));