From d9f856a075af4e0837d01a2d735f744182adc942 Mon Sep 17 00:00:00 2001 From: Alexis Wilke Date: Sun, 16 May 2010 09:10:28 +0000 Subject: [PATCH] Pretty major update to better support several options: * Added a white border at the top of the drop-downs in original * Optimized the "view" test for simplemenu * Enhanced the init() function by creating sub-functions and moving the footer functionality in it * The list of themes is now dynamically generated from the simplemenu themes folder * The list of superfish now includes a 'custom' so the code may come from another module or theme * The Simplemenu variable can now be moved to the header and cache in its own JS file * Create a Devel and Inactive Parents modules for additional functionality * Moved the simplemenu modules in the Menu package * Changed the function generating the menu so other modules may tweak the menu if so they wish * Moved the support for Devel in a separate sub-module. (this is with the new way of doing things & has a corresponding update hook to tell users about the change. It is actually a good example of using the new hook system!) --- simplemenu.admin.inc | 56 +++-- simplemenu.install | 11 + simplemenu.module | 338 +++++++++++++++++------------ simplemenu_devel.info | 8 + simplemenu_devel.module | 31 +++ simplemenu_inactive_parents.info | 7 + simplemenu_inactive_parents.module | 62 ++++++ 7 files changed, 352 insertions(+), 161 deletions(-) create mode 100644 simplemenu_devel.info create mode 100644 simplemenu_devel.module create mode 100644 simplemenu_inactive_parents.info create mode 100644 simplemenu_inactive_parents.module diff --git a/simplemenu.admin.inc b/simplemenu.admin.inc index 0e47f6a5..aaf09686 100644 --- a/simplemenu.admin.inc +++ b/simplemenu.admin.inc @@ -10,6 +10,8 @@ * SimpleMenu settings page. */ function simplemenu_admin_settings() { + $simplemenu_path = drupal_get_path('module', 'simplemenu'); + // menu selection $form['default_menu'] = array( '#type' => 'fieldset', @@ -22,29 +24,22 @@ function simplemenu_admin_settings() { $form['default_menu']['simplemenu_menu'] = array( '#type' => 'select', '#title' => t('Menu'), - '#options' => menu_parent_options(menu_get_menus(), array( 'mlid' => 0 )), // return complete tree; + '#options' => menu_parent_options(menu_get_menus(), array('mlid' => 0)), // return complete tree '#default_value' => variable_get('simplemenu_menu', 'navigation:0'), '#description' => t('Select the menu to display.'), ); } - if (module_exists('devel')) { - $form['default_menu']['simplemenu_devel'] = array( - '#type' => 'checkbox', - '#title' => t('Add devel module links'), - '#default_value' => variable_get('simplemenu_devel', 0), - '#description' => t('Add devel module links for those users that can access the devel module.'), - ); + $themes = file_scan_directory($simplemenu_path . '/themes', '.*', + array('.', '..', 'CVS', '.svn'), 0, FALSE, 'basename'); + $theme_selection = array('custom' => 'custom'); + foreach ($themes as $name => $ignore) { + $theme_selection[$name] = $name; } - $form['default_menu']['simplemenu_theme'] = array( '#type' => 'select', '#title' => t('Theme'), - '#options' => array( - 'original' => t('original'), - 'blackblue' => t('black & blue'), - 'custom' => t('custom'), - ), + '#options' => $theme_selection, '#default_value' => variable_get('simplemenu_theme', 'original'), '#description' => t('Select which theme to use. If you specify custom, you need to define CSS in your theme.'), ); @@ -68,7 +63,9 @@ function simplemenu_admin_settings() { '#title' => t('Scroll or fix menu'), '#options' => $fix_options, '#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.
WARNING: 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.'), + '#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.'), ); $form['settings']['simplemenu_hide_delay'] = array( @@ -115,24 +112,43 @@ function simplemenu_admin_settings() { '#default_value' => variable_get('simplemenu_uid1', 1), ); - $simplemenu_path = drupal_get_path('module', 'simplemenu'); - $superfish = file_scan_directory($simplemenu_path, '^superfish-[0-9.]*\.js$', + $superfish_js = file_scan_directory($simplemenu_path, '^superfish-[0-9.]*\.js$', array('.', '..', 'CVS', '.svn'), 0, FALSE, 'basename'); - foreach ($superfish as $name => $ignore) { + $superfish = array('custom' => 'custom or theme'); + foreach ($superfish_js as $name => $ignore) { $superfish[$name] = $name; } $form['advanced']['simplemenu_superfish_version'] = array( '#type' => 'select', '#title' => t('SuperFish Version'), '#options' => $superfish, - '#description' => t('Select which version of SuperFish you prefer using.') .$simplemenu_path, + '#description' => t('Select which version of SuperFish you prefer using. The choice "custom or theme" means that Simplemenu does not include one of its own version of Superfish. It is expected that another module or your theme does so already.'), '#default_value' => variable_get('simplemenu_superfish_version', 'superfish-1.4.1.js'), ); + $scope = array( + 'header' => 'Header', + 'footer' => 'Footer', + ); + $form['advanced']['simplemenu_menu_scope'] = array( + '#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.'), + '#default_value' => variable_get('simplemenu_menu_scope', 'footer'), + ); + + $form['advanced']['simplemenu_cache_menu'] = array( + '#type' => 'checkbox', + '#title' => t('Cache the simplemenu variable'), + '#description' => t('The Simplemenu now has the capability to cache the simplemenu variable in a .js file. This accelerate the transfer by using the Browser cache.'), + '#default_value' => variable_get('simplemenu_cache_menu', TRUE), + ); + $form['advanced']['simplemenu_menubar_zindex'] = array( '#type' => 'textfield', '#title' => t('Menubar CSS z-index value'), - '#description' => t('By default, the menubar CSS z-index is set to 1. Some themes or other modules may require you to change this value. Use -1 to completely disable the z-index in the menubar.'), + '#description' => t('By default, the menubar CSS z-index is set to 9999. Some themes or other modules may require you to change this value. Use -1 to completely disable the z-index in the menubar. If this value is not set to -1, then the following z-index will not have any effect and can as well be set to -1.'), '#default_value' => variable_get('simplemenu_menubar_zindex', 9999), ); diff --git a/simplemenu.install b/simplemenu.install index 7b2c41cc..cf2afcf6 100644 --- a/simplemenu.install +++ b/simplemenu.install @@ -30,4 +30,15 @@ function simplemenu_update_6002() { 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(); +} + // vim: ts=2 sw=2 et syntax=php diff --git a/simplemenu.module b/simplemenu.module index d40bdc52..f8fb2c5e 100644 --- a/simplemenu.module +++ b/simplemenu.module @@ -33,10 +33,10 @@ function simplemenu_enabled() { if (!isset($enabled)) { global $theme; $exclusions = variable_get('simplemenu_exclusions', array()); - $enabled = (user_access('view simplemenu') - && (!isset($exclusions[$theme]) || !$exclusions[$theme]) + $enabled = (!isset($exclusions[$theme]) || !$exclusions[$theme]) + && user_access('view simplemenu') && _simplemenu_page_visibility() - && _simplemenu_superuser_active()); + && _simplemenu_superuser_active(); } return $enabled; @@ -47,104 +47,198 @@ function simplemenu_enabled() { */ function simplemenu_init() { // do a simple access check here, since theme isn't available to check yet - if (user_access('view simplemenu') && simplemenu_enabled()) { - $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)) { - // The old way had a "static" CSS which meant that we could not easily - // offer options to the users. - //drupal_add_css($simplemenu_path .'/simplemenu.css'); + if (simplemenu_enabled()) { + _simplemenu_add_menu(); + _simplemenu_add_css(); // basic CSS must be before _simplemenu_add_theme() + _simplemenu_add_theme(); + _simplemenu_add_js(); + } +} - $fix = variable_get('simplemenu_fix', 'scroll'); +/** \brief Add the simplemenu variable with the menu to be displayed. + * + * This function loads the menu to be displayed and transforms it so + * it works with superfish. + * + * If the cache version of the simplemenu JavaScript string cannot be + * created, then it is sent inline whether or not the user asked for it + * to be sent inline. + */ +function _simplemenu_add_menu() { + $simplemenu = 'var simplemenu=' . drupal_to_js(simplemenu_get_menu()) . ';'; - // XXX add a variable simplemenu_update which is set to TRUE whenever - // the settings get modified and false here - $output_filename = variable_get('simplemenu_css_filename', ''); - if (!$output_filename) { - $tags = array( - '@MENUBAR_ZINDEX@' => simplemnu_get_zindex('simplemenu_menubar_zindex', 9999), - '@DROPDOWN_ZINDEX@' => simplemnu_get_zindex('simplemenu_dropdown_zindex', 9999), - ); - switch ($fix) { - case 'top': - $tags['@FIX@'] = "position: fixed;\n top: 0;"; - break; + $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'; - case 'bottom': - $tags['@FIX@'] = "position: fixed;\n bottom: 0;"; - break; - - default: // scroll - $tags['@FIX@'] = 'position: relative;'; - break; - - } - $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'; - if (!file_exists($output_filename)) { - // new content, create a new file - file_put_contents($output_filename, $css); - } - else { - // this call is rather ugly, but we must make sure that the - // system cache will take the current Simplemenu CSS in account - _drupal_flush_css_js(); - } - //variable_set('simplemenu_css_filename', $output_filename); + $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; } - drupal_add_css($output_filename); } - else { + } + + $scope = variable_get('simplemenu_menu_scope', 'footer'); + if ($has_file) { + drupal_add_js($js_filename, 'module', $scope); + } + else { + drupal_add_js($simplemenu, 'inline', $scope); + } +} + +/** \brief Generate the CSS and add it to the page. + * + * This function generates the dynamic CSS and then insert that to + * the header of the page. + * + * The function regenerates the CSS only when the settings were + * modified. Otherwise, it uses the cached version. + * + * The function has a fall back, in case the dynamic CSS cannot + * be created. + */ +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)) { + $fix = variable_get('simplemenu_fix', 'scroll'); + + // XXX add a variable simplemenu_update which is set to TRUE whenever + // the settings get modified and false here + $output_filename = variable_get('simplemenu_css_filename', ''); + if (!$output_filename) { + $tags = array( + '@MENUBAR_ZINDEX@' => simplemnu_get_zindex('simplemenu_menubar_zindex', 9999), + '@DROPDOWN_ZINDEX@' => simplemnu_get_zindex('simplemenu_dropdown_zindex', 9999), + ); + switch ($fix) { + case 'top': + $tags['@FIX@'] = "position: fixed;\n top: 0;"; + break; + + case 'bottom': + $tags['@FIX@'] = "position: fixed;\n bottom: 0;"; + break; + + default: // scroll + $tags['@FIX@'] = 'position: relative;'; + break; + + } + $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'; + if (!file_exists($output_filename)) { + // new content, create a new file + file_put_contents($output_filename, $css); + } + else { + // this call is rather ugly, but we must make sure that the + // system cache will take the current Simplemenu CSS in account + _drupal_flush_css_js(); + } + //variable_set('simplemenu_css_filename', $output_filename); + } + drupal_add_css($output_filename); + } + else { + // in case we cannot create the dynamic CSS + $last_msg = variable_get('simplemenu_css_error', 0); + if (($last_msg != -1 && $last_msg + 3600 > time()) || $user->uid == 1) { + // avoid displaying the error on each page... only once per hour. + // (unless you are the admin, in which case you probably want to know!) + variable_set('simplemenu_css_error', time()); drupal_set_message(t('Simplemenu could not create the folder @path in order to save the dynamic CSS data.', - array('@path' => $css_path)), 'error'); - - // use a default that cannot react to the dynamic changes... - drupal_add_css($simplemenu_path .'/simplemenu.css'); + array('@path' => $css_path)), 'warning'); } - // we want to put the simplemenu theme CSS first - // so we can change some CSS entries dynamically - // but at this time the simplemenu.css is used to - // reset many of the CSS entries... Hmmm... - $simplemenu_theme = variable_get('simplemenu_theme', 'original'); - $theme_file = $simplemenu_path .'/themes/'. $simplemenu_theme .'/'. $simplemenu_theme .'.css'; + // use a default that cannot react to the dynamic changes... + drupal_add_css($simplemenu_path .'/simplemenu.css'); + } +} + +/** \brief Add the module theme. + * + * This function adds a theme for the Simplemenu look. + * + * By default, the original theme is used. The module also offers the + * blackblue theme. It is also possible to create new themes or use + * the theming of the current theme for simplemenu (so the menu fits + * perfectly for that theme.) + */ +function _simplemenu_add_theme() { + // we want to put the simplemenu theme CSS first + // so we can change some CSS entries dynamically + // but at this time the simplemenu.css is used to + // reset many of the CSS entries... Hmmm... + $simplemenu_theme = variable_get('simplemenu_theme', 'original'); + if ($simplemenu_theme != 'custom') { + $simplemenu_path = drupal_get_path('module', 'simplemenu'); + $theme_file = $simplemenu_path . '/themes/' . $simplemenu_theme + . '/' . $simplemenu_theme . '.css'; if (is_file($theme_file)) { drupal_add_css($theme_file); } + } +} - switch ($fix) { - case 'top': - $element = 'body'; - $placement = 'prepend'; - break; +/** \brief Add the JavaScript that makes it all work. + * + * This function adds the Simplemenu JavaScript, the Superfish JavaScript + * and settings from the user. + */ +function _simplemenu_add_js() { + $simplemenu_path = drupal_get_path('module', 'simplemenu'); - case 'bottom': - $element = 'body'; - $placement = 'append'; - break; + // Settings + $fix = variable_get('simplemenu_fix', 'scroll'); + switch ($fix) { + case 'top': + $element = 'body'; + $placement = 'prepend'; + break; - default: // 'scroll' - // let user defined other elements when not fixed - $element = variable_get('simplemenu_element', 'body'); - $placement = variable_get('simplemenu_element_method', 'prepend'); - break; + case 'bottom': + $element = 'body'; + $placement = 'append'; + break; - } + default: // 'scroll' + // let user defined other elements when not fixed + $element = variable_get('simplemenu_element', 'body'); + $placement = variable_get('simplemenu_element_method', 'prepend'); + break; - $settings = array( - 'effect' => variable_get('simplemenu_effect', 'opacity'), - 'effectSpeed' => variable_get('simplemenu_effect_speed', 'fast'), - 'element' => $element, - 'placement' => $placement, - 'hideDelay' => variable_get('simplemenu_hide_delay', 800), - 'detectPopup' => variable_get('simplemenu_detect_popup', 1), - ); + } + $settings = array( + 'effect' => variable_get('simplemenu_effect', 'opacity'), + 'effectSpeed' => variable_get('simplemenu_effect_speed', 'fast'), + 'element' => $element, + 'placement' => $placement, + '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), 'setting'); - drupal_add_js($simplemenu_path . '/simplemenu.js'); - $superfish = variable_get('simplemenu_superfish_version', 'superfish-1.4.1.js'); + // Simplemenu + drupal_add_js($simplemenu_path . '/simplemenu.js'); + + // Superfish + $superfish = variable_get('simplemenu_superfish_version', 'superfish-1.4.1.js'); + if ($superfish != 'custom') { drupal_add_js($simplemenu_path . '/' . $superfish); } } @@ -173,27 +267,6 @@ function simplemnu_get_zindex($name, $default) { return $zindex; } -/** - * Implementation of hook_footer(). - * - * This has been broken off of simplemenu_init() because simplemenu_get_menu() - * calls simplemenu_menu_tree() which calls menu_tree_output() which has several - * calls to theme(). This initializes the theme system too early causing hard - * to track bugs. - * - * @see http://drupal.org/node/219910 - */ -function simplemenu_footer() { - if (simplemenu_enabled()) { - $simplemenu = drupal_to_js(simplemenu_get_menu()); - $path = base_path() . drupal_get_path('module', 'simplemenu'); - - $output = "\n"; - - return $output; - } -} - /** * Implementation of hook_perm(). */ @@ -205,27 +278,30 @@ function simplemenu_perm() { * Render an HTML list of links for a given menu. */ function simplemenu_get_menu() { + variable_set('simplemenu_running', TRUE); + // if a user turned off menu module but SimpleMenu was previously set // reset variable so a menu appears $menu_name = module_exists('menu') ? variable_get('simplemenu_menu', 'navigation:0') : 'navigation:0'; - $menu = simplemenu_menu_tree($menu_name); + $tree = simplemenu_menu_tree($menu_name); + // allow other modules to modify the menu tree + drupal_alter('simplemenu_tree', $tree); + + // now generate the output + $menu = menu_tree_output($tree); if (!$menu) { - $menu = ''; + $menu = ''; } - // This is ugly, I know, but it is the only way I can see to get the additional - // links inside the