2015-08-17 17:00:26 -07:00
/ * *
* @ file
* Defines the behavior of the Drupal administration toolbar .
* /
( function ( $ , Drupal , drupalSettings ) {
2015-10-21 21:44:50 -07:00
'use strict' ;
2015-08-17 17:00:26 -07:00
// Merge run-time settings with the defaults.
var 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 }
2015-09-04 13:20:09 -07:00
*
* @ prop { Drupal ~ behaviorAttach } attach
* Attaches the toolbar rendering functionality to the toolbar element .
2015-08-17 17:00:26 -07:00
* /
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' ) . each ( 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 ) ;
2015-08-27 12:03:05 -07:00
var theme = drupalSettings . ajaxPageState . theme ;
localStorage . setItem ( 'Drupal.toolbar.subtrees.' + theme , JSON . stringify ( subtrees ) ) ;
2015-08-17 17:00:26 -07:00
// 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 ) ;
} ) ;
// 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 ( {
2015-09-04 13:20:09 -07:00
activeTab : $ ( '.toolbar-bar .toolbar-tab:not(.home-toolbar-tab) a' ) . get ( 0 )
2015-08-17 17:00:26 -07:00
} ) ;
}
} ) ;
}
} ;
/ * *
* Toolbar methods of Backbone objects .
*
* @ namespace
* /
Drupal . toolbar = {
/ * *
* A hash of View instances .
*
* @ type { object . < string , Backbone . View > }
* /
views : { } ,
/ * *
* A hash of Model instances .
*
* @ type { object . < string , Backbone . Model > }
* /
models : { } ,
/ * *
* A hash of MediaQueryList objects tracked by the toolbar .
*
* @ type { object . < string , 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
2015-09-04 13:20:09 -07:00
* A toolbar model
2015-08-17 17:00:26 -07:00
* @ param { string } label
2015-09-04 13:20:09 -07:00
* Media query label .
2015-08-17 17:00:26 -07:00
* @ param { object } mql
2015-09-04 13:20:09 -07:00
* A MediaQueryList object .
2015-08-17 17:00:26 -07:00
* /
mediaQueryChangeHandler : function ( model , label , mql ) {
switch ( label ) {
case 'toolbar.narrow' :
model . set ( {
2015-09-04 13:20:09 -07:00
isOriented : mql . matches ,
isTrayToggleVisible : false
2015-08-17 17:00:26 -07:00
} ) ;
// 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' ) ) {
2015-09-04 13:20:09 -07:00
model . set ( { orientation : 'vertical' } , { validate : true } ) ;
2015-08-17 17:00:26 -07:00
}
break ;
case 'toolbar.standard' :
model . set ( {
2015-09-04 13:20:09 -07:00
isFixed : mql . matches
2015-08-17 17:00:26 -07:00
} ) ;
break ;
case 'toolbar.wide' :
model . set ( {
2015-09-04 13:20:09 -07:00
orientation : ( ( mql . matches ) ? 'horizontal' : 'vertical' )
2015-08-17 17:00:26 -07:00
} , { validate : true } ) ;
// The tray orientation toggle visibility does not need to be
// validated.
model . set ( {
2015-09-04 13:20:09 -07:00
isTrayToggleVisible : mql . matches
2015-08-17 17:00:26 -07:00
} ) ;
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 '<div class="toolbar-toggle-orientation"><div class="toolbar-lining">' +
'<button class="toolbar-icon" type="button"></button>' +
'</div></div>' ;
} ;
2015-08-27 12:03:05 -07:00
/ * *
* Ajax command to set the toolbar subtrees .
*
* @ param { Drupal . Ajax } ajax
2015-09-04 13:20:09 -07:00
* { @ link Drupal . Ajax } object created by { @ link Drupal . ajax } .
2015-08-27 12:03:05 -07:00
* @ param { object } response
2015-09-04 13:20:09 -07:00
* JSON response from the Ajax request .
2015-08-27 12:03:05 -07:00
* @ param { number } [ status ]
2015-09-04 13:20:09 -07:00
* XMLHttpRequest status .
2015-08-27 12:03:05 -07:00
* /
Drupal . AjaxCommands . prototype . setToolbarSubtrees = function ( ajax , response , status ) {
Drupal . toolbar . setSubtrees . resolve ( response . subtrees ) ;
} ;
2015-08-17 17:00:26 -07:00
} ( jQuery , Drupal , drupalSettings ) ) ;