From 4d9851e4105cbc969eae7bbbc05518b45b7ab4d3 Mon Sep 17 00:00:00 2001 From: Alexis Wilke Date: Mon, 31 May 2010 09:44:37 +0000 Subject: [PATCH] First stride at getting a version 7.x working... --- simplemenu.admin.inc | 14 +- simplemenu.info | 11 +- simplemenu.install | 45 +------ simplemenu.js | 104 ++++++++------- simplemenu.module | 221 +++++++++++++++++++++++-------- simplemenu_devel.info | 10 +- simplemenu_inactive_parents.info | 10 +- simplemenu_multi_menu.info | 13 +- 8 files changed, 266 insertions(+), 162 deletions(-) diff --git a/simplemenu.admin.inc b/simplemenu.admin.inc index b3eb97e0..9dc5029a 100644 --- a/simplemenu.admin.inc +++ b/simplemenu.admin.inc @@ -25,14 +25,14 @@ function simplemenu_admin_settings() { '#type' => 'select', '#title' => t('Menu'), '#options' => menu_parent_options(menu_get_menus(), array('mlid' => 0)), // return complete tree - '#default_value' => variable_get('simplemenu_menu', 'navigation:0'), + '#default_value' => variable_get('simplemenu_menu', 'management:0'), '#description' => t('Select the menu to display.'), '#weight' => -1, ); } - $themes = file_scan_directory($simplemenu_path . '/themes', '.*', - array('.', '..', 'CVS', '.svn'), 0, FALSE, 'basename'); + $themes = file_scan_directory($simplemenu_path . '/themes', '%.*%', + array('key' => 'filename', 'recurse' => FALSE)); $theme_selection = array('custom' => 'custom'); foreach ($themes as $name => $ignore) { $theme_selection[$name] = $name; @@ -66,7 +66,7 @@ function simplemenu_admin_settings() { '#default_value' => variable_get('simplemenu_fix', 'scroll'), '#description' => t('Select the mode to use. The default is to let the menu scroll with the page.') . '
' . t('WARNING') . ': ' - . t('The At the Top/Bottom options prevent you from ever seeing the bottom of your drop-down menus. In other words, if you have many modules installed, it is not unlikely that your Site configuration menu will not fit the screen and the last few entries won\'t be accessible via Simplemenu.'), + . t('The At the Top option prevents you from ever seeing the bottom of your drop-down menus when they are too long. In other words, if you have many modules installed, it is not unlikely that some drop down menus will not fit the height of the screen and the last few entries won\'t be accessible via Simplemenu.'), ); $form['settings']['simplemenu_hide_delay'] = array( @@ -113,8 +113,8 @@ function simplemenu_admin_settings() { '#default_value' => variable_get('simplemenu_uid1', 1), ); - $superfish_js = file_scan_directory($simplemenu_path, '^superfish-[0-9.]*\.js$', - array('.', '..', 'CVS', '.svn'), 0, FALSE, 'basename'); + $superfish_js = file_scan_directory($simplemenu_path, '%^superfish-[0-9.]*\.js$%', + array('key' => 'filename', 'recurse' => FALSE)); $superfish = array('custom' => 'custom or theme'); foreach ($superfish_js as $name => $ignore) { $superfish[$name] = $name; @@ -135,7 +135,7 @@ function simplemenu_admin_settings() { '#type' => 'select', '#title' => t('Scope of simplemenu variable'), '#options' => $scope, - '#description' => t('By default, the simplemenu variable is put in the footer (backward compatible.) It is also possible to put it in the header instead.'), + '#description' => t('By default, the simplemenu variable is put in the footer (backward compatible.) It is possible to put it in the header instead.'), '#default_value' => variable_get('simplemenu_menu_scope', 'footer'), ); diff --git a/simplemenu.info b/simplemenu.info index f927d0c0..a629313d 100644 --- a/simplemenu.info +++ b/simplemenu.info @@ -1,5 +1,14 @@ ; $Id$ name = SimpleMenu description = Displays a menu bar with drop down items. By default it appears at the top of the screen with the Navigation menu. -core = 6.x +core = 7.x package = Menu +files[] = simplemenu.admin.inc +files[] = simplemenu.install +files[] = simplemenu.module +configure = admin/config/simplemenu + +; Normally aded by Drupal +version = "7.x-1.x-dev" +project = simplemenu +datestamp = "1274876110" diff --git a/simplemenu.install b/simplemenu.install index fabbc263..7b3f6239 100644 --- a/simplemenu.install +++ b/simplemenu.install @@ -5,49 +5,8 @@ * Get rid of the variables used by simple menu. */ function simplemenu_uninstall() { - db_query("DELETE FROM {variable} WHERE name LIKE 'simplemenu_%'"); -} - -/** - * Implementation of hook_update_N(). - */ -function simplemenu_update_6001() { - // if navigation menu was used in Drupal 5 use the same in Drupal 6. - // otherwise, we can't do anything. - if (variable_get('simplemenu_menu', 1) == 1) { - variable_set('simplemenu_menu', 'navigation:0'); - } - return array(); -} - -/** - * Implementation of hook_update_N(). - */ -function simplemenu_update_6002() { - // fix variable name - variable_set('simplemenu_detect_popup', variable_get('simplemenu_detect_popop', 1)); - variable_del('simplemenu_detect_popop'); - return array(); -} - -/** - * Implementation of hook_update_N(). - */ -function simplemenu_update_6003() { - if (variable_get('simplemenu_devel', 0)) { - drupal_set_message('The Simplemenu Devel is now defined in a separate module. Enable that module if you want to use the devel menu.', 'warning'); - } - variable_del('simplemenu_devel'); - return array(); -} - -/** - * Implementation of hook_update_N(). - */ -function simplemenu_update_6004() { - // enable multiple menus selection - variable_set('simplemenu_menus', array(variable_get('simplemenu_menu', 'navigation:0'))); - return array(); + // XXX + //db_query("DELETE FROM {variable} WHERE name LIKE 'simplemenu_%'"); } // vim: ts=2 sw=2 et syntax=php diff --git a/simplemenu.js b/simplemenu.js index 098281eb..3617e8a7 100644 --- a/simplemenu.js +++ b/simplemenu.js @@ -1,61 +1,65 @@ // $Id$ +(function($){ -Drupal.behaviors.simplemenuAttach = function(context) { - // If detect pop-ups setting is enabled and we are in a pop-up window - if (Drupal.settings.simplemenu.detectPopup && window.opener) { - return; - } - - if ($('body').hasClass('simplemenu-enabled')) { - return; - } - - // get the element to add the menu to - var element = Drupal.settings.simplemenu.element; - var menu = $(simplemenu); - - switch (Drupal.settings.simplemenu.placement) { - case 'prepend': - $(menu).prependTo(element); - break; - case 'append': - $(menu).appendTo(element); - break; - case 'replace': - $(element).html(menu); - break; - } - - $('body').addClass('simplemenu-enabled'); +Drupal.behaviors.simplemenuAttach = { + attach: function(context, settings) { + // If detect pop-ups setting is enabled and we are in a pop-up window + if (settings.simplemenu.detectPopup && window.opener) { + return; + } - var animation = {}; - animation[Drupal.settings.simplemenu.effect] = 'toggle'; + if ($('body').hasClass('simplemenu-enabled')) { + return; + } - // Build menu - $(menu) - .find('#simplemenu') - .superfish({ - pathClass: 'current', - animation: animation, - delay: Drupal.settings.simplemenu.hideDelay, - speed: Drupal.settings.simplemenu.effectSpeed, - autoArrows: false - }) - .find(">li:has(ul)") - .mouseover(function(){ - $("ul", this).bgIframe(); + // get the element to add the menu to + var element = settings.simplemenu.element; + var menu = $(simplemenu); + + switch (settings.simplemenu.placement) { + case 'prepend': + $(menu).prependTo(element); + break; + case 'append': + $(menu).appendTo(element); + break; + case 'replace': + $(element).html(menu); + break; + } + + $('body').addClass('simplemenu-enabled'); + + var animation = {}; + animation[settings.simplemenu.effect] = 'toggle'; + + // Build menu + $(menu) + .find('#simplemenu') + .superfish({ + pathClass: 'current', + animation: animation, + delay: settings.simplemenu.hideDelay, + speed: settings.simplemenu.effectSpeed, + autoArrows: false }) - .find("a") - .focus(function(){ - $("ul", $(".nav>li:has(ul)")).bgIframe(); + .find(">li:has(ul)") + .mouseover(function(){ + $("ul", this).bgIframe(); }) + .find("a") + .focus(function(){ + $("ul", $(".nav>li:has(ul)")).bgIframe(); + }) + .end() .end() - .end() - .find("a") - .removeAttr('title'); - - $('#simplemenu').children('li.expanded').addClass('root'); + .find("a") + .removeAttr('title'); + + $('#simplemenu').children('li.expanded').addClass('root'); + } }; +})(jQuery); /* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net) diff --git a/simplemenu.module b/simplemenu.module index de46ffd7..45a7098f 100644 --- a/simplemenu.module +++ b/simplemenu.module @@ -12,7 +12,7 @@ function simplemenu_menu() { $items = array(); - $items['admin/settings/simplemenu'] = array( + $items['admin/config/simplemenu'] = array( 'title' => 'SimpleMenu', 'description' => 'Select the menu to display.', 'page callback' => 'drupal_get_form', @@ -65,34 +65,34 @@ function simplemenu_init() { * to be sent inline. */ function _simplemenu_add_menu() { - $simplemenu = 'var simplemenu=' . drupal_to_js(simplemenu_get_menu()) . ';'; + // XXX -- should we put that in the settings instead? why put it in its own variable? + $simplemenu = 'var simplemenu=' . drupal_json_encode(simplemenu_get_menu()) . ';'; $has_file = variable_get('simplemenu_cache_menu', TRUE); if ($has_file) { - $js_path = file_create_path('js'); // same path as concatenated Core JS - $js_md5 = md5($simplemenu); // this is a lot faster than transferring the menu for each page! - $js_filename = $js_path . '/simplemenu-' . $js_md5 . '.js'; - - $has_file = file_check_directory($js_path, FILE_CREATE_DIRECTORY); - if ($has_file) { - // The old way was to send the whole menu each time - if (!file_exists($js_filename)) { - // use LOCK so concurrent writes don't mess up the file - @file_put_contents($js_filename, $simplemenu); - $has_file = file_exists($js_filename); - } - else { - $has_file = TRUE; + $js_hash = drupal_hash_base64($simplemenu); + $js_path = 'public://js'; // same path as concatenated Core JS + $js_filename = $js_path . '/simplemenu_' . $js_hash . '.js'; + if (!file_exists($js_filename)) { + file_prepare_directory($js_path, FILE_CREATE_DIRECTORY); + if (!file_unmanaged_save_data($simplemenu, $js_filename, FILE_EXISTS_REPLACE)) { + $has_file = FALSE; } } } - $scope = variable_get('simplemenu_menu_scope', 'footer'); + $options = array( + 'scope' => variable_get('simplemenu_menu_scope', 'footer'), + // 'version' => ?, -- could we make use of the version? + ); if ($has_file) { - drupal_add_js($js_filename, 'module', $scope); + //$options['type'] = 'file'; -- default + drupal_add_js($js_filename, $options); } else { - drupal_add_js($simplemenu, 'inline', $scope); + // inline adds the value as is (untouched) + $options['type'] = 'inline'; + drupal_add_js($simplemenu, $options); } } @@ -111,8 +111,8 @@ function _simplemenu_add_css() { global $user; $simplemenu_path = drupal_get_path('module', 'simplemenu'); - $css_path = file_create_path('css'); // same path as concatenated Core CSS - if (file_check_directory($css_path, FILE_CREATE_DIRECTORY)) { + $css_path = 'public://css'; // same path as concatenated Core CSS + if (file_prepare_directory($css_path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { $fix = variable_get('simplemenu_fix', 'scroll'); // XXX add a variable simplemenu_update which is set to TRUE whenever @@ -139,8 +139,8 @@ function _simplemenu_add_css() { } $css = file_get_contents($simplemenu_path . '/simplemenu.css.tpl'); $css = strtr($css, $tags); - $css_md5 = md5($css); - $output_filename = $css_path . '/simplemenu-' . $css_md5 . '.css'; + $css_hash = hash('sha256', $css); + $output_filename = $css_path . '/simplemenu-' . $css_hash . '.css'; if (!file_exists($output_filename)) { // new content, create a new file file_put_contents($output_filename, $css); @@ -231,15 +231,16 @@ function _simplemenu_add_js() { 'hideDelay' => variable_get('simplemenu_hide_delay', 800), 'detectPopup' => variable_get('simplemenu_detect_popup', 1), ); - drupal_add_js(array('simplemenu' => $settings), 'setting'); + drupal_add_js(array('simplemenu' => $settings), array('type' => 'setting')); // Simplemenu - drupal_add_js($simplemenu_path . '/simplemenu.js'); + drupal_add_js($simplemenu_path . '/simplemenu.js', array('version' => '1.2')); // Superfish $superfish = variable_get('simplemenu_superfish_version', 'superfish-1.4.1.js'); if ($superfish != 'custom') { - drupal_add_js($simplemenu_path . '/' . $superfish); + $sf_version = str_replace(array('superfish-', '.js'), '', $superfish); + drupal_add_js($simplemenu_path . '/' . $superfish, array('version' => $sf_version)); } } @@ -282,7 +283,7 @@ function simplemenu_get_menu() { // if a user turned off menu module but SimpleMenu was previously set // reset variable so a menu appears - $all_menus = array(variable_get('simplemenu_menu', 'navigation:0')); + $all_menus = array(variable_get('simplemenu_menu', 'management:0')); drupal_alter('simplemenu_menus', $all_menus); if (count($all_menus) > 1) { @@ -316,9 +317,11 @@ function simplemenu_get_menu() { // allow other modules to modify the menu tree drupal_alter('simplemenu_tree', $tree); + $tree = simplemenu_tree_remove_hidden($tree); // now generate the output - $menu = menu_tree_output($tree); + $menu_form = menu_tree_output($tree); + $menu = drupal_render($menu_form); if (!$menu) { $menu = ''; @@ -334,16 +337,41 @@ function simplemenu_get_menu() { return '
' . $menu . ' 
'; } +/** + * At this point (May 31, 2010) the menu tree includes + * many 'below' that should be considered empty but + * aren't... unless we make sure we remove the children + * ourselves. + */ +function simplemenu_tree_remove_hidden($tree) { + $clean = array(); + + foreach ($tree as $key => $data) { + if (!$data['link']['hidden']) { + if ($data['below']) { + $data['below'] = simplemenu_tree_remove_hidden($data['below']); + if (count($data['below']) == 0) { + $data['below'] = 0; + } + } + $clean[] = $data; + } + } + + return $clean; +} + /** * Custom implementation of menu_tree(). * We want to retrieve the entire menu structure for a given menu, * regardless of whether or not the menu item is expanded or not. */ -function simplemenu_menu_tree($menu_name = 'navigation:0') { +function simplemenu_menu_tree($menu_name = 'management:0') { static $menu_tree = array(); if (!isset($menu_output[$menu_name])) { - $menu_tree[$menu_name] = simplemenu_tree_all_data($menu_name); + //$menu_tree[$menu_name] = simplemenu_tree_all_data($menu_name); + $menu_tree[$menu_name] = menu_tree_all_data('management'); } return $menu_tree[$menu_name]; } @@ -357,49 +385,128 @@ function simplemenu_menu_tree($menu_name = 'navigation:0') { * * @todo we don't actually need $menu_name, $mlid would be sufficient */ -function simplemenu_tree_all_data($root_menu = 'navigation:0') { +function simplemenu_tree_all_data($root_menu = 'management:0') { static $tree = array(); list($menu_name, $mlid) = explode(':', $root_menu); - // Generate the cache ID. - // "links:navigation:all:2" means "all from root to 2" (what the ...), so for "all from 2 down" we do "links:navigation:all:2:all" - $cid = "links:$menu_name:all:$mlid" . ($mlid ? ':all' : ''); + // Generate the cache ID for Drupal 7. + $cid = 'links:' . $menu_name . ':all-cid:' . $mlid . ':' . $GLOBALS['language']->language . ':0'; if (!isset($tree[$cid])) { + // // If the static variable doesn't have the data, check {cache_menu}. + // $cache = cache_get($cid, 'cache_menu'); + // if ($cache && isset($cache->data)) { + // $data = $cache->data; + // } + // else { + // // Build and run the query, and build the tree. + // $where = ''; + // $args = array(':menu_name' => $menu_name); + + // if ($mlid > 0) { + // $item = menu_link_load($mlid); + // if ($item) { + // // The tree is a subtree of $menu_name, so we need to restrict the query to + // // this subtree. + // $px = "p" . (int) $item['depth']; + // $where = " AND ml.$px = :ml AND ml.mlid != :mlid"; + // $args[':ml'] = $item[$px]; + // $args[':mlid'] = $mlid; + // } + // } + // // Select the links from the table, and recursively build the tree. We + // // LEFT JOIN since there is no match in {menu_router} for an external + // // link. + // $result = db_query("SELECT m.load_functions, m.to_arg_functions, m.access_callback, + // m.access_arguments, m.page_callback, m.page_arguments, + // m.title, m.title_callback, m.title_arguments, m.type, m.description, ml.* + // FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path + // WHERE ml.menu_name = :menu_name$where + // ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args); + // $data['tree'] = menu_tree_data($result->fetchAssoc()); + // $data['node_links'] = array(); + // menu_tree_collect_node_links($data['tree'], $data['node_links']); + // // Cache the data. + // cache_set($cid, $data, 'cache_menu'); + // } + // // Check access for the current user to each item in the tree. + // menu_tree_check_access($data['tree'], $data['node_links']); + // $tree[$cid] = $data['tree']; + // If the static variable doesn't have the data, check {cache_menu}. $cache = cache_get($cid, 'cache_menu'); if ($cache && isset($cache->data)) { - $data = $cache->data; + // If the cache entry exists, it will just be the cid for the actual data. + // This avoids duplication of large amounts of data. + $cache = cache_get($cache->data, 'cache_menu'); + if ($cache && isset($cache->data)) { + $data = $cache->data; + } } - else { - // Build and run the query, and build the tree. - if ($mlid > 0) { - $item = menu_link_load($mlid); - // The tree is a subtree of $menu_name, so we need to restrict the query to - // this subtree. - $px = "p$item[depth]"; - $where = " AND ml.$px = %d AND ml.mlid != %d"; - $args = array($item[$px], $mlid); + // If the tree data was not in the cache, $data will be NULL. + if (!isset($data)) { + // Build the query using a LEFT JOIN since there is no match in + // {menu_router} for an external link. + $query = db_select('menu_links', 'ml', array('fetch' => PDO::FETCH_ASSOC)); + $query->addTag('translatable'); + $query->leftJoin('menu_router', 'm', 'm.path = ml.router_path'); + $query->fields('ml'); + $query->fields('m', array( + 'load_functions', + 'to_arg_functions', + 'access_callback', + 'access_arguments', + 'page_callback', + 'page_arguments', + 'delivery_callback', + 'title', + 'title_callback', + 'title_arguments', + 'theme_callback', + 'theme_arguments', + 'type', + 'description', + )); + for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) { + $query->orderBy('p' . $i, 'ASC'); + } + $query->condition('ml.menu_name', $menu_name); + if (isset($max_depth)) { + $query->condition('ml.depth', $max_depth, '<='); + } + if ($mlid) { + // The tree is for a single item, so we need to match the values in its + // p columns and 0 (the top level) with the plid values of other links. + $args = array(0); + for ($i = 1; $i < MENU_MAX_DEPTH; $i++) { + $args[] = $link["p$i"]; + } + $args = array_unique($args); + $query->condition('ml.plid', $args, 'IN'); + $parents = $args; + $parents[] = $link['mlid']; } else { // Get all links in this menu. - $where = ''; - $args = array(); + $parents = array(); } - array_unshift($args, $menu_name); - // Select the links from the table, and recursively build the tree. We - // LEFT JOIN since there is no match in {menu_router} for an external - // link. - $data['tree'] = menu_tree_data(db_query(" - SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, m.description, ml.* - FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path - WHERE ml.menu_name = '%s'". $where ." - ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args)); + // Select the links from the table, and build an ordered array of links + // using the query result object. + $links = array(); + foreach ($query->execute() as $item) { + $links[] = $item; + } + $data['tree'] = menu_tree_data($links, $parents); $data['node_links'] = array(); menu_tree_collect_node_links($data['tree'], $data['node_links']); - // Cache the data. - cache_set($cid, $data, 'cache_menu'); + // Cache the data, if it is not already in the cache. + $tree_cid = _menu_tree_cid($menu_name, $data); + if (!cache_get($tree_cid, 'cache_menu')) { + cache_set($tree_cid, $data, 'cache_menu'); + } + // Cache the cid of the (shared) data using the menu and item-specific cid. + cache_set($cid, $tree_cid, 'cache_menu'); } // Check access for the current user to each item in the tree. menu_tree_check_access($data['tree'], $data['node_links']); diff --git a/simplemenu_devel.info b/simplemenu_devel.info index c1fbd307..743c35a5 100644 --- a/simplemenu_devel.info +++ b/simplemenu_devel.info @@ -3,6 +3,14 @@ name = SimpleMenu Devel Menu description = Include the developer menu in the simplemenu tree. dependencies[] = simplemenu dependencies[] = devel -core = 6.x +files[] = simplemenu_devel.module +core = 7.x package = Menu project = simplemenu + +; Information added by drupal.org packaging script on 2010-05-26 +version = "7.x-1.x-dev" +core = "7.x" +project = "simplemenu" +datestamp = "1274876110" + diff --git a/simplemenu_inactive_parents.info b/simplemenu_inactive_parents.info index 90d2a84c..fa5d5940 100644 --- a/simplemenu_inactive_parents.info +++ b/simplemenu_inactive_parents.info @@ -2,6 +2,14 @@ name = SimpleMenu Inactive Parent Menu description = Make all the parent menus inactive so users cannot click on them inadvertendly. dependencies[] = simplemenu -core = 6.x +files[] = simplemenu_inactive_parents.module +core = 7.x package = Menu project = simplemenu + +; Information added by drupal.org packaging script on 2010-05-26 +version = "7.x-1.x-dev" +core = "7.x" +project = "simplemenu" +datestamp = "1274876110" + diff --git a/simplemenu_multi_menu.info b/simplemenu_multi_menu.info index 31c11851..a1beecd8 100644 --- a/simplemenu_multi_menu.info +++ b/simplemenu_multi_menu.info @@ -3,9 +3,18 @@ name = SimpleMenu Multi-Menu support description = Give support to display multiple menu in the top row. dependencies[] = simplemenu dependencies[] = menu -core = 6.x +files[] = simplemenu_multi_menu.install +files[] = simplemenu_multi_menu.module +core = 7.x package = Menu project = simplemenu -version = "6.x-1.x-dev" +version = "7.x-1.x-dev" + + +; Information added by drupal.org packaging script on 2010-05-26 +version = "7.x-1.x-dev" +core = "7.x" +project = "simplemenu" +datestamp = "1274876110"