/** * @file toolbar.js * * Defines the behavior of the Drupal administration toolbar. */ (function ($, Drupal, drupalSettings) { "use strict"; // Merge run-time settings with the defaults. var options = $.extend( { breakpoints: { 'module.toolbar.narrow': '', 'module.toolbar.standard': '', 'module.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(). */ Drupal.behaviors.toolbar = { attach: function (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', function () { // Establish the toolbar models and views. var model = Drupal.toolbar.models.toolbarModel = new Drupal.toolbar.ToolbarModel({ locked: JSON.parse(localStorage.getItem('Drupal.toolbar.trayVerticalLocked')) || false, activeTab: document.getElementById(JSON.parse(localStorage.getItem('Drupal.toolbar.activeTabID'))) }); Drupal.toolbar.views.toolbarVisualView = new Drupal.toolbar.ToolbarVisualView({ el: this, model: model, strings: options.strings }); Drupal.toolbar.views.toolbarAuralView = new Drupal.toolbar.ToolbarAuralView({ el: this, model: model, strings: options.strings }); Drupal.toolbar.views.bodyVisualView = new Drupal.toolbar.BodyVisualView({ el: this, model: model }); // Render collapsible menus. var 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(function (subtrees) { menuModel.set('subtrees', subtrees); localStorage.setItem('Drupal.toolbar.subtrees', JSON.stringify(subtrees)); // Indicate on the toolbarModel that subtrees are now loaded. model.set('areSubtreesLoaded', true); }); // Attach a listener to the configured media query breakpoints. for (var label in options.breakpoints) { if (options.breakpoints.hasOwnProperty(label)) { var mq = options.breakpoints[label]; var 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); } } // 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', function (event, offsets) { model.set('offsets', offsets); }); // Broadcast model changes to other modules. model .on('change:orientation', function (model, orientation) { $(document).trigger('drupalToolbarOrientationChange', orientation); }) .on('change:activeTab', function (model, tab) { $(document).trigger('drupalToolbarTabChange', tab); }) .on('change:activeTray', function (model, tray) { $(document).trigger('drupalToolbarTrayChange', tray); }); }); } }; /** * Toolbar methods of Backbone objects. */ Drupal.toolbar = { // A hash of View instances. views: {}, // A hash of Model instances. models: {}, // A hash of MediaQueryList objects tracked by the toolbar. mql: {}, /** * Accepts a list of subtree menu elements. * * A deferred object that is resolved by an inlined JavaScript callback. * * JSONP callback. * @see toolbar_subtrees_jsonp(). */ setSubtrees: new $.Deferred(), /** * Respond to configured narrow media query changes. */ mediaQueryChangeHandler: function (model, label, mql) { switch (label) { case 'module.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 'module.toolbar.standard': model.set({ 'isFixed': mql.matches }); break; case 'module.toolbar.wide': model.set({ 'orientation': ((mql.matches) ? '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 '
' + '' + '
'; }; }(jQuery, Drupal, drupalSettings));