From 80e10cf11b01f48f5b76d442ed2d2fac00770f81 Mon Sep 17 00:00:00 2001
From: Michael Strelan <mstrelan@gmail.com>
Date: Tue, 31 Jan 2012 10:23:46 +1000
Subject: [PATCH] #742184 - Shortcut.module integration

---
 admin_menu.js                                |    7 ++-
 admin_menu.module                            |   74 +++++++++++++++++++++++---
 admin_menu_toolbar/admin_menu_toolbar.css    |   68 +++++++++++++++++++-----
 admin_menu_toolbar/admin_menu_toolbar.js     |   34 ++++++++++++
 admin_menu_toolbar/admin_menu_toolbar.module |   30 +++++++----
 5 files changed, 180 insertions(+), 33 deletions(-)

diff --git a/admin_menu.js b/admin_menu.js
index f8c730a..ddadb52 100644
--- a/admin_menu.js
+++ b/admin_menu.js
@@ -35,7 +35,12 @@ Drupal.behaviors.adminMenu = {
     if (!$adminMenu.length && settings.admin_menu.hash) {
       Drupal.admin.getCache(settings.admin_menu.hash, function (response) {
           if (typeof response == 'string' && response.length > 0) {
-            $('body', context).prepend(response);
+            // Insert this in the same location and with the same markup that
+            // it would have had if it had been placed on the page by the
+            // server-side code.
+            // @todo: Ideally the wrapping markup should be returned as part of
+            //   the AJAX response.
+            $('body', context).append('<div class="region region-page-bottom">' + response + '</div>');
           }
           var $adminMenu = $('#admin-menu:not(.admin-menu-processed)', context);
           // Apply our behaviors.
diff --git a/admin_menu.module b/admin_menu.module
index e1137b8..b9d8f57 100644
--- a/admin_menu.module
+++ b/admin_menu.module
@@ -116,6 +116,10 @@ function admin_menu_menu_alter(&$items) {
  * like chameleon load and output scripts and stylesheets in front of
  * theme_closure(), so we ensure Admin menu's styles and scripts are loaded on
  * all pages via hook_init().
+ *
+ * See also admin_menu_page_build(), where additional scripts are attached to
+ * regions of the $page array (so that they only are added to the page when
+ * those regions are actually rendered). 
  */
 function admin_menu_init() {
   if (!user_access('access administration menu') || admin_menu_suppress(FALSE)) {
@@ -202,12 +206,39 @@ function admin_menu_suppress($set = TRUE) {
 }
 
 /**
- * Implements hook_page_alter().
+ * Implements hook_page_build().
  */
-function admin_menu_page_alter(&$page) {
+function admin_menu_page_build(&$page) {
   $page['page_bottom']['admin_menu'] = array(
     '#markup' => admin_menu_output(),
   );
+
+  // Attach the administration menu JavaScript to the same part of the $page
+  // array as the menu itself. This ensures that when this region of the page
+  // is not intended to be rendered (for example, inside the Overlay), the
+  // JavaScript won't be added either. (If the JavaScript were added, the
+  // client-side code would add the menu to the page even when it isn't
+  // supposed to be there.)
+  // @todo: Should all the JavaScript added in admin_menu_init() move here too,
+  //   rather than just this file?
+  if (user_access('access administration menu') && !admin_menu_suppress(FALSE)) {
+    $js_file = drupal_get_path('module', 'admin_menu') . '/admin_menu.js';
+    // Performance: Defer execution.
+    $page['page_bottom']['admin_menu']['#attached']['js'][$js_file] = array('defer' => TRUE);
+  }
+}
+
+/**
+ * Implements hook_system_info_alter().
+ *
+ * Indicate that the 'page_bottom' region (in which the administration menu
+ * is displayed) is an overlay supplemental region that should be refreshed
+ * whenever its content is updated.
+ */
+function admin_menu_system_info_alter(&$info, $file, $type) {
+  if ($type == 'theme') {
+    $info['overlay_supplemental_regions'][] = 'page_bottom';
+  }  
 }
 
 /**
@@ -236,7 +267,7 @@ function admin_menu_js() {
  *   The cache ID of the data to retrieve.
  */
 function admin_menu_cache_get($cid) {
-  static $cache = array();
+  $cache = &drupal_static(__FUNCTION__, array());
 
   if (!variable_get('admin_menu_cache_client', TRUE)) {
     return FALSE;
@@ -375,12 +406,13 @@ function admin_menu_output() {
   $cid = 'admin_menu:' . session_id() . ':' . $language->language;
 
   // Do nothing at all here if the client supports client-side caching, the user
-  // has a hash, and is NOT requesting the cache update path. Consult the hash
-  // cache last, since it requires a DB request.
+  // has a hash, and is NOT requesting either the cache update path or the
+  // Overlay module's AJAX update path. Consult the hash cache last, since it
+  // requires a DB request.
   // @todo Implement a sanity-check to prevent permanent double requests; i.e.
   //   what if the client-side cache fails for any reason and performs a second
   //   request on every page?
-  if (!empty($_COOKIE['has_js']) && strpos($_GET['q'], 'js/admin_menu/cache') !== 0) {
+  if (!empty($_COOKIE['has_js']) && strpos($_GET['q'], 'js/admin_menu/cache') !== 0 && strpos($_GET['q'], 'overlay-ajax/') !== 0) {
     if (admin_menu_cache_get($cid)) {
       return;
     }
@@ -527,7 +559,7 @@ function theme_admin_menu_links($variables) {
       '#options' => array(),
     );
     // Render children to determine whether this link is expandable.
-    if (isset($elements[$path]['#type']) || isset($elements[$path]['#theme'])) {
+    if (isset($elements[$path]['#type']) || isset($elements[$path]['#theme']) || isset($elements[$path]['#pre_render'])) {
       $elements[$path]['#admin_menu_depth'] = $depth_child;
       $elements[$path]['#children'] = drupal_render($elements[$path]);
     }
@@ -642,6 +674,7 @@ function admin_menu_flush_caches() {
   // Flush cached output of admin_menu.
   cache_clear_all('admin_menu:', 'cache_menu', TRUE);
   // Flush client-side cache hashes.
+  drupal_static_reset('admin_menu_cache_get');
   // db_table_exists() required for SimpleTest.
   if (db_table_exists('cache_admin_menu')) {
     cache_clear_all('*', 'cache_admin_menu', TRUE);
@@ -658,6 +691,33 @@ function admin_menu_form_system_clean_url_settings_alter(&$form, $form_state) {
 }
 
 /**
+ * Implements hook_menu_link_insert().
+ */
+function admin_menu_menu_link_insert($link) {
+  // Flush the admin menu cache so it can take into account the changed menu
+  // links.
+  admin_menu_flush_caches();
+}
+
+/**
+ * Implements hook_menu_link_update().
+ */
+function admin_menu_menu_link_update($link) {
+  // Flush the admin menu cache so it can take into account the changed menu
+  // links.
+  admin_menu_flush_caches();
+}
+
+/**
+ * Implements hook_menu_link_delete().
+ */
+function admin_menu_menu_link_delete($link) {
+  // Flush the admin menu cache so it can take into account the changed menu
+  // links.
+  admin_menu_flush_caches();
+}
+
+/**
  * Implements hook_form_FORM_ID_alter().
  *
  * Extends Devel module with Administration menu developer settings.
diff --git a/admin_menu_toolbar/admin_menu_toolbar.css b/admin_menu_toolbar/admin_menu_toolbar.css
index 85c7d8e..1428831 100644
--- a/admin_menu_toolbar/admin_menu_toolbar.css
+++ b/admin_menu_toolbar/admin_menu_toolbar.css
@@ -13,6 +13,9 @@
 html body.admin-menu {
   margin-top: 29px !important;
 }
+html body.admin-menu-with-shortcuts {
+  margin-top: 62px !important;
+}
 body div#toolbar {
   top: 30px;
 }
@@ -116,21 +119,21 @@ body div#toolbar {
 #admin-menu li.admin-menu-shortcuts-active span.toggle:hover {
   background-position: -75px -20px;
 }
-
-/**
- * Shortcuts widget.
- */
+/* Override the standard admin menu hover behavior with our own */
+#admin-menu li.admin-menu-shortcuts-inactive ul {
+  display: none !important;
+  left: -999em !important;
+}
 #admin-menu li.admin-menu-shortcuts-active ul {
   display: block !important;
   left: 20px !important;
-  right: 20px;
-  width: auto;
 }
+
+/**
+ * Shortcuts widget.
+ */
+/* General styling that applies to the entire widget and all shortcuts in it */
 #admin-menu li.admin-menu-shortcuts ul {
-  background-color: #666;
-  left: 20px !important;
-  padding: 5px 10px;
-  right: 20px;
   width: auto;
 }
 #admin-menu li.admin-menu-shortcuts ul li {
@@ -146,10 +149,47 @@ body div#toolbar {
   padding: 5px 10px 5px 5px;
   margin-right: 5px;
 }
-#admin-menu li.admin-menu-shortcuts ul li a:hover {
+
+/* Styling that applies to the wrapper list but not the shortcuts themselves */
+#admin-menu li.admin-menu-shortcuts > ul {
+  background-color: #666;
+  padding: 5px 10px;
+  right: 20px;
+}
+#admin-menu li.admin-menu-shortcuts > ul > li {
+  width: 100%;
+}
+
+/* Styling that applies to the actual shortcuts but not to "Edit shortcuts" */
+#admin-menu li.admin-menu-shortcuts .toolbar-shortcuts ul li a:hover {
   background: #555;
 }
-#admin-menu li.admin-menu-shortcuts ul li a.active:hover,
-#admin-menu li.admin-menu-shortcuts ul li a.active {
-  background: url(toolbar.png) 0 -20px repeat-x;
+
+/* Styling that applies to the "Edit shortcuts" link only */
+#admin-menu div#edit-shortcuts-wrapper {
+  float: right;
+  padding: 5px 10px 5px 5px;
+}
+#admin-menu div#edit-shortcuts-wrapper a#edit-shortcuts {
+  display: inline;
+  padding: 0;
+  color: #fefefe;
+}
+#admin-menu div#edit-shortcuts-wrapper a#edit-shortcuts:focus,
+#admin-menu div#edit-shortcuts-wrapper a#edit-shortcuts:hover,
+#admin-menu div#edit-shortcuts-wrapper a#edit-shortcuts.active {
+  color: #fff;
+  text-decoration: underline;
 }
+
+/* Drop shadow on shortcut bar */
+html body.admin-menu-with-shortcuts #admin-menu li.admin-menu-shortcuts > ul {
+  -moz-box-shadow: 0 3px 20px #000;
+  -webkit-box-shadow: 0 3px 20px #000;
+  box-shadow: 0 3px 20px #000;
+  filter: progid:DXImageTransform.Microsoft.Shadow(color=#000000, direction='180', strength='10');
+  -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(color=#000000, direction='180', strength='10')";
+  z-index: -1;
+}
+
+
diff --git a/admin_menu_toolbar/admin_menu_toolbar.js b/admin_menu_toolbar/admin_menu_toolbar.js
index 28f8448..c4c09a7 100644
--- a/admin_menu_toolbar/admin_menu_toolbar.js
+++ b/admin_menu_toolbar/admin_menu_toolbar.js
@@ -4,6 +4,19 @@ Drupal.admin = Drupal.admin || {};
 Drupal.admin.behaviors = Drupal.admin.behaviors || {};
 
 /**
+ * Apply margin to page, taking into account the shortcuts.
+ *
+ * @see Drupal.behaviors.adminMenuMarginTop()
+ */
+Drupal.behaviors.adminMenuMarginTopShortcuts = {
+  attach: function (context, settings) {
+    if (!settings.admin_menu.suppress && settings.admin_menu.toolbar.margin_top_shortcuts) {
+      $('body:not(.admin-menu-with-shortcuts)', context).addClass('admin-menu-with-shortcuts');
+    }
+  }
+};
+
+/**
  * @ingroup admin_behaviors
  * @{
  */
@@ -20,6 +33,27 @@ Drupal.admin.behaviors.toolbarActiveTrail = function (context, settings, $adminM
 };
 
 /**
+ * Toggle the shortcut drawer.
+ */
+Drupal.admin.behaviors.toggleShortcutDrawer = function (context, settings, $adminMenu) {
+  var $body = $('body', context);
+  var $shortcuts = $('li.admin-menu-shortcuts', $adminMenu);
+  var $toggle = $('.toggle', $shortcuts);
+  $toggle.toggle(
+    function () {
+      $shortcuts.addClass('admin-menu-shortcuts-inactive').removeClass('admin-menu-shortcuts-active');
+      $body.removeClass('admin-menu-with-shortcuts');
+      return false;
+    },
+    function () {
+      $shortcuts.addClass('admin-menu-shortcuts-active').removeClass('admin-menu-shortcuts-inactive');
+      $body.addClass('admin-menu-with-shortcuts');
+      return false;
+    }
+  );
+};
+
+/**
  * @} End of "defgroup admin_behaviors".
  */
 
diff --git a/admin_menu_toolbar/admin_menu_toolbar.module b/admin_menu_toolbar/admin_menu_toolbar.module
index 9c04b26..36e5adb 100644
--- a/admin_menu_toolbar/admin_menu_toolbar.module
+++ b/admin_menu_toolbar/admin_menu_toolbar.module
@@ -35,6 +35,12 @@ function admin_menu_toolbar_init() {
   elseif (drupal_is_front_page()) {
     $settings['activeTrail'] = url('<front>');
   }
+  
+  // Adjust top margin for the shortcut bar.
+  if (module_exists('shortcut') && ($setting = variable_get('admin_menu_margin_top', 1))) {
+    $settings['margin_top_shortcuts'] = $setting;
+  }
+    
   drupal_add_js(array('admin_menu' => array('toolbar' => $settings)), 'setting');
 }
 
@@ -44,31 +50,33 @@ function admin_menu_toolbar_init() {
 function admin_menu_toolbar_admin_menu_output_build(&$content) {
   // Add shortcuts menu.
   $content['shortcuts'] = array(
+  	'#access' => module_exists('shortcut'),
     '#theme' => 'admin_menu_links',
     '#weight' => -200,
   );
   $content['shortcuts']['shortcuts'] = array(
     '#title' => t('Show shortcuts'),
     // @todo How do we want to trigger/store state?
-    '#attributes' => array('class' => array('admin-menu-shortcuts')),
-    //'#attributes' => array('class' => array('admin-menu-shortcuts', 'admin-menu-shortcuts-active')),
+		'#attributes' => array('class' => array('admin-menu-shortcuts', 'admin-menu-shortcuts-active')),
     '#options' => array(
       'attributes' => array('class' => 'toggle'),
     ),
   );
-  // @todo Copy this from $content['menu'] instead.
-  $content['shortcuts']['shortcuts']['node-add'] = array(
-    '#title' => t('Add content'),
-    '#href' => 'node/add',
-  );
-  $content['shortcuts']['shortcuts']['admin-content-node'] = array(
-    '#title' => t('Find content'),
-    '#href' => 'admin/content/node',
-    '#access' => user_access('administer nodes'),
+  $content['shortcuts']['shortcuts']['shortcuts'] = array(
+  	'#pre_render' => array('shortcut_toolbar_pre_render', 'admin_menu_toolbar_shortcuts_pre_render'),
   );
 }
 
 /**
+ * Pre-render function to wrap the edit shortcuts link for easier theming.
+ */
+function admin_menu_toolbar_shortcuts_pre_render($element) {
+  $element['toolbar_drawer'][0]['configure']['#prefix'] = '<div id="edit-shortcuts-wrapper">&nbsp;';
+  $element['toolbar_drawer'][0]['configure']['#suffix'] = '</div>';
+  return $element;
+}
+
+/**
  * Implements hook_admin_menu_output_alter().
  */
 function admin_menu_toolbar_admin_menu_output_alter(&$content) {
-- 
1.7.4

