diff --git a/core/misc/debounce.js b/core/misc/debounce.js
new file mode 100644
index 0000000..5896abe
--- /dev/null
+++ b/core/misc/debounce.js
@@ -0,0 +1,25 @@
+/**
+ * Limits the invocations of a function in a given time frame.
+ *
+ * @param {Function} callback
+ * The function to be invoked.
+ *
+ * @param {Number} wait
+ * The time period within which the callback function should only be
+ * invoked once. For example if the wait period is 250ms, then the callback
+ * will only be called at most 4 times per second.
+ */
+Drupal.debounce = function (callback, wait) {
+ var timeout, result;
+ return function () {
+ var context = this;
+ var args = arguments;
+ var later = function () {
+ timeout = null;
+ result = callback.apply(context, args);
+ };
+ window.clearTimeout(timeout);
+ timeout = window.setTimeout(later, wait);
+ return result;
+ };
+};
diff --git a/core/misc/tableheader.js b/core/misc/tableheader.js
index 3ae33c2..0d4f7cd 100644
--- a/core/misc/tableheader.js
+++ b/core/misc/tableheader.js
@@ -130,7 +130,6 @@ $.extend(TableHeader, {
/**
* Sum all [data-offset-top] values and cache it.
- * @todo move this out of tableheader.js into a move generic place like drupal.js.
*/
computeOffsetTop: function () {
var $offsets = $('[data-offset-top]');
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index aa5604c..ab148d9 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -1290,6 +1290,15 @@ function system_library_info() {
),
);
+ // A utility function to limit calls to a function with a given time.
+ $libraries['debounce'] = array(
+ 'title' => 'Drupal debounce',
+ 'version' => VERSION,
+ 'js' => array(
+ 'core/misc/debounce.js' => array('group' => JS_LIBRARY),
+ ),
+ );
+
// jQuery.
$libraries['jquery'] = array(
'title' => 'jQuery',
diff --git a/core/modules/toolbar/js/interactivemenu.js b/core/modules/toolbar/js/interactivemenu.js
new file mode 100644
index 0000000..7b5376c
--- /dev/null
+++ b/core/modules/toolbar/js/interactivemenu.js
@@ -0,0 +1,143 @@
+/**
+ * Decorate a menu with markup and classes for attaching behaviors.
+ */
+
+(function ($) {
+
+ $.fn.interactiveMenu = function () {
+
+ var ui = {
+ 'handleOpen': Drupal.t('Open'),
+ 'handleClose': Drupal.t('Close')
+ };
+
+ var toggleList = function (event) {
+ // The toggle.
+ var $toggle = $(event.target);
+ var $item = $toggle.closest('li');
+ var $list = $item.children('ul');
+ var isHidden = $list.hasClass('dormant');
+ // Close open siblings.
+ $item.siblings().filter('.open').find('.handle').trigger('click');
+ // Toggle the item open state.
+ $item
+ [((isHidden) ? 'add' : 'remove') + 'Class']('open');
+ // Toggle the item list visibility.
+ $list
+ [((isHidden) ? 'remove' : 'add') + 'Class']('dormant');
+ // Twist the toggle.
+ $toggle
+ [((isHidden) ? 'add' : 'remove') + 'Class']('open');
+ // Adjust the toggle text.
+ $toggle
+ .text((isHidden) ? ui.handleClose : ui.handleOpen)
+ .attr('aria-pressed', isHidden);
+ };
+ /**
+ *
+ */
+ var initItems = function ($list) {
+ var boxClass = 'box';
+ var handleClass = 'handle';
+ // Get lists and items.
+ var $ul = $list.find('ul').andSelf();
+ var $li = $list.find('li');
+ // Basic setup
+ $ul
+ .each(function (index, element) {
+ $(this).data('toolbar', {
+ processed: false,
+ type: 'list',
+ level: NaN
+ });
+ });
+ // Initialize items and their links.
+ $li
+ .each(function (index, element) {
+ $(this).data('toolbar', {
+ processed: false,
+ type: 'item'
+ });
+ })
+ // Add a class to item links.
+ .children('a')
+ .wrap(
+ $('
', {
+ 'class': boxClass
+ })
+ )
+ .end()
+ // Add a handle to each list item if it has a menu.
+ .each(function (index, element) {
+ var $item = $(this);
+ if ($item.children('ul').length > 0) {
+ $item
+ .children('.' + boxClass)
+ .prepend(Drupal.theme('interactionMenuItemToggle', {
+ 'class': handleClass,
+ 'text': ui.handleOpen
+ })
+ );
+ }
+ });
+ };
+ /**
+ * Adds a level class to each list based on its depth in the menu.
+ */
+ var markListLevels = function ($lists, level) {
+ level = (!level) ? 1 : level;
+ $lists
+ .addClass('level-' + level)
+ .each(function (index, element) {
+ $(this).data().toolbar.level = level;
+ });
+ $lists = $lists.children('li').children('ul');
+ if ($lists.length > 0) {
+ markListLevels($lists, (level + 1));
+ }
+ };
+ var setLevelVisibility = function ($lists, visibleAfter) {
+ var level;
+ $lists
+ .each(function (index, element) {
+ var $this = $(this);
+ level = $(this).data().toolbar.level;
+ if (level > visibleAfter) {
+ $this.addClass('dormant');
+ }
+ else {
+ $this.addClass('visible');
+ }
+ });
+ $lists = $lists.children('li').children('ul');
+ if ($lists.length > 0) {
+ setLevelVisibility($lists, visibleAfter);
+ }
+ };
+ return this.each(function (selector) {
+ var $menu = $(this).once('decorate-menu');
+ if ($menu.length) {
+ $menu.addClass('root');
+ initItems($menu);
+ markListLevels($menu);
+ setLevelVisibility($menu, 1);
+ // Wrap the list in a div to provide a positioning context.
+ $menu
+ .wrap('')
+ .parent()
+ // Bind event handlers.
+ .on('click.interactivemenu', '.handle', toggleList);
+ }
+ });
+ };
+
+ /**
+ * A toggle is an interactive element often bound to a click handler.
+ *
+ * @return {String}
+ * A string representing a DOM fragment.
+ */
+ Drupal.theme.interactionMenuItemToggle = function (options) {
+ return '';
+ };
+}(jQuery));
diff --git a/core/modules/toolbar/js/toolbar.js b/core/modules/toolbar/js/toolbar.js
index 7249f06..dc044a1 100755
--- a/core/modules/toolbar/js/toolbar.js
+++ b/core/modules/toolbar/js/toolbar.js
@@ -3,12 +3,20 @@
*
* Defines the behavior of the Drupal administration toolbar.
*/
-(function ($, _) {
+(function ($) {
"use strict";
Drupal.toolbar = Drupal.toolbar || {};
-var transitionEnd = "transitionEnd.toolbar webkitTransitionEnd.toolbar transitionend.toolbar msTransitionEnd.toolbar oTransitionEnd.toolbar";
+
+/**
+ * Store the state of the active tab so it will remain active across page loads.
+ */
+var activeTab = JSON.parse(localStorage.getItem('Drupal.toolbar.activeTab'));
+/**
+ * Store the state of the tray orientations to maintain them across page loads.
+ */
+var trayOrientations = JSON.parse(localStorage.getItem('Drupal.toolbar.trayOrientations')) || [];
/**
* Register tabs with the toolbar.
@@ -20,44 +28,48 @@ var transitionEnd = "transitionEnd.toolbar webkitTransitionEnd.toolbar transitio
*/
Drupal.behaviors.toolbar = {
attach: function(context, settings) {
- var options = _.extend(this.options, ('toolbar' in settings) ? settings.toolbar : {});
+ var options = $.extend(this.options, ('toolbar' in settings) ? settings.toolbar : {});
var $toolbar = $(context).find('#toolbar').once('toolbar');
if ($toolbar.length) {
$toolbar
- .addClass('toolbar-main')
- .on('itemregistered', decorateInteractiveMenu);
- var toolbar = new ToolBar($toolbar, options);
- // Find and register tabs. Each tab may have an associated tray.
- var item, tray, $tray, $trays, tab, $tab, $tabs, name, i;
- Drupal.toolbar.tabs = [];
- $tabs = $toolbar.find('.bar .tab');
- $trays = $toolbar.find('.tray');
- for (i = 0; i < $tabs.length; i++) {
- $tab = $($tabs[i]);
- name = $tab.attr('data-toolbar-tray') || '';
- $tray = $trays.filter('[data-toolbar-tray="' + name + '"]');
- tab = new Tab($tab);
- item = {
- name: name,
- tab: tab
- };
- if ($tray.length) {
- item.tray = new Tray($tray);
- }
- toolbar.registerTab(item);
- }
+ .addClass('toolbar-main');
+ // Set the initial orientation of the trays.
+ var $tray = $('.tray', $toolbar)
+ .attr('data-toolbar-orientation', 'vertical')
+ .addClass('vertical');
+ // Add the tray orientation toggles.
+ $tray
+ .find('.lining')
+ .append(Drupal.theme('toolbarOrientationToggle'));
+ // Ensure the orientation toggle agrees with the current tray orientation.
+ toggleOrientationToggle($tray, 'vertical');
+ // Adjust the body to accomodate trays.
+ setBodyState();
+
// Set up switching between the vertical and horizontal presentation
// of the toolbar trays based on a breakpoint.
if (options.breakpoints && options.breakpoints['module.toolbar.wide'] !== undefined) {
var mql = matchMedia(options.breakpoints['module.toolbar.wide']);
- mql.addListener(toolbar.mediaQueryChangeHandler);
- toolbar.mediaQueries.push(mql);
+ mql.addListener(Drupal.toolbar.mediaQueryChangeHandler);
if (mql.matches) {
- toolbar.mediaQueryChangeHandler(mql);
+ Drupal.toolbar.mediaQueryChangeHandler(mql);
}
}
- // Assign the toolbar to the Drupal global object.
- Drupal.toolbar = toolbar;
+ // Recalculate the offset top of the toolbar once on initialization.
+ Drupal.toolbar.setHeight();
+ // Call setHeight on screen resize. Wrap it in debounce to prevent
+ // setHeight from being called too frequently.
+ var setHeight = Drupal.debounce(Drupal.toolbar.setHeight, 250);
+ $(window)
+ .on('resize.toolbar', setHeight);
+ // Attach behaviors to the toolbar.
+ $(document)
+ .on('click.toolbar', '#toolbar .bar .tab', Drupal.toolbar.toggleTray)
+ .on('click.toolbar', '#toolbar .tray .toggle-orientation button', Drupal.toolbar.orientationChangeHandler);
+ // Decorate the main menu with an interactive menu.
+ $('.interactive-menu > .menu', $toolbar).interactiveMenu();
+ // Restore the toolbar to its saved state.
+ restoreState();
}
},
options: {
@@ -65,291 +77,180 @@ Drupal.behaviors.toolbar = {
}
};
/**
- * A toolbar is an administration action button container.
- */
-function ToolBar ($toolbar, options) {
- this.$toolbar = $toolbar;
- this.$bar = $toolbar.find('.bar');
- this.height = 0;
- this.barHeight = 0;
- this.items = [];
- this.activeItem = null;
- this.mediaQueries = [];
- this.ui = {
- 'activeClass': 'active',
- 'trayOpenBodyClass': 'toolbar-tray-open',
- };
- // Bind all ToolBar methods to the instance.
- _.bindAll(this);
- // Recalculate the offset top on screen resize.
- // Use throttle to prevent setHeight from being called too frequently.
- var setHeight = _.debounce(this.setHeight, 250);
- $(window)
- .on({
- 'resize.toolbar': setHeight
- });
- // Toolbar event handlers.
- this.$toolbar
- .on('setup.toolbar', this.setHeight)
- .on('click.toolbar', '.bar .tab', this.toggleTray)
- .on('click.toolbar', '.tray .toggle-orientation button', this.orientationChangeHandler)
- .on(transitionEnd, '.tray.active', this.setHeight)
- .trigger('setup.toolbar');
-};
-/**
- * Extend the prototype of the ToolBar class.
+ * Toggle a toolbar tab and the associated tray.
*/
-_.extend(ToolBar.prototype, {
- /**
- * The height of the toolbar offsets the top of the page content.
- *
- * Page components can register with the offsettopchange event to know when
- * the height of the toolbar changes.
- */
- setHeight: function (event) {
- var height = 0;
- var tray, $tray, $trays, trayH;
- this.barHeight = this.$bar.outerHeight();
- var bhpx = this.barHeight + 'px';
- height += this.barHeight;
- // Set the top of the all the trays to the height of the bar.
- $trays = this.$toolbar.find('.tray');
- for (var i = $trays.length - 1; i >= 0; i--) {
- tray = $trays[i];
- if (!tray.style.top.length || (tray.style.top !== bhpx)) {
- tray.style.top = bhpx;
- }
- };
- // Get the height of the active horizontal tray and include it in the total
- // height of the toolbar.
- height += $trays.filter('.active.horizontal').height('auto').outerHeight() || 0;
- // Set the height of the vertical tray to the scrollHeight of the
- // documentElement.
- $trays.filter('.active.vertical').height(document.documentElement.scrollHeight);
- // Indicate the height of the toolbar in the attribute data-offset-top.
- if (this.height !== height) {
- this.height = height;
- this.$toolbar.attr('data-offset-top', height);
- // Alter the padding on the top of the body element.
- $('body').css('padding-top', height);
- $(document).trigger('offsettopchange', height);
- $(window).triggerHandler('resize');
- }
- },
- /**
- * Toggle a toolbar tab and the associated tray.
- *
- *
- */
- toggleTray: function (event) {
- var $tab = $(event.target);
- var item = this.getItem($tab.data('toolbar').tab.name);
- var tab = item.tab;
- if (item.tray) {
- var tray = item.tray;
- event.preventDefault();
- var disableTrays = _.without(this.getTrays(), tray);
- for (var i = disableTrays.length - 1; i >= 0; i--) {
- disableTrays[i].toggle(false);
- this.getItem(disableTrays[i].name).tab.toggle(false);
- };
- tab.toggle();
- tray.toggle(tab.active);
- this.activeItem = (tab.active) ? item : null;
- this.setBodyState();
- this.setHeight();
- this.$toolbar.trigger('itemtoggled', item);
- }
- },
- /**
- *
- */
- registerTab: function (item) {
- this.items.push(item);
- // Save references to the tab and tray instances on the corresponding DOM
- // elements.
- item.tab.$el.data('toolbar', {tab: item.tab});
- if (item.tray) {
- item.tray.$el.data('toolbar', {tray: item.tray});
- }
- this.$toolbar.trigger('itemregistered', item);
- },
- /**
- *
- */
- getItem: function (name) {
- for (var i = this.items.length - 1; i >= 0; i--) {
- if (this.items[i].name === name) {
- return this.items[i];
- }
- }
- return;
- },
- /**
- *
- */
- getTabs: function () {
- var tabs = [];
- for (var i = this.items.length - 1; i >= 0; i--) {
- tabs.push(this.items[i].tab);
- }
- return tabs;
- },
- /**
- *
- */
- getTrays: function () {
- var trays = [];
- for (var i = this.items.length - 1; i >= 0; i--) {
- if (this.items[i].tray) {
- trays.push(this.items[i].tray);
- }
- }
- return trays;
- },
- /**
- *
- */
- orientationChangeHandler: function (event) {
- var $button = $(event.target);
- var orientation = event.target.value;
- var tray = $button.closest('.tray').data('toolbar').tray;
- this.changeOrientation(tray, orientation, true);
- this.setBodyState();
- this.setHeight();
- this.$toolbar.trigger('toolbarorientationchanged', orientation);
- },
- /**
- *
- */
- mediaQueryChangeHandler: function (mql) {
- var orientation = (mql.matches) ? 'horizontal' : 'vertical';
- this.changeOrientation(this.getTrays(), orientation);
- this.setBodyState();
- this.setHeight();
- this.$toolbar.trigger('toolbarorientationchanged', orientation);
- },
- /**
- *
- */
- changeOrientation: function (trays, orientation, isOverride) {
- trays = (!_.isArray(trays)) ? [trays] : trays;
- for (var i = trays.length - 1; i >= 0; i--) {
- trays[i].changeOrientation(orientation, isOverride);
- };
- },
- /**
- *
- */
- setBodyState: function () {
- var $body = $('body')
- .removeClass('toolbar-vertical toolbar-horizontal');
- if (this.activeItem) {
- $body
- .addClass('toolbar-tray-open')
- .addClass('toolbar-' + this.activeItem.tray.getOrientation());
+Drupal.toolbar.toggleTray = function (event) {
+ var $tab = $(event.target);
+ var name = $tab.attr('data-toolbar-tray');
+ var $toolbar = $tab.closest('#toolbar');
+ // Activate the selected tab and associated tray.
+ var $activateTray = $('[data-toolbar-tray="' + name + '"].tray', $toolbar).toggleClass('active');
+ if ($activateTray.length) {
+ event.preventDefault();
+ event.stopPropagation();
+ $tab.parent().toggleClass('active');
+ // Store the active tab name or remove the setting.
+ if ($tab.parent().hasClass('active')) {
+ localStorage.setItem('Drupal.toolbar.activeTab', JSON.stringify(name));
}
else {
- $body
- .removeClass('toolbar-tray-open');
+ localStorage.removeItem('Drupal.toolbar.activeTab');
}
+ // Disable non-selected tabs and trays.
+ $('.bar .tab', $toolbar).not($tab).parent().removeClass('active');
+ $('.tray', $toolbar).not($activateTray).removeClass('active');
+ setBodyState();
+ Drupal.toolbar.setHeight();
}
-});
+};
/**
- * Toolbar tray.
+ * The height of the toolbar offsets the top of the page content.
+ *
+ * Page components can register with the offsettopchange event to know when
+ * the height of the toolbar changes.
*/
-function Tray ($tray) {
- this.$el = $tray;
- this.name = this.$el.data()['toolbarTray'] || this.$el.attr('id') ||'no name';
- this.active = false;
- this.orientation = 'vertical';
- this.isOrientationLocked = false;
- this.setup.apply(this, arguments);
-}
-
+Drupal.toolbar.setHeight = function (event) {
+ var $toolbar = $('#toolbar');
+ var height = 0;
+ var barHeight = $('.bar', $toolbar).outerHeight();
+ var bhpx = barHeight + 'px';
+ var tray;
+ // Add the bar height to the total calculated height of the toolbar.
+ height += barHeight;
+ // Set the top of the all the trays to the height of the bar.
+ var $trays = $('.tray', $toolbar);
+ for (var tray, i = $trays.length - 1; i >= 0; i--) {
+ tray = $trays[i];
+ if (!tray.style.top.length || (tray.style.top !== bhpx)) {
+ tray.style.top = bhpx;
+ }
+ };
+ // Get the height of the active horizontal tray and include it in the total
+ // height of the toolbar.
+ height += $trays.filter('.active.horizontal').height('auto').outerHeight() || 0;
+ // Set the height of the vertical tray to the scrollHeight of the
+ // documentElement.
+ $trays.filter('.active.vertical').height(document.documentElement.scrollHeight);
+ // Indicate the height of the toolbar in the attribute data-offset-top.
+ var offset = $toolbar.attr('data-offset-top');
+ if (offset !== height) {
+ $toolbar.attr('data-offset-top', height);
+ // Alter the padding on the top of the body element.
+ $('body').css('padding-top', height);
+ $(document).trigger('offsettopchange', height);
+ $(window).triggerHandler('resize');
+ }
+};
/**
- * Extend the prototype of the Tray.
+ *
*/
-_.extend(Tray.prototype, {
- /**
- *
- */
- setup: function () {
- this.$el
- .addClass(this.orientation)
- .find('.lining')
- .append(Drupal.theme('toolbarOrientationToggle'));
- this.toggleOrientationToggle();
- },
- /**
- *
- */
- toggle: function (open) {
- this.$el.toggleClass('active', open);
- },
- /**
- *
- */
- changeOrientation: function (orientation, isOverride) {
- if (isOverride && orientation === 'vertical') {
- this.isOrientationLocked = true;
+Drupal.toolbar.mediaQueryChangeHandler = function (mql) {
+ var orientation = (mql.matches) ? 'horizontal' : 'vertical';
+ changeOrientation($('.tray', '#toolbar'), orientation);
+ setBodyState();
+ Drupal.toolbar.setHeight();
+};
+/**
+ *
+ */
+Drupal.toolbar.orientationChangeHandler = function (event) {
+ event.preventDefault();
+ event.stopPropagation();
+ var $button = $(event.target);
+ var orientation = event.target.value;
+ var $tray = $button.closest('.tray');
+ changeOrientation($tray, orientation, true);
+ setBodyState();
+ Drupal.toolbar.setHeight();
+};
+/**
+ *
+ */
+var restoreState = function () {
+ // Restore the open tab.
+ if (activeTab) {
+ $('[data-toolbar-tray="' + activeTab + '"].tab', '#toolbar').trigger('click.toolbar');
+ }
+ // Restore tray orientations.
+ if (trayOrientations.length) {
+ var $trays = $('.tray', '#toolbar');
+ var $tray;
+ for (var i = trayOrientations.length - 1; i >= 0; i--) {
+ $tray = $trays.filter('[data-toolbar-tray="' + trayOrientations[i].tray + '"]');
+ changeOrientation($tray, trayOrientations[i].orientation, true);
}
- if (isOverride && orientation === 'horizontal') {
- this.isOrientationLocked = false;
+ }
+};
+/**
+ *
+ */
+var changeOrientation = function ($trays, orientation, isOverride) {
+ for (var i = $trays.length - 1; i >= 0; i--) {
+ var $tray = $($trays[i]);
+ if (isOverride) {
+ $tray.attr('data-toolbar-orientation-locked', (orientation === 'vertical') ? 1 : 0);
}
- if (!this.isOrientationLocked && orientation === 'horizontal' && this.orientation === 'vertical') {
- var self = this;
- this.orientation = orientation;
- this.$el
+ var currentOrientation = $tray.attr('data-toolbar-orientation');
+ var isOrientationLocked = parseInt($tray.attr('data-toolbar-orientation-locked'));
+ if (!isOrientationLocked && orientation === 'horizontal' && currentOrientation === 'vertical') {
+ $tray
+ .attr('data-toolbar-orientation', orientation)
.removeClass('vertical')
- .addClass('horizontal');
- this.toggleOrientationToggle();
+ .addClass(orientation);
+ toggleOrientationToggle($tray, orientation);
}
- if (orientation === 'vertical' && this.orientation === 'horizontal') {
- this.orientation = orientation;
- this.$el
+ if (orientation === 'vertical' && currentOrientation === 'horizontal') {
+ $tray
+ .attr('data-toolbar-orientation', orientation)
.removeClass('horizontal')
- .addClass('vertical');
- this.toggleOrientationToggle();
+ .addClass(orientation);
+ toggleOrientationToggle($tray, orientation);
}
- },
- /**
- *
- */
- getOrientation: function () {
- return (this.isOrientationLocked) ? 'vertical' : this.orientation;
- },
- /**
- * Change the orientation toggle active state.
- */
- toggleOrientationToggle: function () {
- this.$el
- .find('[value="' + this.orientation + '"]')
- .removeClass('active')
- .siblings()
- .addClass('active');
}
-});
-
-function Tab ($tab) {
- this.$el = $tab;
- this.active = false;
- this.name = this.$el.data()['toolbarTray'] || this.$el.attr('id') ||'no name';
-}
-
+ // Save the state of overridden trays.
+ localStorage.setItem('Drupal.toolbar.trayOrientations',
+ JSON.stringify(
+ $('[data-toolbar-orientation-locked=1]', '#toolbar')
+ .map(function () {
+ var $tray = $(this);
+ return {
+ 'tray': $tray.attr('data-toolbar-tray'),
+ 'orientation': $tray.attr('data-toolbar-orientation') || 'vertical'
+ };
+ })
+ .get()
+ )
+ );
+};
/**
- * Extend the prototype of the Tray.
+ *
*/
-_.extend(Tab.prototype, {
- /**
- *
- */
- toggle: function (open) {
- this.active = (open !== undefined) ? open : !this.active;
- this.$el.parent('li').toggleClass('active', this.active);
+var setBodyState = function () {
+ var $toolbar = $('#toolbar');
+ var $activeTray = $('.tray.active', $toolbar);
+ var $body = $('body')
+ .removeClass('toolbar-vertical toolbar-horizontal');
+ if ($activeTray.length) {
+ $body
+ .addClass('toolbar-tray-open')
+ .addClass('toolbar-' + $activeTray.attr('data-toolbar-orientation'));
+ }
+ else {
+ $body
+ .removeClass('toolbar-tray-open');
}
-});
+};
+/**
+ * Change the orientation toggle active state.
+ */
+var toggleOrientationToggle = function ($tray, orientation) {
+ $tray
+ .find('[value="' + orientation + '"]')
+ .removeClass('active')
+ .siblings()
+ .addClass('active');
+}
/**
* A toggle is an interactive element often bound to a click handler.
@@ -360,182 +261,5 @@ _.extend(Tab.prototype, {
Drupal.theme.toolbarOrientationToggle = function () {
return '
';
};
-/**
- * A toggle is an interactive element often bound to a click handler.
- *
- * @return {String}
- * A string representing a DOM fragment.
- */
-Drupal.theme.interactionMenuItemToggle = function (options) {
- return '';
-};
-
-/**
- * Interactive menu setup methods.
- */
-function decorateInteractiveMenu (event, item) {
- if (item.tray && item.tray.name === 'administration') {
- item.tray.decorate = interactiveMenuDecorator();
- item.tray.decorate('.interactive-menu > .menu');
- }
-}
-
-/**
- * Decorate a menu with markup and classes for attaching behaviors.
- */
-var interactiveMenuDecorator = function () {
-
- var ui = {
- 'handleOpen': Drupal.t('Open'),
- 'handleClose': Drupal.t('Close')
- };
-
- var processLists = function (event) {
- event.stopPropagation();
- // Mark up the lists and items.
- $(event.target)
- .trigger('listChange');
- };
- var toggleList = function (event) {
- // The toggle.
- var $toggle = $(event.target);
- var $item = $toggle.closest('li');
- var $list = $item.children('ul');
- var isHidden = $list.hasClass('dormant');
- // Close open siblings.
- $item.siblings().filter('.open').find('.handle').trigger('click');
- // Toggle the item open state.
- $item
- [((isHidden) ? 'add' : 'remove') + 'Class']('open');
- // Toggle the item list visibility.
- $list
- [((isHidden) ? 'remove' : 'add') + 'Class']('dormant');
- // Twist the toggle.
- $toggle
- [((isHidden) ? 'add' : 'remove') + 'Class']('open');
- // Adjust the toggle text.
- $toggle
- .text((isHidden) ? ui.handleClose : ui.handleOpen)
- .attr('aria-pressed', isHidden);
- // Fire an event to signify that a list has been toggled.
- $item.trigger('itemtoggled', [$item.parent().data('toolbar').level, !isHidden]);
- };
- var initItems = function (event) {
- // The accordion wrapper.
- var $wrapper = $(event.target);
- var rootClass = 'root';
- var boxClass = 'box';
- var handleClass = 'handle';
- // Get lists and items.
- var $root = $wrapper.children('.' + rootClass);
- var $ul = $wrapper.find('ul');
- var $li = $wrapper.find('li');
- // Basic setup
- $ul
- .each(function (index, element) {
- $(this).data('toolbar', {
- processed: false,
- type: 'list',
- level: NaN
- });
- });
- // Initialize items and their links.
- $li
- .each(function (index, element) {
- $(this).data('toolbar', {
- processed: false,
- type: 'item'
- });
- })
- // Add a class to item links.
- .children('a')
- .wrap(
- $('
', {
- 'class': boxClass
- })
- )
- .end()
- // Add a handle to each list item if it has a menu.
- .each(function (index, element) {
- var $item = $(this);
- if ($item.children('ul').length > 0) {
- $item
- .children('.' + boxClass)
- .prepend(Drupal.theme('interactionMenuItemToggle', {
- 'class': handleClass,
- 'text': ui.handleOpen
- })
- );
- }
- });
- };
- /**
- * Adds a level class to each list based on its depth in the menu.
- */
- var markListLevels = function ($lists, level) {
- level = (typeof level === 'object') ? 1 : level;
- $lists
- .addClass('level-' + level)
- .each(function (index, element) {
- $(this).data().toolbar.level = level;
- });
- $lists = $lists.children('li').children('ul');
- if ($lists.length > 0) {
- markListLevels($lists, (level + 1));
- }
- };
- var setLevelVisibility = function ($lists, visibleAfter) {
- var level;
- $lists
- .each(function (index, element) {
- var $this = $(this);
- level = $(this).data().toolbar.level;
- if (level > visibleAfter) {
- $this.addClass('dormant');
- }
- else {
- $this.addClass('visible');
- }
- });
- $lists = $lists.children('li').children('ul');
- if ($lists.length > 0) {
- setLevelVisibility($lists, visibleAfter);
- }
- };
- return function (selector) {
- var context = this;
- // Find any menus that have already been decorated.
- var $wrapper = this.$el.find(selector);
- // Decorate any menus that have not been.
- $wrapper
- .once('decorate-menu')
- .addClass('clearfix')
- .each(function (index, element) {
- var $root = $(this).addClass('root');
- // Create a set of list-manipulation callbacks.
- // Called when items are added or removed.
- var listUpdate = $.Callbacks();
- listUpdate.add(_.bind(initItems, context));
- listUpdate.add(_.bind(markListLevels, context, $root));
- listUpdate.add(_.bind(setLevelVisibility, context, $root, 1));
- // Wrap the list in a div to provide a positioning context.
- $wrapper = $().add($wrapper).add(
- $root
- .wrap('')
- .parent()
- // Bind event handlers.
- .on('setup.toolbar', _.bind(processLists, context))
- .on('listChange.toolbar', listUpdate.fire)
- .on('click.toolbar', '.handle', _.bind(toggleList, context))
- /* @todo
- .on('clean.toolbar.accordionMode', 'li', cleanItem)
- .on('activate.toolbar.accordionMode', 'li', activateItem)
- */
- .trigger('setup')
- );
- });
- return $wrapper;
- };
-};
-}(jQuery, _));
+}(jQuery));
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index 3651365..5493364 100755
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -172,7 +172,7 @@ function toolbar_toolbar() {
function toolbar_view() {
$build = array('#theme' => 'toolbar');
- $build['#attached']['library'][] = array('toolbar', 'drupal.toolbar');
+ $build['#attached']['library'][] = array('toolbar', 'toolbar');
// Get the configured breakpoint for switch from vertical to horizontal
// toolbar presentation.
@@ -347,7 +347,7 @@ function toolbar_in_active_trail($path) {
* Implements hook_library_info().
*/
function toolbar_library_info() {
- $libraries['drupal.toolbar'] = array(
+ $libraries['toolbar'] = array(
'title' => 'Toolbar',
'version' => VERSION,
'js' => array(
@@ -359,6 +359,7 @@ function toolbar_library_info() {
drupal_get_path('module', 'toolbar') . '/css/toolbar.icons.css',
),
'dependencies' => array(
+ array('system', 'debounce'),
array('system', 'matchMedia'),
array('system', 'jquery'),
array('system', 'underscore'),
@@ -366,6 +367,18 @@ function toolbar_library_info() {
array('system', 'drupalSettings'),
array('system', 'jquery.once'),
array('system', 'jquery.cookie'),
+ array('toolbar', 'toolbar.interactiveMenu'),
+ ),
+ );
+
+ $libraries['toolbar.interactiveMenu'] = array(
+ 'title' => 'Toolbar interactive menu decorator',
+ 'version' => VERSION,
+ 'js' => array(
+ drupal_get_path('module', 'toolbar') . '/js/interactivemenu.js' => array(),
+ ),
+ 'css' => array(
+ drupal_get_path('module', 'toolbar') . '/css/interactivemenu.css',
),
);