From dac186cb328eb53c04e842eb346e171546d65965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?"J.=20Rene=CC=81e=20Beach"?= Date: Mon, 19 Nov 2012 21:22:50 -0500 Subject: [PATCH] Issue #1137920 by jessebeach, benjifisher, nod_, effulgentsia, sjbassett, kathryn531: Fix toolbar on small screen sizes and redesign MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: J. Renée Beach --- core/misc/debounce.js | 36 ++ core/modules/overlay/overlay-parent.js | 4 +- core/modules/shortcut/images/shortcut-active.png | 3 + core/modules/shortcut/images/shortcut.png | 3 + core/modules/shortcut/shortcut.base-rtl.css | 15 - core/modules/shortcut/shortcut.base.css | 14 - core/modules/shortcut/shortcut.module | 38 +- core/modules/shortcut/shortcut.theme-rtl.css | 29 +- core/modules/shortcut/shortcut.theme.css | 56 +-- core/modules/system/system.module | 14 +- .../modules/toolbar/config/toolbar.breakpoints.yml | 3 + core/modules/toolbar/config/toolbar.config.yml | 3 + core/modules/toolbar/css/toolbar.base-rtl.css | 78 ++++ core/modules/toolbar/css/toolbar.base.css | 205 +++++++++ core/modules/toolbar/css/toolbar.icons-rtl.css | 43 ++ core/modules/toolbar/css/toolbar.icons.css | 144 ++++++ core/modules/toolbar/css/toolbar.menu-rtl.css | 19 + core/modules/toolbar/css/toolbar.menu.css | 118 +++++ core/modules/toolbar/css/toolbar.theme-rtl.css | 56 +++ core/modules/toolbar/css/toolbar.theme.css | 144 ++++++ .../toolbar/images/icon-appearance-active.png | 4 + core/modules/toolbar/images/icon-appearance.png | 4 + .../modules/toolbar/images/icon-child-collapse.png | 3 + core/modules/toolbar/images/icon-child-open.png | 3 + core/modules/toolbar/images/icon-collapse.png | 4 + .../toolbar/images/icon-configuration-active.png | 4 + core/modules/toolbar/images/icon-configuration.png | 3 + .../modules/toolbar/images/icon-content-active.png | 4 + core/modules/toolbar/images/icon-content.png | 3 + core/modules/toolbar/images/icon-extend-active.png | 3 + core/modules/toolbar/images/icon-extend.png | 3 + core/modules/toolbar/images/icon-help-active.png | 4 + core/modules/toolbar/images/icon-help.png | 4 + core/modules/toolbar/images/icon-home-active.png | 6 + core/modules/toolbar/images/icon-home.png | 6 + core/modules/toolbar/images/icon-menu-active.png | 3 + core/modules/toolbar/images/icon-menu.png | 3 + core/modules/toolbar/images/icon-open.png | 5 + core/modules/toolbar/images/icon-people-active.png | 3 + core/modules/toolbar/images/icon-people.png | 4 + .../modules/toolbar/images/icon-reports-active.png | 4 + core/modules/toolbar/images/icon-reports.png | 5 + .../toolbar/images/icon-structure-active.png | 3 + core/modules/toolbar/images/icon-structure.png | 3 + .../toolbar/images/icon-toggle-horizontal.png | 3 + .../toolbar/images/icon-toggle-vertical-rtl.png | 3 + .../toolbar/images/icon-toggle-vertical.png | 3 + core/modules/toolbar/js/toolbar.js | 337 ++++++++++++++ core/modules/toolbar/js/toolbar.menu.js | 170 +++++++ .../toolbar/Tests/ToolbarHookToolbarTest.php | 57 +++ core/modules/toolbar/templates/toolbar.tpl.php | 33 -- core/modules/toolbar/templates/toolbar.twig | 39 ++ .../tests/modules/toolbar_test/toolbar_test.info | 6 + .../tests/modules/toolbar_test/toolbar_test.module | 40 ++ core/modules/toolbar/toolbar-rtl.css | 37 -- core/modules/toolbar/toolbar.api.php | 106 +++++ core/modules/toolbar/toolbar.css | 129 ------ core/modules/toolbar/toolbar.info | 4 + core/modules/toolbar/toolbar.install | 46 ++ core/modules/toolbar/toolbar.js | 115 ----- core/modules/toolbar/toolbar.module | 467 +++++++++++++------- core/modules/toolbar/toolbar.png | 4 - core/modules/user/images/icon-user-active.png | 4 + core/modules/user/images/icon-user.png | 6 + core/modules/user/user.css | 12 +- core/modules/user/user.module | 60 +++ core/profiles/standard/standard.info | 1 + 67 files changed, 2209 insertions(+), 589 deletions(-) create mode 100644 core/misc/debounce.js create mode 100644 core/modules/shortcut/images/shortcut-active.png create mode 100644 core/modules/shortcut/images/shortcut.png create mode 100644 core/modules/toolbar/config/toolbar.breakpoints.yml create mode 100644 core/modules/toolbar/config/toolbar.config.yml create mode 100644 core/modules/toolbar/css/toolbar.base-rtl.css create mode 100644 core/modules/toolbar/css/toolbar.base.css create mode 100644 core/modules/toolbar/css/toolbar.icons-rtl.css create mode 100644 core/modules/toolbar/css/toolbar.icons.css create mode 100644 core/modules/toolbar/css/toolbar.menu-rtl.css create mode 100644 core/modules/toolbar/css/toolbar.menu.css create mode 100644 core/modules/toolbar/css/toolbar.theme-rtl.css create mode 100644 core/modules/toolbar/css/toolbar.theme.css create mode 100644 core/modules/toolbar/images/icon-appearance-active.png create mode 100644 core/modules/toolbar/images/icon-appearance.png create mode 100644 core/modules/toolbar/images/icon-child-collapse.png create mode 100644 core/modules/toolbar/images/icon-child-open.png create mode 100644 core/modules/toolbar/images/icon-collapse.png create mode 100644 core/modules/toolbar/images/icon-configuration-active.png create mode 100644 core/modules/toolbar/images/icon-configuration.png create mode 100644 core/modules/toolbar/images/icon-content-active.png create mode 100644 core/modules/toolbar/images/icon-content.png create mode 100644 core/modules/toolbar/images/icon-extend-active.png create mode 100644 core/modules/toolbar/images/icon-extend.png create mode 100644 core/modules/toolbar/images/icon-help-active.png create mode 100644 core/modules/toolbar/images/icon-help.png create mode 100644 core/modules/toolbar/images/icon-home-active.png create mode 100644 core/modules/toolbar/images/icon-home.png create mode 100644 core/modules/toolbar/images/icon-menu-active.png create mode 100644 core/modules/toolbar/images/icon-menu.png create mode 100644 core/modules/toolbar/images/icon-open.png create mode 100644 core/modules/toolbar/images/icon-people-active.png create mode 100644 core/modules/toolbar/images/icon-people.png create mode 100644 core/modules/toolbar/images/icon-reports-active.png create mode 100644 core/modules/toolbar/images/icon-reports.png create mode 100644 core/modules/toolbar/images/icon-structure-active.png create mode 100644 core/modules/toolbar/images/icon-structure.png create mode 100644 core/modules/toolbar/images/icon-toggle-horizontal.png create mode 100644 core/modules/toolbar/images/icon-toggle-vertical-rtl.png create mode 100644 core/modules/toolbar/images/icon-toggle-vertical.png create mode 100644 core/modules/toolbar/js/toolbar.js create mode 100644 core/modules/toolbar/js/toolbar.menu.js create mode 100644 core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarHookToolbarTest.php delete mode 100644 core/modules/toolbar/templates/toolbar.tpl.php create mode 100644 core/modules/toolbar/templates/toolbar.twig create mode 100644 core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.info create mode 100644 core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module delete mode 100644 core/modules/toolbar/toolbar-rtl.css create mode 100644 core/modules/toolbar/toolbar.api.php delete mode 100644 core/modules/toolbar/toolbar.css create mode 100644 core/modules/toolbar/toolbar.install delete mode 100644 core/modules/toolbar/toolbar.js delete mode 100644 core/modules/toolbar/toolbar.png create mode 100644 core/modules/user/images/icon-user-active.png create mode 100644 core/modules/user/images/icon-user.png diff --git a/core/misc/debounce.js b/core/misc/debounce.js new file mode 100644 index 0000000..338a50d --- /dev/null +++ b/core/misc/debounce.js @@ -0,0 +1,36 @@ +/** + * Limits the invocations of a function in a given time frame. + * + * The debounce function wrapper should be used sparingly. One clear use case + * is limiting the invocation of a callback attached to the window resize event. + * + * Before using the debounce function wrapper, consider first whether the + * callback could be attache to an event that fires less frequently or if the + * function can be written in such a way that it is only invoked under specific + * conditions. + * + * @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) { + + "use strict"; + + 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/modules/overlay/overlay-parent.js b/core/modules/overlay/overlay-parent.js index 1f38f2f..caf9336 100644 --- a/core/modules/overlay/overlay-parent.js +++ b/core/modules/overlay/overlay-parent.js @@ -881,9 +881,9 @@ Drupal.overlay.getPath = function (link) { */ Drupal.overlay.getDisplacement = function (region) { var displacement = 0; - var lastDisplaced = $('.overlay-displace-' + region + ':last'); + var lastDisplaced = $('[data-offset-' + region + ']'); if (lastDisplaced.length) { - displacement = lastDisplaced.offset().top + lastDisplaced.outerHeight(); + displacement = parseInt(lastDisplaced.attr('data-offset-' + region)); } return displacement; }; diff --git a/core/modules/shortcut/images/shortcut-active.png b/core/modules/shortcut/images/shortcut-active.png new file mode 100644 index 0000000..214bd30 --- /dev/null +++ b/core/modules/shortcut/images/shortcut-active.png @@ -0,0 +1,3 @@ +PNG + + IHDRĴl;tEXtSoftwareAdobe ImageReadyqe<IDATxbd@wR @ 4 L.f5  *6q136 Ҏ@\jI1QTTd(p }(f'`bbb }C-@P\\ G ^0M}\YIENDB` \ No newline at end of file diff --git a/core/modules/shortcut/images/shortcut.png b/core/modules/shortcut/images/shortcut.png new file mode 100644 index 0000000..739a8d0 --- /dev/null +++ b/core/modules/shortcut/images/shortcut.png @@ -0,0 +1,3 @@ +PNG + + IHDRĴl;tEXtSoftwareAdobe ImageReadyqe<IDATxbd@gΜqR &&&@ 4 L@-@;\<ƣA1#-(6q13@ ? .@1C8@(6{($>|1!!app B+ "IENDB` \ No newline at end of file diff --git a/core/modules/shortcut/shortcut.base-rtl.css b/core/modules/shortcut/shortcut.base-rtl.css index c236f47..ed903a7 100644 --- a/core/modules/shortcut/shortcut.base-rtl.css +++ b/core/modules/shortcut/shortcut.base-rtl.css @@ -5,21 +5,6 @@ */ /** - * Toolbar. - */ -#edit-shortcuts { - left: 0; - position: absolute; - top: 0; -} -#shortcut-toolbar ul { - float: none; -} -#shortcut-toolbar .icon { - float: right; -} - -/** * Add/remove links. */ .add-or-remove-shortcuts .icon, diff --git a/core/modules/shortcut/shortcut.base.css b/core/modules/shortcut/shortcut.base.css index 90a1046..aca7807 100644 --- a/core/modules/shortcut/shortcut.base.css +++ b/core/modules/shortcut/shortcut.base.css @@ -1,23 +1,9 @@ - /** * @file * Generic base styles for shortcut module. */ /** - * Toolbar. - */ -#edit-shortcuts { - float: right; /* LTR */ -} -#shortcut-toolbar ul { - float: left; /* LTR */ -} -#shortcut-toolbar .icon { - float: left; /* LTR */ -} - -/** * Add/remove links. */ .add-or-remove-shortcuts .icon { diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module index 9bbb12a..37b4596 100644 --- a/core/modules/shortcut/shortcut.module +++ b/core/modules/shortcut/shortcut.module @@ -713,20 +713,9 @@ function shortcut_preprocess_page(&$variables) { } /** - * Implements hook_page_alter(). + * Implements hook_toolbar(). */ -function shortcut_page_alter(&$page) { - if (isset($page['page_top']['toolbar'])) { - // If the toolbar is available, add a pre-render function to display the - // current shortcuts in the toolbar drawer. - $page['page_top']['toolbar']['#pre_render'][] = 'shortcut_toolbar_pre_render'; - } -} - -/** - * Pre-render function for adding shortcuts to the toolbar drawer. - */ -function shortcut_toolbar_pre_render($toolbar) { +function shortcut_toolbar() { $links = shortcut_renderable_links(); $links['#attached'] = array( 'css' => array( @@ -734,8 +723,6 @@ function shortcut_toolbar_pre_render($toolbar) { drupal_get_path('module', 'shortcut') . '/shortcut.theme.css', ), ); - $links['#prefix'] = '
'; - $links['#suffix'] = '
'; $shortcut_set = shortcut_current_displayed_set(); $configure_link = NULL; if (shortcut_set_edit_access($shortcut_set)) { @@ -743,17 +730,30 @@ function shortcut_toolbar_pre_render($toolbar) { '#type' => 'link', '#title' => t('Edit shortcuts'), '#href' => 'admin/config/user-interface/shortcut/' . $shortcut_set->set_name, - '#options' => array('attributes' => array('id' => 'edit-shortcuts')), + '#options' => array('attributes' => array('class' => array('edit-shortcuts'))), ); } - $drawer = array( + $links_tray = array( + '#heading' => t('User-defined shortcuts'), 'shortcuts' => $links, 'configure' => $configure_link, ); - $toolbar['toolbar_drawer'][] = $drawer; - return $toolbar; + $items['shortcuts'] = array( + 'tab' => array( + 'title' => t('Shortcuts'), + 'href' => 'admin/config/user-interface/shortcut', + 'html' => FALSE, + 'attributes' => array( + 'title' => t('Shortcuts'), + 'class' => array('icon', 'icon-shortcut'), + ), + ), + 'tray' => $links_tray, + 'weight' => -10, + ); + return $items; } /** diff --git a/core/modules/shortcut/shortcut.theme-rtl.css b/core/modules/shortcut/shortcut.theme-rtl.css index 424f38f..8a687d9 100644 --- a/core/modules/shortcut/shortcut.theme-rtl.css +++ b/core/modules/shortcut/shortcut.theme-rtl.css @@ -5,22 +5,6 @@ */ /** - * Toolbar. - */ -#shortcut-toolbar ul { - margin-left: 0; - margin-right: 5px; -} -#shortcut-toolbar a { - margin-left: 5px; - margin-right: 0; -} -#shortcut-toolbar .icon { - margin-left: 5px; - margin-right: 0; -} - -/** * Add/remove links. */ .add-or-remove-shortcuts .icon { @@ -42,3 +26,16 @@ .add-or-remove-shortcuts a:hover .text { border-radius: 5px 0 0 5px; } + +/** + * Toolbar. + */ +.toolbar-js .horizontal #edit-shortcuts { + border-left: 0 none; + border-right: 1px solid #d9d9d9; + float: right; + margin-left: 0; + margin-right: 0.3333em; + padding-left: 0.3333em; + padding-right: 0.6667em; +} diff --git a/core/modules/shortcut/shortcut.theme.css b/core/modules/shortcut/shortcut.theme.css index 9e2dc69..7d43c69 100644 --- a/core/modules/shortcut/shortcut.theme.css +++ b/core/modules/shortcut/shortcut.theme.css @@ -1,4 +1,3 @@ - /** * @file * Styling for the shortcut module. @@ -7,40 +6,25 @@ /** * Toolbar. */ -.toolbar #edit-shortcuts { - line-height: 24px; - padding: 5px 10px; -} -#edit-shortcuts:focus, -#edit-shortcuts:hover, -#edit-shortcuts.active { - text-decoration: underline; +.icon-shortcut:before { + background-image: url("images/shortcut.png"); } -#shortcut-toolbar ul { - line-height: 24px; - margin-left: 5px; /* LTR */ - padding: 5px 0; +.icon-shortcut:active:before, +.active .icon-shortcut:before { + background-image: url("images/shortcut-active.png"); } -#shortcut-toolbar a { - border-radius: 5px; - margin-right: 5px; /* LTR */ - padding: 0 5px; +.toolbar .tray.horizontal.shortcuts .menu { + float: left; } -#shortcut-toolbar a:focus, -#shortcut-toolbar a:hover, -#shortcut-toolbar a.active:focus { - background: #555; +.edit-shortcuts { + display: block; } -#shortcut-toolbar a.active:hover, -#shortcut-toolbar a.active { - background-color: #000; +.toolbar .vertical .edit-shortcuts { + text-align: right; + padding: 1em; } -#shortcut-toolbar .icon { - background-color: #444; - border-radius: 5px; - height: 30px; - margin-right: 5px; /* LTR */ - width: 30px; +.toolbar .horizontal .edit-shortcuts { + float: left; /* LTR */ } /** @@ -65,15 +49,3 @@ .remove-shortcut a:hover .icon { background-position: -12px -12px; /* LTR */ } -.add-or-remove-shortcuts .text { - padding: 0 6px 0 10px; /* LTR */ -} -.add-or-remove-shortcuts a:focus .text, -.add-or-remove-shortcuts a:hover .text { - background-color: #5f605b; - border-radius: 0 5px 5px 0; /* LTR */ - color: #fff; - cursor: pointer; - font-size: 10px; - line-height: 12px; -} diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 6401361..32fcdf0 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1288,6 +1288,19 @@ function system_library_info() { ), ); + // A utility function to limit calls to a function with a given time. + $libraries['drupal.debounce'] = array( + 'title' => 'Drupal debounce', + 'version' => VERSION, + 'js' => array( + 'core/misc/debounce.js' => array('group' => JS_LIBRARY), + ), + 'dependencies' => array( + // @todo remove drupal dependency. + array('system', 'drupal'), + ), + ); + // jQuery. $libraries['jquery'] = array( 'title' => 'jQuery', @@ -1903,7 +1916,6 @@ function system_library_info() { array('system', 'jquery'), ), ); - $libraries['drupal.tableselect'] = array( 'title' => 'Tableselect', 'version' => VERSION, diff --git a/core/modules/toolbar/config/toolbar.breakpoints.yml b/core/modules/toolbar/config/toolbar.breakpoints.yml new file mode 100644 index 0000000..c623c0e --- /dev/null +++ b/core/modules/toolbar/config/toolbar.breakpoints.yml @@ -0,0 +1,3 @@ +narrow: 'only screen and (min-width: 16.5em)' +standard: 'only screen and (min-width: 38.125em)' +wide: 'only screen and (min-width: 50em)' diff --git a/core/modules/toolbar/config/toolbar.config.yml b/core/modules/toolbar/config/toolbar.config.yml new file mode 100644 index 0000000..8a98715 --- /dev/null +++ b/core/modules/toolbar/config/toolbar.config.yml @@ -0,0 +1,3 @@ +breakpoints: + - 'module.toolbar.narrow' + - 'module.toolbar.wide' diff --git a/core/modules/toolbar/css/toolbar.base-rtl.css b/core/modules/toolbar/css/toolbar.base-rtl.css new file mode 100644 index 0000000..602d122 --- /dev/null +++ b/core/modules/toolbar/css/toolbar.base-rtl.css @@ -0,0 +1,78 @@ +/** + * @file toolbar.base-rtl.css + */ +html.js .toolbar { + left: auto; + right: 0; +} +.js .toolbar .bar li { + float: right; +} + +/** + * Administration menu. + */ +.js .toolbar .bar { + left: auto; + right: 0; +} +@media only screen { + .js .toolbar .bar li, + .js .toolbar .tray li { + float: none; + } +} +@media only screen and (min-width: 16.5em) { + .js .toolbar .bar li, + .js .toolbar .horizontal li { + float: right; + } +} + +/** + * Toolbar tray. + */ +.toolbar .vertical { + left: auto; + right: -100%; +} +.toolbar .horizontal { + left: auto; + right: 0; +} +.toolbar .vertical > .lining { + left: auto; + right: -100%; +} +.toolbar .vertical.active, +.toolbar .vertical.active > .lining { + left: auto; + right: 0; +} +@media only screen and (min-width: 16.5em) { + .toolbar .vertical.active > .lining:before { + left: auto; + right: -1px; + } +} + +/** + * At larger screen sizes, the tray pushes the page content. + */ +@media only screen and (min-width: 38.125em) { + body.toolbar-tray-open.toolbar-vertical { + margin-left: 0; + margin-right: 240px; + margin-right: 15rem; + } +} +/** + * ToolBar tray orientation toggle. + */ +.toolbar .horizontal .toggle-orientation { + left: 0; + right: auto; +} +.toolbar .vertical .toggle-orientation { + float: left; +} diff --git a/core/modules/toolbar/css/toolbar.base.css b/core/modules/toolbar/css/toolbar.base.css new file mode 100644 index 0000000..5e218a2 --- /dev/null +++ b/core/modules/toolbar/css/toolbar.base.css @@ -0,0 +1,205 @@ +/** + * @file toolbar.base.css + * + * + * Aggressive resets so we can achieve a consistent look in hostile CSS + * environments. + */ +html.js #toolbar-administration, +html .toolbar * { + -moz-box-sizing: border-box; + -o-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + margin: 0; + padding: 0; + vertical-align: baseline; +} +html.js #toolbar-administration { + font-size: small; + line-height: 1; +} +html.js .toolbar { + left: 0; /* LTR */ + position: absolute; + top: 0; + width: 100%; +} +/** + * Very specific overrides for Drupal system CSS. + */ +.toolbar li, +.toolbar .menu li, +.toolbar .item-list, +.toolbar .item-list li, +.toolbar .menu li.expanded { + list-style-type: none; + list-style-image: none; +} +.toolbar .menu li { + padding-top: 0; +} +.js .toolbar .bar li, +.js .toolbar .menu li { + display: block; +} +.js .toolbar .bar li, +.js .toolbar .horizontal li { + float: left; /* LTR */ +} +.js .toolbar a { + display: block; + line-height: 1; +} +/** + * Administration menu. + */ +.js .toolbar .bar { + left: 0; /* LTR */ + position: absolute; + top: 0; + z-index: 750; + width: 100%; +} +@media only screen { + .js .toolbar .bar li, + .js .toolbar .tray li { + float: none; /* LTR */ + } +} +@media only screen and (min-width: 16.5em) { + .js .toolbar .bar li, + .js .toolbar .horizontal li { + float: left; /* LTR */ + } +} +@media only screen and (min-width: 28.125em) { + .js .toolbar .bar { + position: fixed; + } +} + +/** + * Toolbar tray. + */ +.js .toolbar .tray { + display: none; + position: absolute; + z-index: 250; +} +.toolbar .horizontal { + width: 100%; +} +.toolbar .vertical, +.toolbar .vertical > .lining:before { + bottom: 0; + width: 240px; + width: 15rem; +} +.toolbar .vertical { + left: -100%; /* LTR */ + position: absolute; +} +.toolbar .horizontal { + left: 0; /* LTR */ + height: 0; + z-index: 750; +} +.toolar .tray .lining { + position: relative; +} +.toolbar .vertical > .lining, +.toolbar .vertical > .lining:before { + left: -100%; /* LTR */ + min-height: 100%; + position: absolute; + width: 100%; +} +.toolbar .vertical > .lining:before { + bottom: 0; + -moz-box-sizing: content-box; + -o-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box; + content: ''; + display: none; + height: 100%; + /* Support for devices that do not support position fixed. */ + position: absolute; + position: fixed; + top: 0; + z-index: -1; +} +.toolbar .tray.active { + display: block; +} +.toolbar .horizontal.active { + height: auto; +} +.toolbar .vertical.active, +.toolbar .vertical.active > .lining { + left: 0; /* LTR */ +} +.toolbar .horizontal .menu li ul { + display: none; +} +@media only screen { + .toolbar .vertical, + .toolbar .vertical > .lining:before { + bottom: auto; + width: 100%; + } +} + +@media only screen and (min-width: 16.5em) { + .toolbar .vertical { + bottom: 0; + } + .toolbar .vertical, + .toolbar .vertical > .lining:before { + width: 240px; + width: 15rem; + } + .toolbar .vertical.active > .lining:before { + display: block; + left: -1px; /* LTR */ + } +} +@media only screen and (min-width: 28.125em) { + .toolbar .horizontal { + position: fixed; + } +} +/** + * At larger screen sizes, the tray pushes the page content. + */ +@media only screen and (min-width: 38.125em) { + body.toolbar-tray-open.toolbar-vertical { + margin-left: 240px; /* LTR */ + margin-left: 15rem; /* LTR */ + } +} +/** + * ToolBar tray orientation toggle. + * + * Hide the orientation toggle from browsers that do not interpret + * media queries. They get a standard horizontal toolbar. + */ +.toolbar .horizontal .toggle-orientation { + display: none; +} +@media only screen { + .toolbar .tray .toggle-orientation { + display: block; + } +} +.toolbar .horizontal .toggle-orientation { + bottom: 0; + position: absolute; + right: 0; /* LTR */ + top: 0; +} +.toolbar .vertical .toggle-orientation { + float: right; /* LTR */ + width: 100%; +} diff --git a/core/modules/toolbar/css/toolbar.icons-rtl.css b/core/modules/toolbar/css/toolbar.icons-rtl.css new file mode 100644 index 0000000..aadd333 --- /dev/null +++ b/core/modules/toolbar/css/toolbar.icons-rtl.css @@ -0,0 +1,43 @@ +/** + * @file toolbar.icons-rtl.css + */ +.toolbar .icon { + padding-left: 1.3333em; + padding-right: 2.75em; +} +.toolbar .icon:before { + left: auto; + right: 0.6667em; +} +.toolbar .menu ul .icon { + padding-left: 0; + padding-right: 1.3333em; +} +.toolbar .vertical .menu ul { + margin-left: 0; + margin-right: 1.5em; +} +.toolbar .vertical .menu ul ul { + margin-left: 0; + margin-right: 0.75em; +} + +@media only screen and (min-width: 16.5em) { + .toolbar .bar .icon:before { + background-size: auto auto; + left: auto; + right: 0; + } +} + +@media only screen and (min-width: 36em) { + .toolbar .bar .icon { + background-position: right center; + padding-left: 1.3333em; + padding-right: 2.75em; + } + .toolbar .bar .icon:before { + left: 0; + right: 0.6667em; + } +} diff --git a/core/modules/toolbar/css/toolbar.icons.css b/core/modules/toolbar/css/toolbar.icons.css new file mode 100644 index 0000000..943d77a --- /dev/null +++ b/core/modules/toolbar/css/toolbar.icons.css @@ -0,0 +1,144 @@ +/** + * @file toolbar.icons.css + */ +.toolbar .icon { + padding-left: 2.75em; /* LTR */ + position: relative; +} +.toolbar .icon:before { + background-attachment: scroll; + background-color: transparent; + background-position: center center; + background-repeat: no-repeat; + content: ''; + display: block; + height: 100%; + left: 0.6667em; /* LTR */ + position: absolute; + top: 0; + width: 20px; +} +.toolbar button.icon { + background-color: transparent; + border: 0; + font-size: 1em; +} +.toolbar .menu ul .icon { + padding-left: 1.3333em; /* LTR */ +} +.toolbar .menu ul a.icon:before { + display: none; +} +.toolbar .vertical .menu ul { + margin-left: 1.5em; /* LTR */ +} +.toolbar .vertical .menu ul ul { + margin-left: 0.75em; /* LTR */ +} + +/** + * Top level icons + */ +.icon-home:before { + background-image: url("../images/icon-home.png"); +} +.icon-home:active:before, +.active .icon-home:before { + background-image: url("../images/icon-home-active.png"); +} +.icon-menu:before { + background-image: url("../images/icon-menu.png"); +} +.icon-menu:active:before, +.active .icon-menu:before { + background-image: url("../images/icon-menu-active.png"); +} + +/** + * Main menu icons. + */ +.icon-content:before { + background-image: url("../images/icon-content.png"); +} +.icon-content:active:before, +.icon-content.active:before { + background-image: url("../images/icon-content-active.png"); +} +.icon-structure:before { + background-image: url("../images/icon-structure.png"); +} +.icon-structure:active:before, +.icon-structure.active:before { + background-image: url("../images/icon-structure-active.png"); +} +.icon-appearance:before { + background-image: url("../images/icon-appearance.png"); +} +.icon-appearance:active:before, +.icon-appearance.active:before { + background-image: url("../images/icon-appearance-active.png"); +} +.icon-people:before { + background-image: url("../images/icon-people.png"); +} +.icon-people:active:before, +.icon-people.active:before { + background-image: url("../images/icon-people-active.png"); +} +.icon-extend:before { + background-image: url("../images/icon-extend.png"); +} +.icon-extend:active:before, +.icon-extend.active:before { + background-image: url("../images/icon-extend-active.png"); +} +.icon-configuration:before { + background-image: url("../images/icon-configuration.png"); +} +.icon-configuration:active:before, +.icon-configuration.active:before { + background-image: url("../images/icon-configuration-active.png"); +} +.icon-reports:before { + background-image: url("../images/icon-reports.png"); +} +.icon-reports:active:before, +.icon-reports.active:before { + background-image: url("../images/icon-reports-active.png"); +} +.icon-help:before { + background-image: url("../images/icon-help.png"); +} +.icon-help:active:before, +.icon-help.active:before { + background-image: url("../images/icon-help-active.png"); +} + +@media only screen and (min-width: 16.5em) { + .toolbar .bar .icon { + margin-left: 0; + margin-right: 0; + padding-left: 0; + padding-right: 0; + text-indent: -9999px; + width: 4em; + } + .toolbar .bar .icon:before { + left: 0; /* LTR */ + width: 100%; + } +} + +@media only screen and (min-width: 36em) { + .toolbar .bar .icon { + background-position: left center; /* LTR */ + padding-left: 2.75em; /* LTR */ + padding-right: 1.3333em; /* LTR */ + text-indent: 0; + width: auto; + } + .toolbar .bar .icon:before { + left: 0.6667em; /* LTR */ + width: 20px; + } +} diff --git a/core/modules/toolbar/css/toolbar.menu-rtl.css b/core/modules/toolbar/css/toolbar.menu-rtl.css new file mode 100644 index 0000000..1435225 --- /dev/null +++ b/core/modules/toolbar/css/toolbar.menu-rtl.css @@ -0,0 +1,19 @@ +/** + * @file toolbar.menu-rtl.css + */ +.toolbar .vertical .handle + a { + margin-left: 3em; + margin-right: 0; +} + +/** + * Handle. + */ +.toolbar .icon.handle { + left: 0; + right: auto; +} +.toolbar .icon.handle:before { + left: auto; + right: 0; +} diff --git a/core/modules/toolbar/css/toolbar.menu.css b/core/modules/toolbar/css/toolbar.menu.css new file mode 100644 index 0000000..3dd0a1b --- /dev/null +++ b/core/modules/toolbar/css/toolbar.menu.css @@ -0,0 +1,118 @@ +/** + * @file toolbar.menu.css + */ +.toolbar .menu { + list-style: none; + margin: 0; + padding: 0; +} +.toolbar .box { + display: block; + line-height: 1em; /* this prevents the value "normal" from being returned as the line-height */ + position: relative; + width: auto; +} +.toolbar .horizontal .menu .handle, +.toolbar .horizontal .menu ul, +.toolbar .vertical .menu ul { + display: none; +} +.toolbar .vertical li.open > ul { + display: block; /* Show the sub-menus */ +} +.toolbar .vertical .handle + a { + margin-right: 3em; /* LTR */ +} + +/** + * Items. + */ +.toolbar .vertical .menu .menu a { + padding-bottom: 0.6667em; + padding-top: 0.6667em; +} +.toolbar .tray .level-3 a { + color: #303030; +} +.toolbar .tray .level-4 a { + color: #2d2d2d; +} +.toolbar .tray .level-5 a { + color: #2a2a2a; +} +.toolbar .tray .level-6 a { + color: #272727; +} +.toolbar .tray .level-7 a { + color: #2a2a2a; +} +.toolbar .tray .level-8 a { + color: #2d2d2d; +} +.toolbar .tray .level-9 a { + color: #303030; +} +.toolbar .level-2 > ul { + background-color: #f5f5f5; + border-color: #cccccc; +} +.toolbar .level-3 > ul { + background-color: #e5e5e5; + border-color: #bbbbbb; +} +.toolbar .level-4 > ul { + background-color: #d5d5d5; + border-color: #aaaaaa; +} +.toolbar .level-5 > ul { + background-color: #c5c5c5; + border-color: #999999; +} +.toolbar .level-6 > ul { + background-color: #b5b5b5; + border-color: #888888; +} +.toolbar .level-7 > ul { + background-color: #c5c5c5; + border-color: #999999; +} +.toolbar .level-8 > ul { + background-color: #d5d5d5; + border-color: #aaaaaa; +} +.toolbar .level-9 > ul { + background-color: #e5e5e5; + border-color: #bbbbbb; +} + +/** + * Handle. + */ +.toolbar .handle:hover { + cursor: pointer; +} +.toolbar .icon.handle { + bottom: 0; + display: block; + height: 100%; + padding: 0; + position: absolute; + right: 0; /* LTR */ + text-indent: -9999px; + top: 0; + width: 3em; + z-index: 1; +} +.toolbar .icon.handle:before { + background-image: url("../images/icon-open.png"); + left: 0; /* LTR */ +} +.toolbar .icon.handle.open:before { + background-image: url("../images/icon-collapse.png"); +} +.toolbar .menu .menu .icon.handle:before { + background-image: url("../images/icon-child-open.png"); +} +.toolbar .menu .menu .icon.handle.open:before { + background-image: url("../images/icon-child-collapse.png"); +} diff --git a/core/modules/toolbar/css/toolbar.theme-rtl.css b/core/modules/toolbar/css/toolbar.theme-rtl.css new file mode 100644 index 0000000..fa5a1df --- /dev/null +++ b/core/modules/toolbar/css/toolbar.theme-rtl.css @@ -0,0 +1,56 @@ +/** + * @file toolbar.theme-rtl.css + */ + +/** + * Toolbar tray. + */ +.toolbar .horizontal > .lining { + padding-right: 0; + padding-left: 5em; +} +.toolbar .vertical > .lining, +.toolbar .vertical > .lining:before { + border-left: 1px solid #aaaaaa; + border-right: 0 none; +} +.toolbar .vertical > .lining:before { + box-shadow: 1px 0 5px 2px rgba(0, 0, 0, 0.3333); +} +.toolbar .horizontal .menu li + li { + border-left: 0 none ; + border-right: 1px solid #dddddd; +} +.toolbar .horizontal .menu li:last-child { + border-left: 1px solid #dddddd; +} +.toolbar .vertical .menu .menu .menu { + margin-left: 0; + margin-right: 1.3333em; +} +.toolbar .vertical .menu .menu .menu .menu { + margin-left: 0; + margin-right: 0.25em; +} +.toolbar .vertical .menu .menu .menu a { + padding-left: 0; + padding-right: 0.5em; +} + +/** + * Orientation toggle. + */ +.toolbar .horizontal .toggle-orientation { + border-left: 0 none; + border-right: 1px solid #c9c9c9; +} +.toolbar .toggle-orientation > .lining { + float: left; +} +.toolbar .toggle-orientation button:before { + left: auto; + right: 0; +} +.toolbar .toggle-orientation [value="vertical"]:before { + background-image: url('../images/icon-toggle-vertical-rtl.png'); /* LTR */ +} diff --git a/core/modules/toolbar/css/toolbar.theme.css b/core/modules/toolbar/css/toolbar.theme.css new file mode 100644 index 0000000..ea54a80 --- /dev/null +++ b/core/modules/toolbar/css/toolbar.theme.css @@ -0,0 +1,144 @@ +/** + * @file toolbar.theme.css + */ +.toolbar { + font-family: "Source Sans Pro", "Lucida Grande", Verdana, sans-serif; + /* Set base font size to 13px based on root ems. */ + font-size: 0.8125rem; + -moz-tap-highlight-color: rgba(0,0,0,0); + -o-tap-highlight-color: rgba(0,0,0,0); + -webkit-tap-highlight-color: rgba(0,0,0,0); + tap-highlight-color: rgba(0,0,0,0); + -moz-touch-callout: none; + -o-touch-callout: none; + -webkit-touch-callout: none; + touch-callout: none; +} +.toolbar a { + cursor: pointer; + padding: 1em 1.3333em; + text-decoration: none; +} +.toolbar a:hover { + text-decoration: underline; +} + +/** + * Toolbar bar. + */ +.toolbar .bar { + background-color: #0f0f0f; + box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.3333); + color: #dddddd; +} +.toolbar .bar a:hover { + background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0.125) 20%, transparent 200%); + background-image: linear-gradient(rgba(255, 255, 255, 0.125) 20%, transparent 200%); +} +.toolbar .bar a.active { + background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0.25) 20%, transparent 200%); + background-image: linear-gradient(rgba(255, 255, 255, 0.25) 20%, transparent 200%); +} +.toolbar .bar a { + color: #ffffff; +} + +/** + * Toolbar tray. + */ +.toolbar .tray > .lining { + background-color: #ffffff; +} +.toolbar .horizontal > .lining { + padding-right: 5em; /* LTR */ +} +.toolbar .vertical > .lining, +.toolbar .vertical > .lining:before { + background-color: #ffffff; + border-right: 1px solid #aaaaaa; /* LTR */ +} +.toolbar .vertical > .lining:before { + box-shadow: -1px 0 5px 2px rgba(0, 0, 0, 0.3333); /* LTR */ +} +.toolbar .horizontal { + border-bottom: 1px solid #aaaaaa; + box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.3333); +} +.toolbar .horizontal .tray { + background-color: #f5f5f5; +} +.toolbar .tray a { + color: #333333; +} +.toolbar .horizontal .menu { + background-color: #ffffff; +} +.toolbar .horizontal .menu li + li { + border-left: 1px solid #dddddd; /* LTR */ +} +.toolbar .horizontal .menu li:last-child { + border-right: 1px solid #dddddd; /* LTR */ +} +.toolbar .vertical .menu li + li { + border-top: 1px solid #dddddd; +} +.toolbar .vertical .menu li:last-child { + border-bottom: 1px solid #dddddd; +} +.toolbar .vertical .menu .menu li { + border: 0 none; +} +.toolbar .vertical .menu ul ul { + border-bottom: 1px solid #dddddd; + border-top: 1px solid #dddddd; +} +.toolbar .vertical .menu li:last-child > ul { + border-bottom: 0; +} +.toolbar .vertical .menu .menu .menu { + margin-left: 1.3333em; /* LTR */ +} +.toolbar .vertical .menu .menu .menu .menu { + margin-left: 0.25em; /* LTR */ +} +.toolbar .vertical .menu a { + font-weight: bold; +} +.toolbar .vertical .menu .menu a { + font-weight: normal; +} +.toolbar .vertical .menu .menu .menu a { + padding-left: 0.5em; /* LTR */ +} + +/** + * Orientation toggle. + */ +.toolbar .toggle-orientation { + background-color: #f5f5f5; + padding: 0.6667em; +} +.toolbar .horizontal .toggle-orientation { + border-left: 1px solid #c9c9c9; /* LTR */ +} +.toolbar .toggle-orientation > .lining { + float: right; /* LTR */ + padding: 0.1667em; +} +.toolbar .toggle-orientation button { + cursor: pointer; + display: inline-block; + height: 16px; + padding: 0; + text-indent: -999em; + width: 20px; +} +.toolbar .toggle-orientation button:before { + left: 0; /* LTR */ +} +.toolbar .toggle-orientation [value="vertical"]:before { + background-image: url('../images/icon-toggle-vertical.png'); /* LTR */ +} +.toolbar .toggle-orientation [value="horizontal"]:before { + background-image: url('../images/icon-toggle-horizontal.png'); +} diff --git a/core/modules/toolbar/images/icon-appearance-active.png b/core/modules/toolbar/images/icon-appearance-active.png new file mode 100644 index 0000000..2b11761 --- /dev/null +++ b/core/modules/toolbar/images/icon-appearance-active.png @@ -0,0 +1,4 @@ +PNG + + IHDR tEXtSoftwareAdobe ImageReadyqe<IDATxڬ DI$LB%LN0 H@&a$B\/ZP#NIZ-ƎuIŠI؃K"=eT:+*s6ǽy+ {XA`fgdi#GXzP~'Y; +ઊ/A4Տxzs576IENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-appearance.png b/core/modules/toolbar/images/icon-appearance.png new file mode 100644 index 0000000..fd581f6 --- /dev/null +++ b/core/modules/toolbar/images/icon-appearance.png @@ -0,0 +1,4 @@ +PNG + + IHDR tEXtSoftwareAdobe ImageReadyqe<AIDATxڜ0EZ;Bsv/q|.2BJ/,%gvd+5eY6ư3<ۦi~b֓]Ao=00QF{n?#GDKT-lJV\6#xxf$t?(~KkQ@&\,2oRgBmqj{mA gE%JVh+*՛Ч3>m9 U?$tlPЧK/c_@߹5H\ . +ձcsC 0@^ǀIENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-child-collapse.png b/core/modules/toolbar/images/icon-child-collapse.png new file mode 100644 index 0000000..b7a744f --- /dev/null +++ b/core/modules/toolbar/images/icon-child-collapse.png @@ -0,0 +1,3 @@ +PNG + + IHDRVΎWtEXtSoftwareAdobe ImageReadyqe<OIDATxb`#0RP^^.YA @|qH!00F k 1HGBn(7PBH4t=!hC3>+ ?C#^x>ah ( dMx@BCha4GxCq8 e 64k~IENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-configuration.png b/core/modules/toolbar/images/icon-configuration.png new file mode 100644 index 0000000..a5d46b2 --- /dev/null +++ b/core/modules/toolbar/images/icon-configuration.png @@ -0,0 +1,3 @@ +PNG + + IHDR tEXtSoftwareAdobe ImageReadyqe<IDATxڜ-@w[Y#p8[`qp DǛdH6e6o_g^_iʐFS۶O%([PmŀK\Uu:giq'=Pg^ƞ9 #,y0#س1(ʜb eKJ%s\P݂ٞ9%nsW=Gވ‡rfyL38Rhc_P͍ Z7⃵(TKa;qzqB@)4KX O%]PMƠCЯyAIENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-content-active.png b/core/modules/toolbar/images/icon-content-active.png new file mode 100644 index 0000000..24b6982 --- /dev/null +++ b/core/modules/toolbar/images/icon-content-active.png @@ -0,0 +1,4 @@ +PNG + + IHDR tEXtSoftwareAdobe ImageReadyqe<IDATxbd@(&\ 5p6CʂC1# + B.0C i  C|ORՅ \ </G<Hur/ zIu!(| @P( O 2U# ?R݅'szPIENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-content.png b/core/modules/toolbar/images/icon-content.png new file mode 100644 index 0000000..32081b6 --- /dev/null +++ b/core/modules/toolbar/images/icon-content.png @@ -0,0 +1,3 @@ +PNG + + IHDR tEXtSoftwareAdobe ImageReadyqe<IDATxbdr @ٹ dX=4t8`>|.͌x\PdRB.0C i  C|=|”.dB@ʀ@.$@ ? Ʌr^O oZHA#GI.F0@bH)$'R蓰ѳӀ 4!IENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-extend-active.png b/core/modules/toolbar/images/icon-extend-active.png new file mode 100644 index 0000000..faa13c5 --- /dev/null +++ b/core/modules/toolbar/images/icon-extend-active.png @@ -0,0 +1,3 @@ +PNG + + IHDR tEXtSoftwareAdobe ImageReadyqe<IDATxڼ  `#F0JG0 n4#΃K.r$'ZcҸzZOB}O uhsw`6ahQԎ`( a,412*_5I0c5!|P:vMhsf͆`3 ƥ<IENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-extend.png b/core/modules/toolbar/images/icon-extend.png new file mode 100644 index 0000000..52219ff --- /dev/null +++ b/core/modules/toolbar/images/icon-extend.png @@ -0,0 +1,3 @@ +PNG + + IHDR tEXtSoftwareAdobe ImageReadyqe<,IDATxڜ10 Evb8B: la8Lt G:d۱DYeYn`6R# N`UUn&o`S)ָV\+ A 5weQi~ķ ?w5cVP*U9r'eisJ#H!L&迖[cR!5m AЏ;b'+d,F"\.uJv*BԘ+B&&'u @H@U\Ax=P ;Oa0|q(~Oa la`` 8" +4:DC l .o34iX08 ##.dA߰@&!ɷd^f ṖЁyXk "aJPCd=KT) 2$JIENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-help.png b/core/modules/toolbar/images/icon-help.png new file mode 100644 index 0000000..0a8fe2e --- /dev/null +++ b/core/modules/toolbar/images/icon-help.png @@ -0,0 +1,4 @@ +PNG + + IHDR tEXtSoftwareAdobe ImageReadyqe<>IDATxڴ0!Cv%PT V t;qD,A;0H %?m. ɷ͟M1 gzB{RTah+!|fLN27 '@]y s:TSkWBf~.B ֦$LKV.w%IML&=+'P܏P}*N m\;`8J3h뼙[`%ȣLQґIwR +Դ[Dy:9\.c@w -M#6suF}}#?D9ot:[+WmBQ*/*G.)qz$ UZpNj`۶{.Hk*>LO0{ +0\ lJIENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-home.png b/core/modules/toolbar/images/icon-home.png new file mode 100644 index 0000000..5d8d501 --- /dev/null +++ b/core/modules/toolbar/images/icon-home.png @@ -0,0 +1,6 @@ +PNG + + IHDRĴl;tEXtSoftwareAdobe ImageReadyqe<IDATxԔA +0E xGH;UqJ#. ( GԊ ?1h02*B 8MS +a! J,bN G3/H$s8qUUkIpE +!ɄAuJb}:yh3PEQu]hymEUU8Y' m8ذޘG3M5MC#&/7a],uDS)~o=ʱIENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-menu-active.png b/core/modules/toolbar/images/icon-menu-active.png new file mode 100644 index 0000000..ab6462e --- /dev/null +++ b/core/modules/toolbar/images/icon-menu-active.png @@ -0,0 +1,3 @@ +PNG + + IHDRĴl;tEXtSoftwareAdobe ImageReadyqe<IIDATxb``v,Pia0M`_~b߿xW^Ǵ 4Iq2{LIENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-menu.png b/core/modules/toolbar/images/icon-menu.png new file mode 100644 index 0000000..a02939f --- /dev/null +++ b/core/modules/toolbar/images/icon-menu.png @@ -0,0 +1,3 @@ +PNG + + IHDRĴl;tEXtSoftwareAdobe ImageReadyqe<\IDATxbb` $o kDΖD" gJ.| 2ynd$`UI &11; 9dsIENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-reports-active.png b/core/modules/toolbar/images/icon-reports-active.png new file mode 100644 index 0000000..96f4673 --- /dev/null +++ b/core/modules/toolbar/images/icon-reports-active.png @@ -0,0 +1,4 @@ +PNG + + IHDR tEXtSoftwareAdobe ImageReadyqe<IDATxڬ ]Fp6N  :BGTr<.,3w] +#IhT*TD :L0(]'!+%N!g;&}XMQoRy8c67`'R)zX (Sx/Q#%eF?-Nڦ-@4rdL7U O)ouеQtủ+as|47 zIENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-reports.png b/core/modules/toolbar/images/icon-reports.png new file mode 100644 index 0000000..49ede88 --- /dev/null +++ b/core/modules/toolbar/images/icon-reports.png @@ -0,0 +1,5 @@ +PNG + + IHDR tEXtSoftwareAdobe ImageReadyqe< IDATxڬT 0 LQdF00B_}Ͼ `f26 +2IKX&.ڶR1{Ld"f:@ ih1sAUJd0`S=|`g(!j͒\΅" ۳*5Jr8!DF5:4G] +xt#oQ ϶ K4q:cE&2HO0G^yc,tDHY3 w'^ :3PdVIENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-structure-active.png b/core/modules/toolbar/images/icon-structure-active.png new file mode 100644 index 0000000..3ab2375 --- /dev/null +++ b/core/modules/toolbar/images/icon-structure-active.png @@ -0,0 +1,3 @@ +PNG + + IHDR tEXtSoftwareAdobe ImageReadyqe<IDATxb`q$#r"uHc 0QT7PxAH0쨛H5Dp([#6 #wf t)cb V PB 6ʡB~(|9Wr\Q@^ `c'6CIENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-structure.png b/core/modules/toolbar/images/icon-structure.png new file mode 100644 index 0000000..7a8302f --- /dev/null +++ b/core/modules/toolbar/images/icon-structure.png @@ -0,0 +1,3 @@ +PNG + + IHDR tEXtSoftwareAdobe ImageReadyqe<IDATxb`qdEEr"u6=,,VCL2 $H^s@b?f`/3%JJ,Xҗ#./q'x b +bz,/ 1jZ`@ArC' "`+@C0nj+Sލu\IENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-toggle-horizontal.png b/core/modules/toolbar/images/icon-toggle-horizontal.png new file mode 100644 index 0000000..759701c --- /dev/null +++ b/core/modules/toolbar/images/icon-toggle-horizontal.png @@ -0,0 +1,3 @@ +PNG + + IHDRtEXtSoftwareAdobe ImageReadyqe<cIDATxb,//g 01諍;::HSQQAmG|7o>{,Km@ G ~ڮ^6 (H,}j0p#mVIENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-toggle-vertical-rtl.png b/core/modules/toolbar/images/icon-toggle-vertical-rtl.png new file mode 100644 index 0000000..95e3fba --- /dev/null +++ b/core/modules/toolbar/images/icon-toggle-vertical-rtl.png @@ -0,0 +1,3 @@ +PNG + + IHDRtEXtSoftwareAdobe ImageReadyqe<hIDATxb,//g qGGAu\&mW^%GŋϞ=K6 X $kxt$,$}}}IjllLm$$A= Zz#`u8: BIENDB` \ No newline at end of file diff --git a/core/modules/toolbar/images/icon-toggle-vertical.png b/core/modules/toolbar/images/icon-toggle-vertical.png new file mode 100644 index 0000000..dd3240e --- /dev/null +++ b/core/modules/toolbar/images/icon-toggle-vertical.png @@ -0,0 +1,3 @@ +PNG + + IHDRtEXtSoftwareAdobe ImageReadyqe<kIDATxb,//g ;::ꩨ`b vU={vń 6o|QV^ |-44ؘB4ABrM aLoh0Z}8IENDB` \ No newline at end of file diff --git a/core/modules/toolbar/js/toolbar.js b/core/modules/toolbar/js/toolbar.js new file mode 100644 index 0000000..3265ea9 --- /dev/null +++ b/core/modules/toolbar/js/toolbar.js @@ -0,0 +1,337 @@ +/** + * @file toolbar.js + * + * Defines the behavior of the Drupal administration toolbar. + */ +(function ($, Drupal, drupalSettings) { + +"use strict"; + +Drupal.toolbar = Drupal.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 trays to maintain them across page loads. + */ +var orientation = JSON.parse(localStorage.getItem('Drupal.toolbar.trayOrientation')) || 'vertical'; +var locked = JSON.parse(localStorage.getItem('Drupal.toolbar.trayLocked')) || false; + +/** + * Holds the jQuery objects of the toolbar DOM element, the trays and messages. + */ +var $toolbar; +var $trays; +var $messages; + +/** + * Holds the mediaQueryList object. + */ +var mql = { + standard: null, + wide: null +}; + +/** + * Register 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) { + var options = $.extend(this.options, drupalSettings.toolbar); + $toolbar = $(context).find('#toolbar-administration').once('toolbar'); + if ($toolbar.length) { + // Add subtrees. + // @todo Optimize this to delay adding each subtree to the DOM until it is + // needed; however, take into account screen readers for determining + // when the DOM elements are needed. + if (Drupal.toolbar.subtrees) { + for (var id in Drupal.toolbar.subtrees) { + $('#toolbar-link-' + id).after(Drupal.toolbar.subtrees[id]); + } + } + // Append a messages element for appending interaction updates for screen + // readers. + $messages = $(Drupal.theme('toolbarMessageBox')).appendTo($toolbar); + // Store the trays in a scoped variable. + $trays = $toolbar.find('.tray'); + $trays + // Add the tray orientation toggles. + .find('.lining') + .append(Drupal.theme('toolbarOrientationToggle')); + // Set the active state of the orientation toggles. + changeOrientation(orientation, locked); + // Store media queries. + mql.standard = window.matchMedia(options.breakpoints['module.toolbar.standard']); + // Set up switching between the vertical and horizontal presentation + // of the toolbar trays based on a breakpoint. + mql.wide = window.matchMedia(options.breakpoints['module.toolbar.wide']); + mql.wide.addListener(Drupal.toolbar.mediaQueryChangeHandler); + if (mql.wide.matches) { + Drupal.toolbar.mediaQueryChangeHandler(mql.wide); + } + // 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); + // Attach behavior to the window. + $(window) + .on('resize.toolbar', setHeight); + // Attach behaviors to the toolbar. + $toolbar + .on('click.toolbar', '.bar a', Drupal.toolbar.toggleTray) + .on('click.toolbar', '.toggle-orientation button', Drupal.toolbar.orientationChangeHandler); + // Decorate the main menu with an interactive menu. + $toolbar.find('.administration.tray .toolbar-menu > .menu').toolbarMenu(); + // Restore the open tab. Only open the tab on wide screens. + if (activeTab && window.matchMedia(options.breakpoints['module.toolbar.standard']).matches) { + $toolbar.find('[data-toolbar-tray="' + activeTab + '"]').trigger('click.toolbar'); + } + // Recalculate the offset top of the toolbar once on initialization. + else { + Drupal.toolbar.setHeight(); + } + } + }, + // Default options. + options: { + breakpoints: { + 'module.toolbar.standard': '', + 'module.toolbar.wide': '' + } + } +}; + +/** + * Set subtrees. + */ +Drupal.toolbar.setSubtrees = function(subtrees) { + Drupal.toolbar.subtrees = subtrees; +} + +/** + * Toggle a toolbar tab and the associated tray. + */ +Drupal.toolbar.toggleTray = function (event) { + var strings = { + opened: Drupal.t('opened'), + closed: Drupal.t('closed') + }; + var $tab = $(event.target); + var name = $tab.attr('data-toolbar-tray'); + // Activate the selected tab and associated tray. + var $activateTray = $toolbar.find('[data-toolbar-tray="' + name + '"].tray').toggleClass('active'); + if ($activateTray.length) { + event.preventDefault(); + event.stopPropagation(); + $tab.toggleClass('active'); + // Toggle aria-pressed. + var value = $tab.attr('aria-pressed'); + $tab.attr('aria-pressed', (value === 'false') ? 'true' : 'false'); + // Append a message that a tray has been opened. + setMessage(Drupal.t('@tray tray @state.', { + '@tray': name, + '@state': (value === 'true') ? strings.closed : strings.opened + })); + // Store the active tab name or remove the setting. + if ($tab.hasClass('active')) { + localStorage.setItem('Drupal.toolbar.activeTab', JSON.stringify(name)); + } + else { + localStorage.removeItem('Drupal.toolbar.activeTab'); + } + // Disable non-selected tabs and trays. + $toolbar.find('.bar a') + .not($tab) + .removeClass('active') + // Set aria-pressed to false. + .attr('aria-pressed', 'false'); + $toolbar.find('.tray').not($activateTray).removeClass('active'); + // Adjust the body to accommodate trays. + setBodyState(); + // Adjust the height of the toolbar. + Drupal.toolbar.setHeight(); + } +}; + +/** + * 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. + */ +Drupal.toolbar.setHeight = function () { + // Set the top of the all the trays to the height of the bar. + var barHeight = $toolbar.find('.bar').outerHeight(); + var height = barHeight; + var bhpx = barHeight + 'px'; + var tray; + for (var i = 0, il = $trays.length; i < il; i++) { + tray = $trays[i]; + if (!tray.style.top.length || (tray.style.top !== bhpx)) { + tray.style.top = bhpx; + } + } + /** + * Get the height of the active tray and include it in the total + * height of the toolbar. + */ + height += $trays.filter('.active.horizontal').outerHeight() || 0; + // Indicate the height of the toolbar in the attribute data-offset-top. + var offset = parseInt($toolbar.attr('data-offset-top'), 10); + 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).trigger('resize'); + } +}; + +/** + * Respond to configured media query applicability changes. + */ +Drupal.toolbar.mediaQueryChangeHandler = function (mql) { + if (!locked) { + var orientation = (mql.matches) ? 'horizontal' : 'vertical'; + changeOrientation(orientation); + // Adjust the body to accommodate trays. + setBodyState(); + // Adjust the height of the toolbar. + Drupal.toolbar.setHeight(); + } +}; + +/** + * Respond to the toggling of the tray orientation. + */ +Drupal.toolbar.orientationChangeHandler = function (event) { + event.preventDefault(); + event.stopPropagation(); + var $button = $(event.target); + var orientation = event.target.value; + var $tray = $button.closest('.tray'); + changeOrientation(orientation, true); + // Adjust the body to accommodate trays. + setBodyState(); + // Adjust the height of the toolbar. + Drupal.toolbar.setHeight(); +}; + +/** + * Change the orientation of the tray between vertical and horizontal. + * + * @param {String} newOrientation + * Either 'vertical' or 'horizontal'. The orientation to change the tray to. + * + * @param {Boolean} isLock + * Whether the orientation of the tray should be locked if it is being toggled + * to vertical. + */ +function changeOrientation (newOrientation, isLock) { + var oldOrientation = orientation; + if (isLock) { + locked = (newOrientation === 'vertical'); + if (locked) { + localStorage.setItem('Drupal.toolbar.trayLocked', JSON.stringify(locked)); + } + else { + localStorage.removeItem('Drupal.toolbar.trayLocked'); + } + } + if ((!locked && newOrientation === 'horizontal') || newOrientation === 'vertical') { + $trays + .removeClass('horizontal vertical') + .addClass(newOrientation); + orientation = newOrientation; + toggleOrientationToggle((newOrientation === 'vertical') ? 'horizontal' : 'vertical'); + } + // Store the orientation to maintain it across page loads. + localStorage.setItem('Drupal.toolbar.trayOrientation', JSON.stringify(newOrientation)); +} + +/** + * Mark up the body tag to reflect the current state of the toolbar. + */ +function setBodyState () { + var $activeTray = $trays.filter('.active'); + $('body') + .toggleClass('toolbar-tray-open', !!$activeTray.length) + .toggleClass('toolbar-vertical', (!!$activeTray.length && orientation === 'vertical')) + .toggleClass('toolbar-horizontal', (!!$activeTray.length && orientation === 'horizontal')); +} + +/** + * Change the orientation toggle active state. + */ +function toggleOrientationToggle (orientation) { + var strings = { + horizontal: Drupal.t('Horizontal orientation'), + vertical: Drupal.t('Vertical orientation') + }; + var antiOrientation = (orientation === 'vertical') ? 'horizontal' : 'vertical'; + var iconClass = 'icon-toggle-' + orientation; + var iconAntiClass = 'icon-toggle-' + antiOrientation; + // Append a message that the tray orientation has been changed. + setMessage(Drupal.t('Tray orientation changed to @orientation.', { + '@orientation': antiOrientation + })); + // Change the tray orientation. + $trays.find('.toggle-orientation button') + .val(orientation) + .text(strings[orientation]) + .removeClass(iconAntiClass) + .addClass(iconClass); +} + +/** + * Places the message in the toolbar's ARIA live message area. + * + * The message will be read by speaking User Agents. + * + * @param {String} message + * A string to be inserted into the message area. + */ +function setMessage (message) { + $messages.html(Drupal.theme('toolbarTrayMessage', message)); +} + +/** + * 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 '
' + + '' + + '
'; +}; + +/** + * A region to post messages that a screen reading UA will announce. + * + * @return {String} + * A string representing a DOM fragment. + */ +Drupal.theme.toolbarMessageBox = function () { + return '
'; +}; + +/** + * Wrap a message string in a p tag. + * + * @return {String} + * A string representing a DOM fragment. + */ +Drupal.theme.toolbarTrayMessage = function (message) { + return '

