123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570 |
- <?php
- /**
- * @file
- * Module to enable CSS dropdown and flyout menus.
- *
- * Maintainer: Addison Berry (add1sun)
- * Originally written by Jake Gordon (jakeg)
- */
- /**
- * Implements hook_help().
- */
- function nice_menus_help($path, $arg) {
- $output = '';
- switch ($path) {
- case 'admin/config/modules#description':
- $output .= t('Make drop down/flyout CSS menus for site and admin menus.');
- break;
- case 'admin/config/nice_menus':
- $output .= t('<p>This is a simple module that enables the site to have drop down/flyout CSS menus for site and admin navigation.</p><p>Remember to activate and configure the menu blocks in !link</p>', array('!link' => l('admin/structure/block', 'admin/structure/block')));
- break;
- }
- return $output;
- }
- /**
- * Implements hook_form_alter().
- */
- function nice_menus_form_alter(&$form, $form_state, $form_id) {
- switch ($form_id) {
- case 'system_theme_settings':
- // This is a global setting, so only insert the field
- // on the global settings page.
- if (arg(4) && arg(4) != 'global') {
- return;
- }
- // Have to add a custom submit handler since this form doesn't use
- // the standard system submit handler.
- $form['#submit'][] = 'nice_menus_system_theme_settings_submit';
- // Add global theme setting for a custom CSS file.
- $form['nice_menus_custom_css'] = array(
- '#type' => 'textfield',
- '#title' => t('Path to custom Nice menus CSS file'),
- '#description' => t('To override the default Nice menus CSS layout, enter the path to your custom CSS file. It should be a relative path from the root of your Drupal install (e.g. sites/all/themes/example/mymenu.css).'),
- '#default_value' => variable_get('nice_menus_custom_css', ''),
- // Field appears below submit buttons without this -- yucky.
- '#weight' => 0,
- );
- break;
- }
- }
- /**
- * Records the Nice menu custom CSS file per theme.
- */
- function nice_menus_system_theme_settings_submit($form, &$form_state) {
- variable_set('nice_menus_custom_css', $form_state['values']['nice_menus_custom_css']);
- }
- /**
- * Implements hook_menu().
- */
- function nice_menus_menu() {
- $items['admin/config/user-interface/nice_menus'] = array(
- 'title' => 'Nice menus',
- 'description' => 'Configure Nice menus.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('nice_menus_admin_settings'),
- 'access arguments' => array('administer site configuration'),
- 'type' => MENU_NORMAL_ITEM,
- );
- return $items;
- }
- /**
- * Settings form as implemented by hook_menu
- */
- function nice_menus_admin_settings($form, &$form_state) {
- $form['nice_menus_number'] = array(
- '#type' => 'textfield',
- '#description' => t('The total number of independent Nice menus blocks you want. Enter a number between 0 and 99. If you set this to 0, you will have no blocks created but you can still use the Nice menus theme functions directly in your theme.'),
- '#default_value' => variable_get('nice_menus_number', '2'),
- '#size' => 2,
- );
- $form['nice_menus_js'] = array(
- '#type' => 'checkbox',
- '#title' => t('Use JavaScript'),
- '#description' => t('This will add Superfish Jquery to Nice menus. This is required for Nice menus to work properly in Internet Explorer.'),
- '#default_value' => variable_get('nice_menus_js', 1),
- );
- $form['nice_menus_sf_options'] = array(
- '#type' => 'fieldset',
- '#title' => t('Advanced: Superfish options'),
- '#description' => t('You can change the default Superfish options by filling out the desired values here. These only take effect if the Use JavaScript box above is checked.'),
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- );
- $form['nice_menus_sf_options']['nice_menus_sf_delay'] = array(
- '#type' => 'textfield',
- '#title' => t('Mouse delay'),
- '#description' => t('The delay in milliseconds that the mouse can remain outside a submenu without it closing.'),
- '#default_value' => variable_get('nice_menus_sf_delay', 800),
- '#size' => 5,
- );
- $form['nice_menus_sf_options']['nice_menus_sf_speed'] = array(
- '#type' => 'select',
- '#title' => t('Animation speed'),
- '#multiple' => FALSE,
- '#description' => t('Speed of the menu open/close animation.'),
- '#options' => array(
- 'slow' => t('slow'),
- 'normal' => t('normal'),
- 'fast' => t('fast'),
- ),
- '#default_value' => variable_get('nice_menus_sf_speed', 1),
- );
- // Custom validation to make sure the user is entering numbers.
- $form['#validate'][] = 'nice_menus_settings_validate';
- return system_settings_form($form);
- }
- /**
- * Custom validation for the settings form.
- */
- function nice_menus_settings_validate($form, &$form_state) {
- $number = $form_state['values']['nice_menus_number'];
- // Check to make sure it is a number and that is a maximum of 2 digits.
- if (!is_numeric($number) || strlen($number) > 2) {
- form_set_error('nice_menus_number', t('You must enter a number from 0 to 99.'));
- }
- }
- /**
- * Implements hook_init().
- *
- * We are adding the JavaScript and CSS here rather than theme_nice_menu
- * because when block caching is enabled none of it would get fired
- * and the menus are unstyled.
- */
- function nice_menus_init() {
- // Add Superfish JavaScript, if enabled.
- if (variable_get('nice_menus_js', 1) == 1) {
- // The script, from http://users.tpg.com.au/j_birch/plugins/superfish.
- drupal_add_js(drupal_get_path('module', 'nice_menus') . '/superfish/js/superfish.js');
- // Add the Superfish options variables.
- drupal_add_js(array(
- 'nice_menus_options' => array(
- 'delay' => variable_get('nice_menus_sf_delay', 800),
- 'speed' => variable_get('nice_menus_sf_speed', 1),
- ),
- ), array('type' => 'setting', 'scope' => JS_DEFAULT));
- // Add the bgIframe plugin.
- drupal_add_js(drupal_get_path('module', 'nice_menus') . '/superfish/js/jquery.bgiframe.min.js');
- // Add the HoverIntent plugin.
- drupal_add_js(drupal_get_path('module', 'nice_menus') . '/superfish/js/jquery.hoverIntent.minified.js');
- // The Nice menus implementation.
- drupal_add_js(drupal_get_path('module', 'nice_menus') . '/nice_menus.js');
- }
- // Add main CSS functionality.
- drupal_add_css(drupal_get_path('module', 'nice_menus') . '/nice_menus.css', array('group' => CSS_DEFAULT, 'basename' => 'nice_menus.css'));
- // Add custom CSS layout if specified.
- if ($custom = variable_get('nice_menus_custom_css', '')) {
- drupal_add_css($custom, array('group' => CSS_DEFAULT, 'basename' => 'nice_menus_custom.css'));
- }
- // Fall back to default layout.
- else {
- drupal_add_css(drupal_get_path('module', 'nice_menus') . '/nice_menus_default.css', array('group' => CSS_DEFAULT, 'basename' => 'nice_menus_default.css'));
- }
- }
- /**
- * Implements hook_block_info().
- */
- function nice_menus_block_info() {
- $blocks = array();
- for ($i = 1; $i <= variable_get('nice_menus_number', '2'); $i++) {
- $blocks[$i]['info'] = variable_get('nice_menus_name_' . $i, 'Nice menu ' . $i) . ' (Nice menu)';
- // We have too many things changing per user, per page to cache.
- $blocks[$i]['cache'] = DRUPAL_NO_CACHE;
- }
- return $blocks;
- }
- /**
- * Implements hook_block_configure().
- */
- function nice_menus_block_configure($delta) {
- $form['nice_menus_name_' . $delta] = array(
- '#type' => 'textfield',
- '#title' => t('Menu Name'),
- '#default_value' => variable_get('nice_menus_name_' . $delta, 'Nice menu ' . $delta),
- );
- $form['nice_menus_menu_' . $delta] = array(
- '#type' => 'select',
- '#title' => t('Menu Parent'),
- '#description' => t('The menu parent from which to show a Nice menu.'),
- '#default_value' => variable_get('nice_menus_menu_' . $delta, 'navigation:0'),
- '#options' => menu_get_menus(),
- );
- $form['nice_menus_depth_' . $delta] = array(
- '#type' => 'select',
- '#title' => t('Menu Depth'),
- '#description' => t('The depth of the menu, i.e. the number of child levels starting with the parent selected above. Leave set to -1 to display all children and use 0 to display no children.'),
- '#default_value' => variable_get('nice_menus_depth_' . $delta, -1),
- '#options' => drupal_map_assoc(range(-1, 5)),
- );
- $form['nice_menus_type_' . $delta] = array(
- '#type' => 'select',
- '#title' => t('Menu Style'),
- '#description' => t('right: menu items are listed on top of each other and expand to the right') . '<br />' . t('left: menu items are listed on top of each other and expand to the left') . '<br />' . t('down: menu items are listed side by side and expand down'),
- '#default_value' => variable_get('nice_menus_type_' . $delta, 'right'),
- '#options' => drupal_map_assoc(array('right', 'left', 'down')),
- );
- return $form;
- }
- /**
- * Implements hook_block_save().
- */
- function nice_menus_block_save($delta, $edit) {
- variable_set('nice_menus_name_' . $delta, $edit['nice_menus_name_' . $delta]);
- variable_set('nice_menus_menu_' . $delta, $edit['nice_menus_menu_' . $delta]);
- variable_set('nice_menus_depth_' . $delta, $edit['nice_menus_depth_' . $delta]);
- variable_set('nice_menus_type_' . $delta, $edit['nice_menus_type_' . $delta]);
- }
- /**
- * Implements hook_block_view().
- */
- function nice_menus_block_view($delta) {
- // Build the Nice menu for the block.
- list($menu_name) = explode(':', variable_get('nice_menus_menu_' . $delta, 'navigation:0'));
- $direction = variable_get('nice_menus_type_' . $delta, 'right');
- $depth = variable_get('nice_menus_depth_' . $delta, '-1');
- if ($output = theme('nice_menus', array('id' => $delta, 'menu_name' => $menu_name, 'direction' => $direction, 'depth' => $depth))) {
- $block['content'] = $output['content'];
- if (variable_get('nice_menus_type_' . $delta, 'right') == 'down') {
- $class = 'nice-menu-hide-title';
- }
- else {
- $class = 'nice-menu-show-title';
- }
- // If we're building the navigation block
- // use the same block title logic as menu module.
- global $user;
- if ($output['subject'] == t('navigation') && $user->uid) {
- $subject = $user->name;
- }
- else {
- $subject = $output['subject'];
- }
- $block['subject'] = '<span class="' . $class . '">' . check_plain($subject) . '</span>';
- }
- else {
- $block['content'] = FALSE;
- }
- return $block;
- }
- /**
- * Implements hook_theme().
- */
- function nice_menus_theme() {
- return array(
- 'nice_menus_tree' => array(
- 'variables' => array('menu_name' => NULL, 'mlid' => NULL, 'depth' => -1, 'menu' => NULL),
- ),
- 'nice_menus_build' => array(
- 'variables' => array('menu' => NULL, 'depth' => -1, 'trail' => NULL),
- ),
- 'nice_menus' => array(
- 'variables' => array('id' => NULL, 'menu_name' => NULL, 'mlid' => NULL, 'direction' => 'right', 'depth' => -1, 'menu' => NULL),
- ),
- 'nice_menus_main_menu' => array(
- 'variables' => array('direction' => 'down', 'depth' => -1),
- ),
- 'nice_menus_secondary_menu' => array(
- 'variables' => array('direction' => 'down', 'depth' => -1),
- ),
- );
- }
- /**
- * Builds the active trail from the page's menu data.
- *
- * @param $page_menu
- * The menu data for a page.
- *
- * @return
- * An array of parent menu item ids.
- */
- function nice_menus_build_page_trail($page_menu) {
- $trail = array();
- foreach ($page_menu as $item) {
- if ($item['link']['in_active_trail']) {
- $trail[] = $item['link']['mlid'];
- }
- if ($item['below']) {
- $trail = array_merge($trail, nice_menus_build_page_trail($item['below']));
- }
- }
- return $trail;
- }
- /**
- * Builds the final Nice menu.
- *
- * @param $menu_name
- * The top-level menu name that contains the menu to use (e.g. navigation
- * or main-menu) for Drupal menus. For custom $menus this is just the
- * name for menu display.
- * @param $mlid
- * The menu ID from which to start building the items, i.e. the parent
- * of the displayed menu.
- * @param $depth
- * The number of children levels to display. Use -1 to display all children
- * and use 0 to display no children.
- * @param $menu
- * Optional. A custom menu array to use for theming -- it should have
- * the same structure as that returned by menu_tree_all_data().
- *
- * @return
- * An HTML string of properly nested Nice menu lists.
- */
- function theme_nice_menus_tree($variables) {
- $menu_name = $variables['menu_name'];
- $mlid = $variables['mlid'];
- $depth = $variables['depth'];
- $menu = $variables['menu'];
- // Load the full menu array.
- $menu = isset($menu) ? $menu : menu_tree_all_data($menu_name);
- if (isset($menu)) {
- $page_menu = menu_tree_page_data($menu_name);
- $trail = nice_menus_build_page_trail($page_menu);
- unset($page_menu);
- }
- // Allow i18n module to translate strings where available.
- if (module_exists('i18n_menu')) {
- $menu = i18n_menu_localize_tree($menu);
- }
-
- // Assume depth == 0 by default, overriden if mlid is specified.
- $parent_depth = 0;
-
- // For custom $menus and menus built all the way from the top-level we
- // don't need to "create" the specific sub-menu and we need to get the title
- // from the $menu_name since there is no "parent item" array.
- // Create the specific menu if we have a mlid.
- if (!empty($mlid)) {
- // Load the parent menu item.
- $item = menu_link_load($mlid);
- $title = check_plain($item['title']);
- // The depth for our parent item, if it exists.
- $parent_depth = ($item['depth']) ? $item['depth'] : 0;
- // Narrow down the full menu to the specific sub-tree we need.
- for ($p = 1; $p < 10; $p++) {
- if ($sub_mlid = $item["p$p"]) {
- $subitem = menu_link_load($sub_mlid);
- // Menu sets these ghetto-ass keys in _menu_tree_check_access().
- $menu = $menu[(50000 + $subitem['weight']) . ' ' . $subitem['title'] . ' ' . $subitem['mlid']]['below'];
- }
- }
- }
- // Otherwise just set a title and move on.
- else {
- // Get the title from the DB since we don't have it in the $menu.
- $result = db_query("SELECT title FROM {menu_custom} WHERE menu_name = :menu_name", array(':menu_name' => $menu_name))->fetchField();
- $title = check_plain($result);
- }
- $output['content'] = '';
- $output['subject'] = $title;
- if ($menu) {
- // Set the total menu depth counting from this parent if we need it.
- $depth = ($depth > 0) ? ($parent_depth + $depth) : $depth;
- $output['content'] .= theme('nice_menus_build', array('menu' => $menu, 'depth' => $depth, 'trail' => $trail));
- }
-
- return $output;
- }
- /**
- * Helper function that builds the nested lists of a Nice menu.
- *
- * @param $menu
- * Menu array from which to build the nested lists.
- * @param $depth
- * The number of children levels to display. Use -1 to display all children
- * and use 0 to display no children.
- * @param $trail
- * An array of parent menu items.
- */
- function theme_nice_menus_build($variables) {
- $menu = $variables['menu'];
- $depth = $variables['depth'];
- $trail = $variables['trail'];
- $output = '';
- // Prepare to count the links so we can mark first, last, odd and even.
- $index = 0;
- $count = 0;
- foreach ($menu as $menu_count) {
- if ($menu_count['link']['hidden'] == 0) {
- $count++;
- }
- }
- // Get to building the menu.
- foreach ($menu as $menu_item) {
- $mlid = $menu_item['link']['mlid'];
- // Check to see if it is a visible menu item.
- if (!isset($menu_item['link']['hidden']) || $menu_item['link']['hidden'] == 0) {
- // Check our count and build first, last, odd/even classes.
- $index++;
- $first_class = $index == 1 ? ' first ' : '';
- $oddeven_class = $index % 2 == 0 ? ' even ' : ' odd ';
- $last_class = $index == $count ? ' last ' : '';
- // Build class name based on menu path
- // e.g. to give each menu item individual style.
- // Strip funny symbols.
- $clean_path = str_replace(array('http://', 'www', '<', '>', '&', '=', '?', ':', '.'), '', $menu_item['link']['href']);
- // Convert slashes to dashes.
- $clean_path = str_replace('/', '-', $clean_path);
- $class = 'menu-path-' . $clean_path;
- if ($trail && in_array($mlid, $trail)) {
- $class .= ' active-trail';
- }
- // If it has children build a nice little tree under it.
- if ((!empty($menu_item['link']['has_children'])) && (!empty($menu_item['below'])) && $depth != 0) {
- // Keep passing children into the function 'til we get them all.
- if ($menu_item['link']['depth'] <= $depth || $depth == -1) {
- $children = array(
- '#theme' => 'nice_menus_build',
- '#prefix' => '<ul>',
- '#suffix' => '</ul>',
- '#menu' => $menu_item['below'],
- '#depth' => $depth,
- '#trail' => $trail,
- );
- }
- else {
- $children = '';
- }
- // Set the class to parent only of children are displayed.
- $parent_class = ($children && ($menu_item['link']['depth'] <= $depth || $depth == -1)) ? 'menuparent ' : '';
- $element = array(
- '#below' => $children,
- '#title' => $menu_item['link']['link_title'],
- '#href' => $menu_item['link']['href'],
- '#localized_options' => $menu_item['link']['localized_options'],
- '#attributes' => array(
- 'class' => array('menu-' . $mlid, $parent_class, $class, $first_class, $oddeven_class, $last_class),
- ),
- );
- $variables['element'] = $element;
- $output .= theme('menu_link', $variables);
-
- }
- else {
-
- $element = array(
- '#below' => '',
- '#title' => $menu_item['link']['link_title'],
- '#href' => $menu_item['link']['href'],
- '#localized_options' => $menu_item['link']['localized_options'],
- '#attributes' => array(
- 'class' => array('menu-' . $mlid, $class, $first_class, $oddeven_class, $last_class),
- ),
- );
- $variables['element'] = $element;
- $output .= theme('menu_link', $variables);
- }
- }
- }
- return $output;
- }
- /**
- * Theme function to allow any menu tree to be themed as a Nice menu.
- *
- * @param $id
- * The Nice menu ID.
- * @param $menu_name
- * The top parent menu name from which to build the full menu.
- * @param $mlid
- * The menu ID from which to build the displayed menu.
- * @param $direction
- * Optional. The direction the menu expands. Default is 'right'.
- * @param $depth
- * The number of children levels to display. Use -1 to display all children
- * and use 0 to display no children.
- * @param $menu
- * Optional. A custom menu array to use for theming --
- * it should have the same structure as that returned
- * by menu_tree_all_data(). Default is the standard menu tree.
- *
- * @return
- * An HTML string of Nice menu links.
- */
- function theme_nice_menus($variables) {
- $output = array(
- 'content' => '',
- 'subject' => '',
- );
- $id = $variables['id'];
- $menu_name = $variables['menu_name'];
- $mlid = $variables['mlid'];
- $direction = $variables['direction'];
- $depth = $variables['depth'];
- $menu = $variables['menu'];
- if ($menu_tree = theme('nice_menus_tree', array('menu_name' => $menu_name, 'mlid' => $mlid, 'depth' => $depth, 'menu' => $menu))) {
- if ($menu_tree['content']) {
- $output['content'] = '<ul class="nice-menu nice-menu-' . $direction . '" id="nice-menu-' . $id . '">' . $menu_tree['content'] . '</ul>' . "\n";
- $output['subject'] = $menu_tree['subject'];
- }
- }
- return $output;
- }
- /**
- * Theme the main menu as a Nice menu.
- *
- * @param $direction
- * Optional. The direction the menu expands. Default is 'down'.
- * @param $depth
- * The number of children levels to display. Use -1 to display all children
- * and use 0 to display no children.
- *
- * @return
- * An HTML string of Nice main menu links.
- */
- function theme_nice_menus_main_menu($variables) {
- $direction = $variables['direction'];
- $depth = $variables['depth'];
- $menu_name = variable_get('menu_main_links_source', 'main-menu');
- $output = theme('nice_menus', array('id' => 0, 'menu_name' => $menu_name, 'mlid' => 0, 'direction' => $direction, 'depth' => $depth));
- return $output['content'];
- }
- /**
- * Theme the secondary menu as a Nice menu.
- *
- * @param $direction
- * Optional. The direction the menu expands. Default is 'down'.
- * @param $depth
- * The number of children levels to display. Use -1 to display all children
- * and use 0 to display no children.
- *
- * @return
- * An HTML string of Nice secondary menu links.
- */
- function theme_nice_menus_secondary_menu($variables) {
- $direction = $variables['direction'];
- $depth = $variables['depth'];
- $menu_name = variable_get('menu_secondary_links_source', 'user-menu');
- $output = theme('nice_menus', array('id' => 0, 'menu_name' => $menu_name, 'mlid' => 0, 'direction' => $direction, 'depth' => $depth));
- return $output['content'];
- }
|