dpmid]['info'] = t('Dynamic persistent menu #@dpmid', array('@dpmid' => $row->dpmid)); $block[$row->dpmid]['cache'] = BLOCK_NO_CACHE; } return $block; break; case 'view': $dpm = dynamic_persistent_menu_load($delta); $params = explode(':', $dpm->root); $block['content'] = theme('dynamic_persistent_menu', $delta, $params[0], $params[1], $dpm->timeout); return $block; break; case 'configure': if (user_access('administer dynamic persistent menu')) { $dpm = dynamic_persistent_menu_load($delta); $form = dynamic_persistent_menu_setting_base_form($dpm); return $form; } case 'save': if (user_access('administer dynamic persistent menu')) { $dpm = array( 'dpmid' => $edit['dpmid'], 'root' => $edit['root'], 'timeout' => $edit['timeout'], ); drupal_write_record('dynamic_persistent_menu', $dpm, array('dpmid')); } break; } } function dynamic_persistent_menu_init() { drupal_add_css(drupal_get_path('module', 'dynamic_persistent_menu') .'/dynamic-persistent-menu.css', 'module', 'all', TRUE); } /** * Implementation of hook_menu */ function dynamic_persistent_menu_menu() { $items['admin/settings/dynamic_persistent_menu'] = array( 'title' => 'Dynamic persistent menu', 'page callback' => 'dynamic_persistent_menu_settings', 'type' => MENU_NORMAL_ITEM, 'access arguments' => array('administer dynamic persistent menu'), 'file' => 'dynamic_persistent_menu.admin.inc' ); $items['admin/settings/dynamic_persistent_menu/list'] = array( 'title' => t('List'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'access arguments' => array('administer dynamic persistent menu'), ); $items['admin/settings/dynamic_persistent_menu/add'] = array( 'title' => 'New', 'type' => MENU_LOCAL_TASK, 'page callback' => 'drupal_get_form', 'page arguments' => array('dynamic_persistent_menu_settings_form'), 'access arguments' => array('administer dynamic persistent menu'), 'file' => 'dynamic_persistent_menu.admin.inc' ); $items['admin/settings/dynamic_persistent_menu/%dynamic_persistent_menu/edit'] = array( 'title' => 'Edit', 'type' => MENU_CALLBACK, 'page callback' => 'drupal_get_form', 'page arguments' => array('dynamic_persistent_menu_settings_form', 3), 'access arguments' => array('administer dynamic persistent menu'), 'file' => 'dynamic_persistent_menu.admin.inc' ); $items['admin/settings/dynamic_persistent_menu/%dynamic_persistent_menu/delete'] = array( 'title' => 'Delete', 'type' => MENU_CALLBACK, 'page callback' => 'drupal_get_form', 'page arguments' => array('dynamic_persistent_menu_delete_form', 3), 'access arguments' => array('administer dynamic persistent menu'), 'file' => 'dynamic_persistent_menu.admin.inc' ); return $items; } function dynamic_persistent_menu_perm() { return array('administer dynamic persistent menu'); } /** * Implementation of hook_theme */ function dynamic_persistent_menu_theme() { return array( 'dynamic_persistent_menu' => array( 'arguments' => array( 'id' => NULL, 'menu' => NULL, 'parent' => NULL, 'timeout' => NULL ), ), 'dynamic_persistent_menu_menu_item' => array( 'arguments' => array( 'link' => NULL, 'extra_class' => NULL, 'id' => NULL ) ), 'dynamic_persistent_menu_settings_list' => array( 'arguments' => array('menus' => array()), ), ); } /** * Callback functions */ function dynamic_persistent_menu_setting_base_form($dpm = NULL) { $options = menu_parent_options(menu_get_menus(), 0); $form['dpmid'] = array( '#type' => 'hidden', '#value' => $dpm->dpmid ); $form['root'] = array( '#type' => 'select', '#title' => t('Menu root'), '#default_value' => $dpm->root, '#options' => $options, '#description' => t('Choose the menu you wish to display in the block') ); $form['timeout'] = array( '#type' => 'textfield', '#title' => t('Sub-menu timeout'), '#default_value' => $dpm->timeout, '#description' => t('Time before menu hiding when the mouse pointer leaves the parent menu (in milliseconds)') ); return $form; } function dynamic_persistent_menu_load($dpmid) { $result = db_query('SELECT dpmid, root, timeout FROM {dynamic_persistent_menu} WHERE dpmid=%d', $dpmid); return db_fetch_object($result); } function dynamic_persistent_menu_delete($pid) { db_query('DELETE FROM {dynamic_persistent_menu} WHERE dpmid = %d', $pid); } /** * Theme functions */ function theme_dynamic_persistent_menu($id, $menu_name, $mlid, $timeout) { global $language; static $settings; if (!isset($settings)) { $settings = array( "menus" => array() ); $settings_js = drupal_to_js($settings); drupal_add_js("DynamicPersistentMenu = $settings_js;", 'inline'); } $item_class = "dynamic-persistent-menu-menu-item"; $sub_item_class = "dynamic-persistent-menu-sub-menu-item"; // Find menu item in the menu tree $tree = dynamic_persistent_menu_tree_page_data($menu_name, $mlid); // Pull out just the menu items we are going to render so that we // get an accurate count for the first/last classes. foreach ($tree as $data) { if (!$data['link']['hidden']) { $menu_tree[] = $data; } } $menu_link = menu_link_load($mlid); // Don't display anything if the selected menu has no children if (!$menu_tree) { return; } // Build the menus $output = ''; $output .= $submenu; $menu = array( 'default' => $over_menu_default, 'over' => $over_menu_default, 'timeout' => $timeout ); drupal_add_js(array("dynamic_persistent_menu" => array("menus" => array($id => $menu))), 'setting'); drupal_add_js(drupal_get_path('module', 'dynamic_persistent_menu') .'/dynamic_persistent_menu.js'); return $output; } /** * Generate the HTML output for a menu item and submenu item. * * @ingroup themeable */ function theme_dynamic_persistent_menu_menu_item($link, $extra_class = NULL, $id = NULL) { if (!empty($extra_class)) { $class .= ' '. $extra_class; } if ($link['in_active_trail']) { $link['localized_options']['attributes']['class'] = 'active'; } return '
  • '. theme('menu_item_link', $link) ."
  • \n"; } /** * Get the data structure representing a named menu tree, based on the current page. * * The tree order is maintained by storing each parent in an individual * field, see http://drupal.org/node/141866 for more. * * @param $menu_name * The named menu links to return * @return * An array of menu links, in the order they should be rendered. The array * is a list of associative arrays -- these have two keys, link and below. * link is a menu item, ready for theming as a link. Below represents the * submenu below the link if there is one, and it is a subtree that has the * same structure described for the top-level array. */ function dynamic_persistent_menu_tree_page_data($menu_name, $mlid) { static $tree = array(); // Load the menu item corresponding to the current page. if ($item = menu_get_item()) { if (!isset($tree[$cid])) { // If the static variable doesn't have the data, check {cache_menu}. $cache = cache_get($cid, 'cache_menu'); // If the tree data was not in the cache, $data will be NULL. if (!isset($data)) { // Build and run the query, and build the tree. if ($item['access']) { // Check whether a menu link exists that corresponds to the current path. $args = array($menu_name, $item['href']); $placeholders = "'%s'"; if (drupal_is_front_page()) { $args[] = ''; $placeholders .= ", '%s'"; } $parents = db_fetch_array(db_query("SELECT p1, p2, p3, p4, p5, p6, p7, p8 FROM {menu_links} WHERE menu_name = '%s' AND link_path IN (". $placeholders .")", $args)); if (empty($parents)) { // If no link exists, we may be on a local task that's not in the links. // TODO: Handle the case like a local task on a specific node in the menu. $parents = db_fetch_array(db_query("SELECT p1, p2, p3, p4, p5, p6, p7, p8 FROM {menu_links} WHERE menu_name = '%s' AND link_path = '%s'", $menu_name, $item['tab_root'])); } // We always want all the top-level links with plid == 0. $parents[] = '0'; // Use array_values() so that the indices are numeric for array_merge(). $args = array($mlid); for ($i=0; $i < 2; $i++) { $placeholders = implode(', ', array_fill(0, count($args), '%d')); $result = db_query("SELECT * FROM {menu_links} WHERE plid in (". $placeholders .")", $args); while ($row = db_fetch_object($result)) { $args[] = $row->mlid; } } array_shift($args); $placeholders = implode(', ', array_fill(0, count($args), '%d')); array_unshift($args, $menu_name); } else { // Show only the top-level menu items when access is denied. $args = array($menu_name, '0'); $placeholders = '%d'; $parents = array(); } // 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' AND ml.mlid IN (". $placeholders .") ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents); $data['node_links'] = array(); menu_tree_collect_node_links($data['tree'], $data['node_links']); } // Check access for the current user to each item in the tree. menu_tree_check_access($data['tree'], $data['node_links']); $tree = $data['tree']; } return $tree; } return array(); }