' + message + '

'; +}; + +}(jQuery, Drupal, drupalSettings)); diff --git a/core/modules/toolbar/js/toolbar.menu.js b/core/modules/toolbar/js/toolbar.menu.js new file mode 100644 index 0000000..75ddbe3 --- /dev/null +++ b/core/modules/toolbar/js/toolbar.menu.js @@ -0,0 +1,170 @@ +/** + * Builds a nested accordion widget. + * + * Invoke on an HTML list element with the jQuery plugin pattern. + * - For example, $('.menu').toolbarMenu(); + */ + +(function ($, Drupal) { + +"use strict"; + +/** + * Store the open menu tray. + */ +var openItem = JSON.parse(localStorage.getItem('Drupal.toolbar.menu.openItem')); + + $.fn.toolbarMenu = function () { + + var ui = { + 'handleOpen': Drupal.t('Extend'), + 'handleClose': Drupal.t('Collapse') + }; + /** + * Handle clicks from the disclosure button on an item with sub-items. + * + * @param {Object} event + * A jQuery Event object. + */ + function toggleClickHandler (event) { + var $toggle = $(event.target); + var $item = $toggle.closest('li'); + // Toggle the list item. + toggleList($item); + // Close open siblings and their open children. + var $openItems = $item.siblings().filter('.open'); + toggleList($openItems, false); + // Save link of the closest open item through a unique selector. + var href = $toggle.siblings('a[href]').attr('href'); + if (href) { + localStorage.setItem('Drupal.toolbar.menu.openItem', JSON.stringify(href)); + } + else { + localStorage.removeItem('Drupal.toolbar.menu.openItem'); + } + } + /** + * Toggle the open/close state of a list is a menu. + * + * @param {jQuery} $item + * The li item to be toggled. + * + * @param {Boolean} switcher + * A flag that forces toggleClass to add or a remove a class, rather than + * simply toggling its presence. + */ + function toggleList ($item, switcher) { + var $toggle = $item.find('> .box > .handle'); + switcher = (typeof switcher !== 'undefined') ? switcher : !$item.hasClass('open'); + // Toggle the item open state. + $item.toggleClass('open', switcher); + // Twist the toggle. + $toggle.toggleClass('open', switcher); + // Adjust the toggle text. + $toggle + .find('.action') + // Expand Structure, Collapse Structure + .text((switcher) ? ui.handleClose : ui.handleOpen); + } + /** + * Add markup to the menu elements. + * + * Items with sub-elements have a list toggle attached to them. Menu item + * links and the corresponding list toggle are wrapped with in a div + * classed with .box. The .box div provides a positioning context for the + * item list toggle. + * + * @param {jQuery} $menu + * The root of the menu to be initialized. + */ + function initItems ($menu) { + var options = { + 'class': 'icon handle', + 'action': ui.handleOpen, + 'text': '' + }; + // Initialize items and their links. + $menu.find('li > a').wrap('
'); + // Add a handle to each list item if it has a menu. + $menu.find('li').each(function (index, element) { + var $item = $(element); + if ($item.find('> ul.menu').length) { + var $box = $item.find('> .box'); + options.text = Drupal.t('@label', {'@label': $box.find('a').text()}); + $item.find('> .box') + .append(Drupal.theme('toolbarMenuItemToggle', options)); + } + }); + } + /** + * Adds a level class to each list based on its depth in the menu. + * + * This function is called recursively on each sub level of lists elements + * until the depth of the menu is exhausted. + * + * @param {jQuery} $lists + * A jQuery object of ul elements. + * + * @param {Integer} level + * The current level number to be assigned to the list elements. + */ + function markListLevels ($lists, level) { + level = (!level) ? 1 : level; + var $lis = $lists.find('> li').addClass('level-' + level); + $lists = $lis.find('> ul'); + if ($lists.length) { + markListLevels($lists, level + 1); + } + } + /** + * Marks the trail of the active link in the menu back to the root of the + * menu. + * + * @param {jQuery} $menu + * The root of the menu. + */ + function traceActiveTrail ($menu) { + $menu.find('a.active').parentsUntil('.root', 'li').addClass('active-trail'); + } + /** + * On page load, open the active menu item. + * + * @param {jQuery} $menu + * The root of the menu. + */ + function openActiveItem ($menu) { + var $activeItem = $menu.find('a.active'); + if ($activeItem.attr('href') === location.pathname) { + toggleList($menu.find('a[href="' + location.pathname + '"]').parentsUntil('.root', 'li'),true); + localStorage.setItem('Drupal.toolbar.menu.openItem', JSON.stringify(location.pathname)); + } + else if (openItem) { + toggleList($menu.find('a[href="' + openItem + '"]').parentsUntil('.root', 'li'), true); + } + } + // Bind event handlers. + $(document).on('click.toolbar', '.handle', toggleClickHandler); + return this.each(function (selector) { + var $menu = $(this).once('toolbar-menu'); + if ($menu.length) { + $menu.addClass('root'); + initItems($menu); + markListLevels($menu); + // Restore previous and active states. + traceActiveTrail($menu); + openActiveItem($menu); + } + }); + }; + + /** + * A toggle is an interactive element often bound to a click handler. + * + * @return {String} + * A string representing a DOM fragment. + */ + Drupal.theme.toolbarMenuItemToggle = function (options) { + return ''; + }; + +}(jQuery, Drupal)); diff --git a/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarHookToolbarTest.php b/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarHookToolbarTest.php new file mode 100644 index 0000000..442eb4a --- /dev/null +++ b/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarHookToolbarTest.php @@ -0,0 +1,57 @@ + 'Toolbar hook_toolbar', + 'description' => 'Tests the implementation of hook_toolbar by a module.', + 'group' => 'Toolbar', + ); + } + + function setUp() { + parent::setUp(); + + // Create an administrative user and log it in. + $this->admin_user = $this->drupalCreateUser(array('access toolbar')); + $this->drupalLogin($this->admin_user); + } + + /** + * Tests for inclusion of a tab and tray in the toolbar by a module + * implementing hook_toolbar. + */ + function testHookToolbar() { + $this->drupalGet('/node'); + $this->assertResponse(200); + + // Assert that the toolbar is present in the HTML. + $this->assertRaw('id="toolbar-administration"'); + + // Assert that the tab registered by toolbar_test is present. + $this->assertRaw('id="toolbar-tab-testing"'); + + // Assert that the tray registered by toolbar_test is present. + $this->assertRaw('id="toolbar-tray-testing"'); + } +} diff --git a/core/modules/toolbar/templates/toolbar.tpl.php b/core/modules/toolbar/templates/toolbar.tpl.php deleted file mode 100644 index b3d561c..0000000 --- a/core/modules/toolbar/templates/toolbar.tpl.php +++ /dev/null @@ -1,33 +0,0 @@ - - diff --git a/core/modules/toolbar/templates/toolbar.twig b/core/modules/toolbar/templates/toolbar.twig new file mode 100644 index 0000000..c2181df --- /dev/null +++ b/core/modules/toolbar/templates/toolbar.twig @@ -0,0 +1,39 @@ +{# +/** + * @file + * Default template for admin toolbar. + * + * Available variables: + * + * - tabs: Themed links for the top level tabs. + * - trays: An array of trays. It contains: + * - content: The themed tray content. + * - attributes: HTML attributes for the surrounding element. It includes: + * - id: The unique id of the tray. This corresponds to the module name + * registered the tray. + * - class: A list of classes to target the trays for styling. + * - attributes: HTML attributes for the surrounding element. It includes: + * - id: The unique id of the toolbar. + * - class: A list of classes to target the toolbar for styling. + * + * @see template_preprocess() + * @see template_preprocess_toolbar() + * + * @ingroup themeable + */ +#} + + diff --git a/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.info b/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.info new file mode 100644 index 0000000..b8e0c59 --- /dev/null +++ b/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.info @@ -0,0 +1,6 @@ +name = "Toolbar module API tests" +description = "Support module for toolbar testing." +package = Testing +version = VERSION +core = 8.x +hidden = TRUE diff --git a/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module b/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module new file mode 100644 index 0000000..cadddc9 --- /dev/null +++ b/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module @@ -0,0 +1,40 @@ +'), + l('link 2', ''), + l('link 3', ''), + ); + $items['testing'] = array( + 'tab' => array( + 'title' => t('Test tab'), + 'href' => '', + 'html' => FALSE, + 'attributes' => array( + 'title' => t('Test tab'), + ), + ), + 'tray' => array( + '#heading' => t('Test tray'), + 'content' => array( + '#theme' => 'item_list', + '#items' => $tray_items, + '#attributes' => array( + 'class' => array('menu'), + ), + ), + ), + 'weight' => 50, + ); + + return $items; +} diff --git a/core/modules/toolbar/toolbar-rtl.css b/core/modules/toolbar/toolbar-rtl.css deleted file mode 100644 index e121547..0000000 --- a/core/modules/toolbar/toolbar-rtl.css +++ /dev/null @@ -1,37 +0,0 @@ - -#toolbar, -#toolbar * { - text-align: right; -} -#toolbar ul li { - float: right; -} -#toolbar ul li a { - display: inline-block; - float: none; - zoom: 1; -} -#toolbar div.toolbar-menu { - padding: 5px 50px 5px 50px; -} -#toolbar-user { - float: left; -} -#toolbar ul#toolbar-user li { - float: none; - display: inline; -} -#toolbar-menu { - float: none; -} -#toolbar-home { - float: right; -} -#toolbar ul li.home a { - position: absolute; - right: 10px; -} -#toolbar div.toolbar-menu a.toggle { - left: 10px; - right: auto; -} diff --git a/core/modules/toolbar/toolbar.api.php b/core/modules/toolbar/toolbar.api.php new file mode 100644 index 0000000..42ca3fe --- /dev/null +++ b/core/modules/toolbar/toolbar.api.php @@ -0,0 +1,106 @@ + array( + 'title' => t('Home'), + 'href' => '', + 'html' => FALSE, + 'attributes' => array( + 'title' => t('Home page'), + ), + ), + 'weight' => -10, + ); + + /** + * A tab may be associated with a tray. + * + * The tray should contain a renderable array. An option #heading property + * can be passed. The text is written to a heading tag in the tray as a + * landmark for accessibility. A default heading will be created if one is not + * passed. + */ + $items['commerce'] = array( + 'tab' => array( + 'title' => t('Shopping cart'), + 'href' => '', + 'html' => FALSE, + 'attributes' => array( + 'title' => t('Shopping cart'), + ), + ), + 'tray' => array( + '#heading' => t('Shopping cart actions'), + 'content' => array( + '#theme' => 'item_list', + '#items' => array( /* An item list renderable array */ ), + ), + ), + 'weight' => 50, + ); + + return $items; +} + +/** + * Alter the Toolbar menu after hook_toolbar() is invoked. + * + * This hook is invoked by toolbar_view() immediately after hook_toolbar(). The + * toolbar definitions are passed in by reference. Each element of the $items + * array is one item returned by a module from hook_toolbar(). Additional items + * may be added, or existing items altered. + * + * @param $items + * Associative array of Toolbar menu definitions returned from hook_toolbar(). + */ +function hook_toolbar_alter(&$items) { + // Move the User tab to the right. + $items['commerce']['weight'] = 5; +} + +/** + * @} End of "addtogroup hooks". + */ diff --git a/core/modules/toolbar/toolbar.css b/core/modules/toolbar/toolbar.css deleted file mode 100644 index bd18110..0000000 --- a/core/modules/toolbar/toolbar.css +++ /dev/null @@ -1,129 +0,0 @@ - -body.toolbar { - padding-top: 2.2em; -} -body.toolbar-drawer { - padding-top: 5.3em; -} - -/** - * Aggressive resets so we can achieve a consistent look in hostile CSS - * environments. - */ -#toolbar, -#toolbar * { - border: 0; - font-size: 100%; - line-height: inherit; - list-style: none; - margin: 0; - outline: 0; - padding: 0; - text-align: left; /* LTR */ - vertical-align: baseline; -} - -/** - * Base styles. - * - * We use a keyword for the toolbar font size to make it display consistently - * across different themes, while still allowing browsers to resize the text. - */ -#toolbar { - background: #666; - color: #ccc; - font: normal small "Lucida Grande", Verdana, sans-serif; - left: 0; - margin: 0 -20px; - padding: 0 20px; - position: fixed; - right: 0; - top: 0; - box-shadow: 0 3px 20px #000; - z-index: 600; -} -#toolbar div.collapsed { - display: none; - visibility: hidden; -} -#toolbar a { - color: #fff; - font-size: .846em; - text-decoration: none; -} -#toolbar ul li, -#toolbar ul li a { - float: left; /* LTR */ -} - -/** - * Administration menu. - */ -#toolbar div.toolbar-menu { - background: #000; - line-height: 20px; - padding: 5px 50px 5px 10px; /* LTR */ - position: relative; -} -#toolbar-home a span { - background: url(toolbar.png) no-repeat 0 -45px; - display: block; - height: 14px; - margin: 3px 0px; - text-indent: -9999px; - vertical-align: text-bottom; - width: 11px; -} -#toolbar-user { - float: right; /* LTR */ -} -#toolbar-menu { - float: left; /* LTR */ -} -#toolbar div.toolbar-menu a.toggle { - background: url(toolbar.png) 0 -20px no-repeat; - bottom: 0; - cursor: pointer; - height: 25px; - overflow: hidden; - position: absolute; - right: 10px; /* LTR */ - text-indent: -9999px; - width: 25px; -} -#toolbar div.toolbar-menu a.toggle:focus, -#toolbar div.toolbar-menu a.toggle:hover { - background-position: -50px -20px; -} -#toolbar div.toolbar-menu a.toggle-active { - background-position: -25px -20px; -} -#toolbar div.toolbar-menu a.toggle-active.toggle:focus, -#toolbar div.toolbar-menu a.toggle-active.toggle:hover { - background-position: -75px -20px; -} -#toolbar div.toolbar-menu ul li a { - padding: 0 10px; - border-radius: 10px; -} -#toolbar div.toolbar-menu ul li a:focus, -#toolbar div.toolbar-menu ul li a:hover, -#toolbar div.toolbar-menu ul li a:active, -#toolbar div.toolbar-menu ul li a.active:focus { - background: #444; -} -#toolbar div.toolbar-menu ul li a.active:hover, -#toolbar div.toolbar-menu ul li a.active:active, -#toolbar div.toolbar-menu ul li a.active, -#toolbar div.toolbar-menu ul li.active-trail a { - background: url(toolbar.png) 0 0 repeat-x; - text-shadow: #333 0 1px 0; -} - -/** - * Collapsed drawer of additional toolbar content. - */ -#toolbar div.toolbar-drawer { - position: relative; - padding: 0 10px; -} diff --git a/core/modules/toolbar/toolbar.info b/core/modules/toolbar/toolbar.info index 758dc9c..a6fd841 100644 --- a/core/modules/toolbar/toolbar.info +++ b/core/modules/toolbar/toolbar.info @@ -3,3 +3,7 @@ description = Provides a toolbar that shows the top-level administration menu it core = 8.x package = Core version = VERSION + +dependencies[] = breakpoint + +configure = admin/structure/toolbar diff --git a/core/modules/toolbar/toolbar.install b/core/modules/toolbar/toolbar.install new file mode 100644 index 0000000..2b23e3d --- /dev/null +++ b/core/modules/toolbar/toolbar.install @@ -0,0 +1,46 @@ +' . t('Uses') . ''; $output .= '
'; $output .= '
' . t('Displaying administrative links') . '
'; - $output .= '
' . t('The Toolbar module displays a bar containing top-level administrative links across the top of the screen. Below that, the Toolbar module has a drawer section where it displays links provided by other modules, such as the core Shortcut module. The drawer can be hidden/shown by using the show/hide shortcuts link at the end of the toolbar.', array('@shortcuts-help' => url('admin/help/shortcut'))) . '
'; + $output .= '
' . t('The Toolbar module displays a bar containing top-level administrative links across the top of the screen. Below that, the Toolbar module has a drawer section where it displays links provided by other modules, such as the core Shortcut module. The drawer can be hidden/shown by clicking on its corresponding tab.', array('@shortcuts-help' => url('admin/help/shortcut'))) . '
'; $output .= '
'; return $output; } @@ -41,12 +44,6 @@ function toolbar_theme($existing, $type, $theme, $path) { 'render element' => 'toolbar', 'template' => 'toolbar', ); - $items['toolbar_toggle'] = array( - 'variables' => array( - 'collapsed' => NULL, - 'attributes' => array(), - ), - ); return $items; } @@ -54,62 +51,76 @@ function toolbar_theme($existing, $type, $theme, $path) { * Implements hook_menu(). */ function toolbar_menu() { - $items['toolbar/toggle'] = array( - 'title' => 'Toggle drawer visibility', + $items['toolbar/subtrees/%'] = array( + 'page callback' => 'toolbar_subtrees_jsonp', + 'page arguments' => array(2), + 'access callback' => '_toolbar_subtrees_access', + 'access arguments' => array(2), 'type' => MENU_CALLBACK, - 'page callback' => 'toolbar_toggle_page', - 'access arguments' => array('access toolbar'), ); return $items; } /** - * Page callback: Toggles the visibility of the toolbar drawer. + * Access callback: Returns if the user has access to the rendered subtree requested by the hash. * * @see toolbar_menu(). */ -function toolbar_toggle_page() { - global $base_path; - // Toggle the value in the cookie. - setcookie('Drupal.toolbar.collapsed', !_toolbar_is_collapsed(), NULL, $base_path); - // Redirect the user from where he used the toggle element. - drupal_goto(); +function _toolbar_subtrees_access($hash) { + return user_access('access toolbar') && ($hash == _toolbar_get_subtree_hash()); } /** - * Formats an element used to toggle the toolbar drawer's visibility. - * - * @param $variables - * An associative array containing: - * - collapsed: A boolean value representing the toolbar drawer's visibility. - * - attributes: An associative array of HTML attributes. + * Page callback: Returns the rendered subtree of each top-level toolbar link. * - * @return - * An HTML string representing the element for toggling. - * - * @ingroup themable + * @see toolbar_menu(). */ -function theme_toolbar_toggle($variables) { - if ($variables['collapsed']) { - $toggle_text = t('Show shortcuts'); - } - else { - $toggle_text = t('Hide shortcuts'); - $variables['attributes']['class'][] = 'toggle-active'; - } - return l($toggle_text, 'toolbar/toggle', array('query' => drupal_get_destination(), 'attributes' => array('title' => $toggle_text) + $variables['attributes'])); +function toolbar_subtrees_jsonp($hash) { + _toolbar_initialize_page_cache(); + $subtrees = toolbar_get_rendered_subtrees(); + $response = new JsonResponse($subtrees); + $response->setCallback('Drupal.toolbar.setSubtrees'); + return $response; } /** - * Determines the current state of the toolbar drawer's visibility. + * Use Drupal's page cache for toolbar/subtrees/*, even for authenticated users. * - * @return - * TRUE when drawer is collapsed, FALSE when it is expanded. + * This gets invoked after full bootstrap, so must duplicate some of what's + * done by _drupal_bootstrap_page_cache(). + * + * @todo Replace this hack with something better integrated with DrupalKernel + * once Drupal's page caching itself is properly integrated. */ -function _toolbar_is_collapsed() { - // PHP converts dots into underscores in cookie names to avoid problems with - // its parser, so we use a converted cookie name. - return isset($_COOKIE['Drupal_toolbar_collapsed']) ? $_COOKIE['Drupal_toolbar_collapsed'] : 0; +function _toolbar_initialize_page_cache() { + $GLOBALS['conf']['system.performance']['cache']['page']['enabled'] = TRUE; + drupal_page_is_cacheable(TRUE); + + // If we have a cache, serve it. + // @see _drupal_bootstrap_page_cache() + $cache = drupal_page_get_cache(); + if (is_object($cache)) { + header('X-Drupal-Cache: HIT'); + // Restore the metadata cached with the page. + $_GET['q'] = $cache->data['path']; + date_default_timezone_set(drupal_get_user_timezone()); + + drupal_serve_page_from_cache($cache); + + // We are done. + exit; + } + + // Otherwise, create a new page response (that will be cached). + header('X-Drupal-Cache: MISS'); + + // The Expires HTTP header is the heart of the client-side HTTP caching. The + // additional server-side page cache only takes effect when the client + // accesses the callback URL again (e.g., after clearing the browser cache or + // when force-reloading a Drupal page). + $max_age = 3600 * 24 * 365; + drupal_add_http_header('Expires', gmdate(DATE_RFC1123, REQUEST_TIME + $max_age)); + drupal_add_http_header('Cache-Control', 'private, max-age=' . $max_age); } /** @@ -121,7 +132,6 @@ function toolbar_page_build(&$page) { $page['page_top']['toolbar'] = array( '#pre_render' => array('toolbar_pre_render'), '#access' => user_access('access toolbar'), - 'toolbar_drawer' => array(), ); } @@ -139,27 +149,42 @@ function toolbar_pre_render($toolbar) { } /** - * Implements hook_preprocess_HOOK() for html.tpl.php. - * - * Add some page classes, so global page theming can adjust to the toolbar. + * Implements template_preprocess_HOOK(). */ -function toolbar_preprocess_html(&$vars) { - if (isset($vars['page']['page_top']['toolbar']) && user_access('access toolbar')) { - $vars['attributes']['class'][] = 'toolbar'; - if (!_toolbar_is_collapsed()) { - $vars['attributes']['class'][] = 'toolbar-drawer'; - } - } -} +function template_preprocess_toolbar(&$variables) { + // Metadata for the toolbar wrapping element. + $variables['attributes'] = new Attribute(array( + // The id cannot be simply "toolbar" or it will clash with the simpletest + // tests listing which produces a checkbox with attribute id="toolbar" + 'id' => 'toolbar-administration', + // The 'overlay-displace-top' class pushes the overlay down, so it appears + // below the toolbar. + 'class' => array('toolbar', 'overlay-displace-top'), + 'role' => 'navigation' + )); -/** - * Implements hook_preprocess_HOOK() for toolbar.tpl.php. - * - * Adding the 'overlay-displace-top' class to the toolbar pushes the overlay - * down, so it appears below the toolbar. - */ -function toolbar_preprocess_toolbar(&$variables) { - $variables['attributes']['class'][] = "overlay-displace-top"; + // Provide a convenience variable for the themed tabs. + $variables['toolbar']['tabs']['#attributes']['class'][] = 'overlay-displace-top'; + $variables['tabs'] = $variables['toolbar']['tabs']; + + // Place the tabs in a top-level variable so that attribute information + // can be associated with each one. + foreach ($variables['toolbar']['trays'] as $key => $tray) { + // Create tray heading text. Prefer the provided heading text if it exists. + $heading = isset($tray['#heading']) ? $tray['#heading'] : t('@group actions', array('@group' => $key)); + + $variables['trays'][$key] = array( + 'heading' => $heading, + 'content' => $variables['toolbar']['trays'][$key], + 'attributes' => new Attribute(array( + 'id' => 'toolbar-tray-' . $key, + 'class' => array('tray', 'overlay-displace-top', $key), + 'data-toolbar-tray' => $key, + 'aria-owned-by' => 'toolbar-tab-' . $key, + ) + ), + ); + } } /** @@ -179,93 +204,148 @@ function toolbar_system_info_alter(&$info, $file, $type) { } /** - * Builds the admin menu as a structured array ready for drupal_render(). - * - * @return - * Array of links and settings relating to the admin menu. + * Implements hook_toolbar(). */ -function toolbar_view() { - global $user; +function toolbar_toolbar() { + $items = array(); - $build = array( - '#theme' => 'toolbar', - '#attached'=> array( - 'library' => array( - array('toolbar', 'drupal.toolbar'), + // The 'Home' tab is a simple link, with no corresponding tray. + $items['home'] = array( + 'tab' => array( + 'title' => t('Home'), + 'href' => '', + 'html' => FALSE, + 'attributes' => array( + 'title' => t('Home page'), + 'class' => array('icon', 'icon-home'), ), ), + 'weight' => -20, ); - // Retrieve the admin menu from the database. - $links = toolbar_menu_navigation_links(toolbar_get_menu_tree()); - $build['toolbar_menu'] = array( - '#theme' => 'links__toolbar_menu', - '#links' => $links, - '#attributes' => array('id' => 'toolbar-menu'), - '#heading' => array('text' => t('Administrative toolbar'), 'level' => 'h2', 'class' => 'element-invisible'), - ); + // Retrieve the administration menu from the database. + $tree = toolbar_get_menu_tree(); - // Add logout & user account links or login link. - if ($user->uid) { - $links = array( - 'account' => array( - 'title' => t('Hello @username', array('@username' => user_format_name($user))), - 'href' => 'user', - 'html' => TRUE, - 'attributes' => array('title' => t('User account')), - ), - 'logout' => array( - 'title' => t('Log out'), - 'href' => 'user/logout', + // Add attributes to the links before rendering. + toolbar_menu_navigation_links($tree); + + $menu = array( + 'toolbar_administration' => array( + '#type' => 'container', + '#attributes' => array( + 'class' => array('toolbar-menu',), ), - ); - } - else { - $links = array( - 'login' => array( - 'title' => t('Log in'), - 'href' => 'user', + 'administration_menu' => menu_tree_output($tree), + ), + '#heading' => t('Administration menu'), + ); + + // To conserve bandwidth, we only include the top-level links in the HTML. + // The subtrees are included in a JSONP script, cached by the browser. Here we + // add that JSONP script. We add it as an external script, because it's a + // Drupal path, not a file available via a stream wrapper. + // @see toolbar_subtrees_jsonp() + $menu['toolbar_administration']['#attached']['js'][url('toolbar/subtrees/' . _toolbar_get_subtree_hash())] = array('type' => 'external'); + + $items['administration'] = array( + 'tab' => array( + 'title' => t('Menu'), + 'href' => 'admin', + 'html' => FALSE, + 'attributes' => array( + 'title' => t('Admin menu'), + 'class' => array('icon', 'icon-menu'), ), + ), + 'tray' => $menu, + 'weight' => -15, + ); + + return $items; +} + +/** + * Builds the Toolbar as a structured array ready for drupal_render(). + * + * @return + * A renderable arrray, with two children: + * - 'tabs': an array of links, rendered by theme('links'). + * - 'trays': an array of render elements displayed when the corresponding tab + * is activated. + */ +function toolbar_view() { + + $build = array('#theme' => 'toolbar'); + $build['#attached']['library'][] = array('toolbar', 'toolbar'); + + // Get the configured breakpoint to switch from vertical to horizontal + // toolbar presentation. + $breakpoints = entity_load('breakpoint_group', 'module.toolbar.toolbar'); + if (!empty($breakpoints)) { + $media_queries = array(); + $media_queries['toolbar']['breakpoints'] = array_map( + function($object) {return $object->mediaQuery;}, + $breakpoints->breakpoints); + + $build['#attached']['js'][] = array( + 'data' => $media_queries, + 'type' => 'setting', ); + // // Load the breakpoints for toolbar. + foreach ($breakpoints->breakpoints as $key => $breakpoint) { + $build['#attached']['js'][0]['data']['toolbar']['breakpoints'][$key] = $breakpoint->mediaQuery; + } } - $build['toolbar_user'] = array( - '#theme' => 'links__toolbar_user', - '#links' => $links, - '#attributes' => array('id' => 'toolbar-user'), - ); - // Add a "home" link. - $link = array( - 'home' => array( - 'title' => 'Home', - 'href' => '', - 'html' => TRUE, - 'attributes' => array('title' => t('Home')), + // Get toolbar items from all modules that implement hook_toolbar() or + // hook_toolbar_alter(). + $toolbar_groups = module_invoke_all('toolbar'); + drupal_alter('toolbar', $toolbar_groups); + uasort($toolbar_groups, 'drupal_sort_weight'); + + // Build the tabs and trays from the toolbar groups. + $build['trays'] = array(); + $build['tabs'] = array( + '#theme' => 'links', + '#links' => array(), + '#attributes' => array( + 'class' => array('bar', 'clearfix'), ), + '#heading' => array('text' => t('Toolbar'), 'level' => 'h2', 'class' => 'element-invisible'), ); - $build['toolbar_home'] = array( - '#theme' => 'links', - '#links' => $link, - '#attributes' => array('id' => 'toolbar-home'), + $tab_defaults = array( + 'title' => '', + 'href' => '', + 'html' => FALSE, + 'attributes' => new Attribute(), ); - // Add an anchor to be able to toggle the visibility of the drawer. - $build['toolbar_toggle'] = array( - '#theme' => 'toolbar_toggle', - '#collapsed' => _toolbar_is_collapsed(), - '#attributes' => array('class' => array('toggle')), - ); + foreach ($toolbar_groups as $group => $items) { + if ($tab = $items['tab']) { + // Merge in the defaults. + $tab += $tab_defaults; + } + // Register a tray if one is associated with this tab. + if (!empty($items['tray'])) { + // Provide an id, a data attribute linking each tab to the corresponding + // tray and aria information. + $tab['attributes']['id'] = 'toolbar-tab-' . $group; + $tab['attributes']['data-toolbar-tray'] = $group; + $tab['attributes']['aria-owns'] = 'toolbar-tray-' . $group; + $tab['attributes']['role'] = 'button'; + $tab['attributes']['aria-pressed'] = 'false'; - // Prepare the drawer links CSS classes. - $toolbar_drawer_classes = array( - 'toolbar-drawer', - 'clearfix', - ); - if (_toolbar_is_collapsed()) { - $toolbar_drawer_classes[] = 'collapsed'; + if (array_key_exists($group, $build['trays'])) { + array_merge($build['trays'][$group], $items['tray']); + } + else { + // Assign the tray to the build. + $build['trays'][$group] = $items['tray']; + } + } + // Assign the tabs to the build. + $build['tabs']['#links'][$group] = $tab; } - $build['toolbar_drawer']['#type'] = 'container'; - $build['toolbar_drawer']['#attributes']['class'] = $toolbar_drawer_classes; return $build; } @@ -299,34 +379,55 @@ function toolbar_get_menu_tree() { * @return * An array of links as defined above. */ -function toolbar_menu_navigation_links($tree) { - $links = array(); - foreach ($tree as $item) { - if (!$item['link']['hidden'] && $item['link']['access']) { - // Make sure we have a path specific ID in place, so we can attach icons - // and behaviors to the items. - $id = str_replace(array('/', '<', '>'), array('-', '', ''), $item['link']['href']); - - $link = $item['link']['localized_options']; - $link['href'] = $item['link']['href']; - // Add icon placeholder. - $link['title'] = '' . check_plain($item['link']['title']); - // Add admin link ID. - $link['attributes'] = array('id' => 'toolbar-link-' . $id); - if (!empty($item['link']['description'])) { - $link['title'] .= ' (' . $item['link']['description'] . ')'; - $link['attributes']['title'] = $item['link']['description']; - } - $link['html'] = TRUE; +function toolbar_menu_navigation_links(&$tree) { + foreach ($tree as $key => $item) { + // Configure sub-items. + if (!empty($item['below'])) { + toolbar_menu_navigation_links($tree[$key]['below']); + } + // Make sure we have a path specific ID in place, so we can attach icons + // and behaviors to the items. + $tree[$key]['link']['localized_options']['attributes'] = array( + 'id' => 'toolbar-link-' . str_replace(array('/', '<', '>'), array('-', '', ''), $item['link']['link_path']), + 'class' => array( + 'icon', + 'icon-' . strtolower(str_replace(' ', '-', $item['link']['title'])), + ), + ); + } +} - $class = ' path-' . $id; - if (toolbar_in_active_trail($item['link']['href'])) { - $class .= ' active-trail'; +/** + * Returns the rendered subtree of each top-level toolbar link. + */ +function toolbar_get_rendered_subtrees() { + $subtrees = array(); + $tree = toolbar_get_menu_tree(); + foreach ($tree as $tree_item) { + $item = $tree_item['link']; + if (!$item['hidden'] && $item['access']) { + if ($item['has_children']) { + $query = db_select('menu_links'); + $query->addField('menu_links', 'mlid'); + $query->condition('has_children', 1); + for ($i=1; $i <= $item['depth']; $i++) { + $query->condition('p' . $i, $item['p' . $i]); + } + $parents = $query->execute()->fetchCol(); + $subtree = menu_build_tree($item['menu_name'], array('expanded' => $parents, 'min_depth' => $item['depth']+1)); + toolbar_menu_navigation_links($subtree); + $subtree = menu_tree_output($subtree); + $subtree = drupal_render($subtree); } - $links['menu-' . $item['link']['mlid'] . $class] = $link; + else { + $subtree = ''; + } + + $id = str_replace(array('/', '<', '>'), array('-', '', ''), $item['href']); + $subtrees[$id] = $subtree; } } - return $links; + return $subtrees; } /** @@ -361,23 +462,67 @@ 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( - drupal_get_path('module', 'toolbar') . '/toolbar.js' => array(), + drupal_get_path('module', 'toolbar') . '/js/toolbar.js' => array(), ), 'css' => array( - drupal_get_path('module', 'toolbar') . '/toolbar.css', + drupal_get_path('module', 'toolbar') . '/css/toolbar.base.css', + drupal_get_path('module', 'toolbar') . '/css/toolbar.theme.css', + drupal_get_path('module', 'toolbar') . '/css/toolbar.icons.css', ), 'dependencies' => array( array('system', 'jquery'), array('system', 'drupal'), array('system', 'drupalSettings'), + array('system', 'matchmedia'), + array('system', 'jquery.once'), + array('system', 'drupal.debounce'), + array('toolbar', 'toolbar.menu'), + ), + ); + + $libraries['toolbar.menu'] = array( + 'title' => 'Toolbar nested accordion menus.', + 'version' => VERSION, + 'js' => array( + drupal_get_path('module', 'toolbar') . '/js/toolbar.menu.js' => array(), + ), + 'css' => array( + drupal_get_path('module', 'toolbar') . '/css/toolbar.menu.css', + ), + 'dependencies' => array( + array('system', 'jquery'), + array('system', 'drupal'), array('system', 'jquery.once'), - array('system', 'jquery.cookie'), ), ); return $libraries; } + +/** + * Implements hook_cache_flush(). + */ +function toolbar_cache_flush() { + return array('toolbar'); +} + +/** + * Returns the hash of the per-user rendered toolbar subtrees. + */ +function _toolbar_get_subtree_hash() { + global $user; + $cid = $user->uid . ':' . language(LANGUAGE_TYPE_INTERFACE)->langcode; + if ($cache = cache('toolbar')->get($cid)) { + $hash = $cache->data; + } + else { + $subtrees = toolbar_get_rendered_subtrees(); + $hash = drupal_hash_base64(serialize($subtrees)); + cache('toolbar')->set($cid, $hash); + } + return $hash; +} diff --git a/core/modules/toolbar/toolbar.png b/core/modules/toolbar/toolbar.png deleted file mode 100644 index f2c7f35..0000000 --- a/core/modules/toolbar/toolbar.png +++ /dev/null @@ -1,4 +0,0 @@ -PNG - - IHDRd9,~OPLTEfffffffffffffff===>>>GGGHHHPPPQQQXXXfffstRNSO^zIDATx[O@o -VK71i}.f.Ifbd`pg01\. \ԌP`MRhUl DB(gŰ8!+2VL,Z$MNY16:V,fKzANJZ?6 se]OԍI_"[Wߺ, }8D !yP,G9BUĩ%W'X"_U!N<*"IENDB` \ No newline at end of file diff --git a/core/modules/user/images/icon-user-active.png b/core/modules/user/images/icon-user-active.png new file mode 100644 index 0000000..3c9d73b --- /dev/null +++ b/core/modules/user/images/icon-user-active.png @@ -0,0 +1,4 @@ +PNG + + IHDRĴl;tEXtSoftwareAdobe ImageReadyqe<IDATxb`v߿@?߇6߿ +@|c q ?DžA2:OlllYp?aU H(f< )A˗/q#~ H"̑O@'?F ^9޽.XсH>@AHHo߾mR%dho޼RT FW^|a fH, \<4ddIENDB` \ No newline at end of file diff --git a/core/modules/user/images/icon-user.png b/core/modules/user/images/icon-user.png new file mode 100644 index 0000000..3c847c6 --- /dev/null +++ b/core/modules/user/images/icon-user.png @@ -0,0 +1,6 @@ +PNG + + IHDRĴl;tEXtSoftwareAdobe ImageReadyqe<&IDATxb`j'O +022@lx' Ǐ+ d*`~46, |2@A$СC o'"8 . +O$0(J EdȈ5pipuu} @̀#`8 `/ 7oEN$oR |}}? l^z5u@C3fƒ@zChhW\40W$|Z>le @#%K@^O0fZD 0= +`PC0q WIENDB` \ No newline at end of file diff --git a/core/modules/user/user.css b/core/modules/user/user.css index 866ee40..ccd2b56 100644 --- a/core/modules/user/user.css +++ b/core/modules/user/user.css @@ -1,4 +1,3 @@ - #permissions td.module { font-weight: bold; } @@ -88,3 +87,14 @@ div.password-suggestions ul { .profile dd { margin: 0 0 1em 0; } + +/** + * Toolbar icon. + */ +.icon-user:before { + background-image: url("images/icon-user.png"); +} +.icon-user:active:before, +.active .icon-user:before { + background-image: url("images/icon-user-active.png"); +} diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 68b45ea..d576afc 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -3100,6 +3100,66 @@ function user_file_download_access($field, EntityInterface $entity, File $file) } /** + * Implements hook_toolbar(). + */ +function user_toolbar() { + global $user; + + // Add logout & user account links or login link. + if ($user->uid) { + $links = array( + 'account' => array( + 'title' => t('View profile'), + 'href' => 'user', + 'html' => TRUE, + 'attributes' => array( + 'title' => t('User account'), + ), + ), + 'logout' => array( + 'title' => t('Log out'), + 'href' => 'user/logout', + ), + ); + } + else { + $links = array( + 'login' => array( + 'title' => t('Log in'), + 'href' => 'user', + ), + ); + } + + $user_tray = array( + '#heading' => t('User account actions'), + 'content' => array( + '#theme' => 'links__toolbar_user', + '#links' => $links, + '#attributes' => array( + 'class' => array('menu',), + ), + ), + ); + + $items['user'] = array( + 'tab' => array( + 'title' => user_format_name($user), + 'href' => 'user', + 'html' => FALSE, + 'attributes' => array( + 'title' => t('My account'), + 'class' => array('icon', 'icon-user'), + ), + ), + 'tray' => $user_tray, + 'weight' => 100, + ); + + return $items; +} + +/** * Implements hook_library_info(). */ function user_library_info() { diff --git a/core/profiles/standard/standard.info b/core/profiles/standard/standard.info index 4c812d0..4fb4d6c 100644 --- a/core/profiles/standard/standard.info +++ b/core/profiles/standard/standard.info @@ -4,6 +4,7 @@ version = VERSION core = 8.x dependencies[] = node dependencies[] = block +dependencies[] = breakpoint dependencies[] = color dependencies[] = config dependencies[] = comment -- 1.7.10.4