diff options
-rw-r--r-- | includes/common.inc | 19 | ||||
-rw-r--r-- | includes/database.inc | 1 | ||||
-rw-r--r-- | includes/menu.inc | 79 | ||||
-rw-r--r-- | modules/comment/comment.module | 20 | ||||
-rw-r--r-- | modules/menu/menu.module | 967 | ||||
-rw-r--r-- | modules/node/node.module | 2 | ||||
-rw-r--r-- | modules/system/system.module | 2 |
7 files changed, 560 insertions, 530 deletions
diff --git a/includes/common.inc b/includes/common.inc index 1c18f6d34..7ddf2ac82 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -2292,22 +2292,3 @@ function element_child($key) { function element_children($element) { return array_filter(array_keys((array) $element), 'element_child'); } - -/** - * Generate vancode. - * - * Consists of a leading character indicating length, followed by N digits - * with a numerical value in base 36. Vancodes can be sorted as strings - * without messing up numerical order. - * - * It goes: - * 00, 01, 02, ..., 0y, 0z, - * 110, 111, ... , 1zy, 1zz, - * 2100, 2101, ..., 2zzy, 2zzz, - * 31000, 31001, ... - */ -function int2vancode($i = 0) { - $num = base_convert((int)$i, 10, 36); - $length = strlen($num); - return chr($length + ord('0') - 1) . $num; -} diff --git a/includes/database.inc b/includes/database.inc index 9a837a576..66e00df03 100644 --- a/includes/database.inc +++ b/includes/database.inc @@ -312,4 +312,3 @@ function db_escape_table($string) { * @} End of "defgroup database". */ - diff --git a/includes/menu.inc b/includes/menu.inc index 87e5b34b8..54c6f4617 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -167,7 +167,27 @@ define('MENU_HANDLE_REQUEST', 0); define('MENU_RENDER_LINK', 1); /** - * @} End of "Menu helper directions + * @} End of "Menu operations." + */ + +/** + * @Name Menu alterations + * @{ + * Menu alter phases + */ + +/** + * Alter the menu as defined in modules, keys are like user/%user. + */ +define('MENU_ALTER_MODULE_DEFINED', 0); + +/** + * Alter the menu after the first preprocessing phase, keys are like user/%. + */ +define('MENU_ALTER_PREPROCESSED', 1); + +/** + * @} End of "Menu alterations". */ /** @@ -290,7 +310,9 @@ function menu_get_item($path = NULL, $item = NULL) { if ($item = db_fetch_object(db_query_range('SELECT * FROM {menu} WHERE path IN ('. implode (',', $placeholders) .') ORDER BY fit DESC', $ancestors, 0, 1))) { // We need to access check the parents to match the navigation tree // behaviour. The last parent is always the item itself. - $result = db_query('SELECT * FROM {menu} WHERE mid IN ('. $item->parents .') ORDER BY mleft'); + $args = explode(',', $item->parents); + $placeholders = implode(', ', array_fill(0, count($args), '%d')); + $result = db_query('SELECT * FROM {menu} WHERE mid IN ('. $placeholders .') ORDER BY mleft', $args); $item->access = TRUE; while ($item->access && ($parent = db_fetch_object($result))) { $map = _menu_translate($parent, $original_map); @@ -379,7 +401,8 @@ function _menu_translate(&$item, $map, $operation = MENU_HANDLE_REQUEST) { $return = $load_function(isset($path_map[$index]) ? $path_map[$index] : ''); // If callback returned an error or there is no callback, trigger 404. if ($return === FALSE) { - return array(FALSE, FALSE, ''); + $item->access = FALSE; + return FALSE; } $map[$index] = $return; } @@ -414,7 +437,9 @@ function _menu_translate(&$item, $map, $operation = MENU_HANDLE_REQUEST) { */ function menu_tree() { if ($item = menu_get_item()) { - list(, $menu) = _menu_tree(db_query('SELECT * FROM {menu} WHERE pid IN ('. $item->parents .') AND visible = 1 ORDER BY mleft')); + $args = explode(',', $item->parents); + $placeholders = implode(', ', array_fill(0, count($args), '%d')); + list(, $menu) = _menu_tree(db_query('SELECT * FROM {menu} WHERE pid IN ('. $placeholders .') AND visible = 1 ORDER BY mleft', $args)); return $menu; } } @@ -552,8 +577,11 @@ function menu_rebuild() { // TODO: split menu and menu links storage. db_query('DELETE FROM {menu}'); $menu = module_invoke_all('menu'); - drupal_alter('menu', $menu); + + // Alter the menu as defined in modules, keys are like user/%user. + drupal_alter('menu', $menu, MENU_ALTER_MODULE_DEFINED); $mid = 1; + // First pass: separate callbacks from pathes, making pathes ready for // matching. Calculate fitness, and fill some default values. foreach ($menu as $path => $item) { @@ -626,15 +654,21 @@ function menu_rebuild() { $menu_path_map[$path] = $new_path; $menu[$new_path] = $item; } + + // Alter the menu after the first preprocessing phase, keys are like user/%. + drupal_alter('menu', $menu, MENU_ALTER_PREPROCESSED); + $menu_path_map[''] = ''; // Second pass: prepare for sorting and find parents. foreach ($menu as $path => $item) { $item = &$menu[$path]; $number_parts = $item['_number_parts']; if (isset($item['parent'])) { - $item['parent'] = $menu_path_map[$item['parent']]; + if (isset($menu_path_map[$item['parent']])) { + $item['parent'] = $menu_path_map[$item['parent']]; + } $parent_parts = explode('/', $item['parent'], 6); - $slashes = count($parent_parts) - 1; + $slashes = count($parent_parts); } else { $parent_parts = $item['_parts']; @@ -670,6 +704,7 @@ function menu_rebuild() { unset($item); } array_multisort($sort, $menu); + // We are now sorted, so let's build the tree. $children = array(); foreach ($menu as $path => $item) { @@ -678,6 +713,7 @@ function menu_rebuild() { } } menu_renumber($menu); + // Apply inheritance rules. foreach ($menu as $path => $item) { $item = &$menu[$path]; @@ -719,6 +755,9 @@ function menu_rebuild() { if (is_bool($item['access callback'])) { $item['access callback'] = intval($item['access callback']); } + if (empty($item['page callback'])) { + $item['access callback'] = 0; + } if ($item['_tab']) { if (!isset($item['parent'])) { $item['parent'] = implode('/', array_slice($item['_parts'], 0, $item['_number_parts'] - 1)); @@ -764,7 +803,11 @@ function menu_rebuild() { break; } } - + // We remove disabled items here -- this way they will be numbered in the + // tree so the menu overview screen can show them. + if (!empty($item['disabled'])) { + $item['_visible'] = FALSE; + } db_query("INSERT INTO {menu} ( mid, pid, path, load_functions, to_arg_functions, access_callback, access_arguments, page_callback, page_arguments, fit, @@ -914,3 +957,23 @@ function menu_get_active_title() { } } } + +/** + * Get a menu item by its mid, access checked and link translated for + * rendering. + * + * @param $mid + * The mid of the menu item. + * @return + * A menu object, with $item->access filled and link translated for + * rendering. + */ +function menu_get_item_by_mid($mid) { + if ($item = db_fetch_object(db_query('SELECT * FROM {menu} WHERE mid = %d', $mid))) { + _menu_translate($item, arg(), MENU_RENDER_LINK); + if ($item->access) { + return $item; + } + } + return FALSE; +} diff --git a/modules/comment/comment.module b/modules/comment/comment.module index 1c650eaff..e3b0a4e51 100644 --- a/modules/comment/comment.module +++ b/modules/comment/comment.module @@ -1989,6 +1989,26 @@ function comment_invoke_comment(&$comment, $op) { return $return; } + +/** + * Generate vancode. + * + * Consists of a leading character indicating length, followed by N digits + * with a numerical value in base 36. Vancodes can be sorted as strings + * without messing up numerical order. + * + * It goes: + * 00, 01, 02, ..., 0y, 0z, + * 110, 111, ... , 1zy, 1zz, + * 2100, 2101, ..., 2zzy, 2zzz, + * 31000, 31001, ... + */ +function int2vancode($i = 0) { + $num = base_convert((int)$i, 10, 36); + $length = strlen($num); + return chr($length + ord('0') - 1) . $num; +} + /** * Decode vancode back to an integer. */ diff --git a/modules/menu/menu.module b/modules/menu/menu.module index 3a4eae773..b5661b77c 100644 --- a/modules/menu/menu.module +++ b/modules/menu/menu.module @@ -32,53 +32,69 @@ Menu administration tabs: } /** + * Implementation of hook_perm(). + */ +function menu_perm() { + return array('administer menu'); +} + +/** * Implementation of hook_menu(). */ function menu_menu() { - return; - $items = array(); - - if ($may_cache) { - $items[] = array('path' => 'admin/build/menu', - 'title' => t('Menus'), - 'description' => t("Control your site's navigation menu, primary links and secondary links. as well as rename and reorganize menu items."), - 'callback' => 'menu_overview', - 'access' => user_access('administer menu')); - $items[] = array('path' => 'admin/build/menu/list', - 'title' => t('List'), - 'type' => MENU_DEFAULT_LOCAL_TASK, - 'weight' => -10); - - $items[] = array('path' => 'admin/build/menu/item/add', - 'title' => t('Add menu item'), - 'callback' => 'drupal_get_form', - 'callback arguments' => array('menu_edit_item_form', 'add'), - 'access' => user_access('administer menu'), - 'type' => MENU_LOCAL_TASK); - $items[] = array('path' => 'admin/build/menu/item/edit', - 'title' => t('Edit menu item'), - 'callback' => 'drupal_get_form', - 'callback arguments' => array('menu_edit_item_form', 'edit'), - 'access' => user_access('administer menu'), - 'type' => MENU_CALLBACK); - $items[] = array('path' => 'admin/build/menu/item/reset', - 'title' => t('Reset menu item'), - 'callback' => 'drupal_get_form', - 'callback arguments' => array('menu_reset_item'), - 'access' => user_access('administer menu'), - 'type' => MENU_CALLBACK); - $items[] = array('path' => 'admin/build/menu/item/disable', - 'title' => t('Disable menu item'), - 'callback' => 'menu_disable_item', - 'access' => user_access('administer menu'), - 'type' => MENU_CALLBACK); - $items[] = array('path' => 'admin/build/menu/item/delete', - 'title' => t('Delete menu item'), - 'callback' => 'drupal_get_form', - 'callback arguments' => array('menu_item_delete_form'), - 'access' => user_access('administer menu'), - 'type' => MENU_CALLBACK); - + $items['admin/build/menu'] = array( + 'title' => t('Menus'), + 'description' => t("Control your site's navigation menu, primary links and secondary links. as well as rename and reorganize menu items."), + 'page callback' => 'menu_overview', + 'access callback' => 'user_access', + 'access arguments' => array('administer menu'), + ); + $items['admin/build/menu/list'] = array( + 'title' => t('List'), + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -10, + ); + $items['admin/build/menu/item/disable'] = array( + 'title' => t('Disable menu item'), + 'page callback' => 'menu_flip_item', + 'page arguments' => array('0'), + 'type' => MENU_CALLBACK, + ); + $items['admin/build/menu/item/enable'] = array( + 'title' => t('Enable menu item'), + 'page callback' => 'menu_flip_item', + 'page arguments' => array('1'), + 'type' => MENU_CALLBACK, + ); + $items['admin/build/menu/item/add'] = array( + 'title' => t('Add menu item'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('menu_edit_item_form', 'add'), + 'parent' => 'admin/build/menu', + 'type' => MENU_LOCAL_TASK); + $items['admin/build/menu/item/edit'] = array( + 'title' => t('Edit menu item'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('menu_edit_item_form', 'edit'), + 'type' => MENU_CALLBACK); + $items['admin/build/menu/item/reset'] = array( + 'title' => t('Reset menu item'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('menu_reset_item'), + 'type' => MENU_CALLBACK); + $items['admin/build/menu/item/delete'] = array( + 'title' => t('Delete menu item'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('menu_item_delete_form'), + 'type' => MENU_CALLBACK); + $result = db_query('SELECT * FROM {menu_edit} WHERE admin = 1'); + while ($item = db_fetch_array($result)) { + $item['access callback'] = 1; + $item['access inherited'] = TRUE; + $items[$item['path']] = $item; + } + return $items; +/* $items[] = array('path' => 'admin/build/menu/menu/add', 'title' => t('Add menu'), 'callback' => 'drupal_get_form', @@ -105,15 +121,417 @@ function menu_menu() { 'type' => MENU_LOCAL_TASK, 'weight' => 5, ); +*/ +} + +/** + * Implementation of hook_menu_alter. + */ +function menu_menu_alter(&$menu, $phase) { + if ($phase == MENU_ALTER_PREPROCESSED) { + $result = db_query('SELECT * FROM {menu_edit} me WHERE admin = 0'); + while ($item = db_fetch_array($result)) { + $menu[$item['path']] = $item + $menu[$item['path']]; + } } +} - return $items; +/** + * Menu callback which displays every menu element accessible to the current + * user and the relevant operations. + */ +function menu_overview() { + $header = array(t('Menu item'), t('Expanded'), array('data' => t('Operations'), 'colspan' => '3')); + $result = db_query('SELECT m.*, me.disabled FROM {menu} m LEFT JOIN {menu_edit} me ON m.path = me.path WHERE visible = 1 OR (disabled = 1 AND admin = 0) ORDER BY mleft'); + $map = arg(); + $rows = array(); + while ($item = db_fetch_object($result)) { + _menu_translate($item, $map, MENU_RENDER_LINK); + if (!$item->access) { + continue; + } + $title = str_repeat(' ', $item->depth - 1) . ($item->depth > 1 ? '- ' : ''); + $title .= l($item->title, $item->path, (array)$item); + // Populate the operations field. + $operations = array(); + // Set the edit column. + $operations[] = array('data' => l(t('edit'), 'admin/build/menu/item/edit/'. $item->mid)); + if ($item->disabled) { + $title .= ' ('. t('disabled') .')'; + $class = 'menu-disabled'; + $operations[] = array('data' => l(t('enable'), 'admin/build/menu/item/enable/'. $item->mid)); + } + else { + $class = 'menu-enabled'; + $operations[] = array('data' => l(t('disable'), 'admin/build/menu/item/disable/'. $item->mid)); + } + // Set the reset column. + if ($item->type & MENU_CREATED_BY_ADMIN) { + $operations[] = array('data' => l(t('delete'), 'admin/build/menu/item/delete/'. $item->mid)); + } + else if ($item->type & MENU_MODIFIED_BY_ADMIN) { + $operations[] = array('data' => l(t('reset'), 'admin/build/menu/item/reset/'. $item->mid)); + } + else { + $operations[] = array('data' => ''); + } + $row = array( + array('data' => $title, 'class' => $class), + array('data' => ($item->has_children ? (($item->type & MENU_EXPANDED) ? t('Yes') : t('No')) : ''), 'class' => $class), + ); + foreach ($operations as $operation) { + $operation['class'] = $class; + $row[] = $operation; + } + $rows[] = $row; + } + return theme('table', $header, $rows); +} + +/** + * Menu callback; enable/disable a menu item. + * + * @param $visible + * 0 to remove from the menu tree. 1 to make the item and its children + * reappear in menu tree. + * @param $mid + * mid of the menu item. + * @param $path + * Optional. Path of the menu item. Only considered if mid is NULL. + */ +function menu_flip_item($visible, $mid, $path = NULL) { + if (isset($mid)) { + $parent = menu_get_item_by_mid($mid); + } + elseif (isset($path)) { + $parent = menu_get_item($path); + } + if (isset($parent) && $parent->access) { + $result = db_query('SELECT * FROM {menu} WHERE %d <= mleft AND mright <= %d', $parent->mleft, $parent->mright); + while ($item = db_fetch_object($result)) { + $update_result = db_query("UPDATE {menu_edit} SET disabled = %d WHERE path = '%s'", !$visible, $item->path); + if (!db_affected_rows($update_result)) { + db_query("INSERT INTO {menu_edit} (parent, path, title, description, weight, type, admin, disabled) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d, %d)", $item->parent, $item->path, $item->title, $item->description, 0, $item->type, 0, !$visible); + } + } + menu_rebuild(); + if (isset($mid)) { + drupal_set_message($visible ? t('The menu item has been enabled.') : t('The menu item has been disabled.')); + drupal_goto('admin/build/menu'); + } + } +} + +/** + * Present the menu item editing form. + */ +function menu_edit_item_form($type, $mid = 0) { + if ($type == 'edit') { + if (!($item = menu_get_item_by_mid($mid))) { + drupal_not_found(); + return; + } + } + else { + // This is an add form. + // The mid argument (if set) will be the default pid to use. + $item = (object)array('mid' => 0, 'pid' => $mid ? $mid : 0, 'weight' => 0, 'type' => MENU_CUSTOM_ITEM, 'title' => '', 'description' => '', 'path' => ''); + } + + $form['title'] = array('#type' => 'textfield', + '#title' => t('Title'), + '#default_value' => $item->title, + '#description' => t('The name of the menu item.'), + '#required' => TRUE, + ); + $form['description'] = array( + '#type' => 'textfield', + '#title' => t('Description'), + '#default_value' => $item->description, + '#description' => t('The description displayed when hovering over a menu item.'), + ); + + if ($item->type & MENU_CREATED_BY_ADMIN) { + $form['path'] = array( + '#type' => 'textfield', + '#title' => t('Path'), + '#default_value' => $item->path, + '#description' => t('The path this menu item links to. This can be an internal Drupal path such as %add-node or an external URL such as %drupal. Enter %front to link to the front page.', array('%front' => '<front>', '%add-node' => 'node/add', '%drupal' => 'http://drupal.org')), + '#required' => TRUE, + ); + } + else { + $form['_path'] = array( + '#type' => 'item', + '#title' => t('Path'), + '#description' => l($item->path, $item->link_path, (array)$item), + ); + } + $form['original_path'] = array('#type' => 'value', '#value' => $item->path); + + $form['expanded'] = array( + '#type' => 'checkbox', + '#title' => t('Expanded'), + '#default_value' => $item->type & MENU_EXPANDED ? 1 : 0, + '#description' => t('If selected and this menu item has children, the menu will always appear expanded.'), + ); + + // Generate a list of possible parents (not including this item or descendants). + $options = menu_parent_options($item->mid); + $form['pid'] = array( + '#type' => 'select', + '#title' => t('Parent item'), + '#default_value' => $item->pid, + '#options' => $options, + ); + $form['weight'] = array( + '#type' => 'weight', + '#title' => t('Weight'), + '#default_value' => isset($item->weight) ? $item->weight : 0, + '#description' => t('Optional. In the menu, the heavier items will sink and the lighter items will be positioned nearer the top.'), + ); + + // Always enable menu items (but not menus) when editing them. + if (!($item->type & MENU_IS_ROOT)) { + $item->type |= MENU_VISIBLE_IN_TREE | MENU_VISIBLE_IN_BREADCRUMB; + } + + $form['type'] = array('#type' => 'value', '#value' => $item->type); + $form['submit'] = array('#type' => 'submit', '#value' => t('Submit')); + + return $form; +} + +function menu_edit_item_form_validate($form_id, $form_values) { + if (isset($form_values['path'])) { + $path = $form_values['path']; + // Skip external links. + $colonpos = strpos($path, ':'); + if ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos))) { + return; + } + $item = menu_get_item($path); + if (!$item || !$item->access) { + form_set_error('path', t('This path is either invalid or you do not have access to it')); + } + elseif ($path != $form_values['original_path'] && $item->path == $path) { + form_set_error('path', t('There is already a menu item pointing to this path.')); + } + } +} +/** + * Process menu and menu item add/edit form submissions. + */ +function menu_edit_item_form_submit($form_id, $form_values) { + menu_edit_item_save($form_values); + return 'admin/build/menu'; +} + +/** + * Return a list of menu items that are valid possible parents for the + * given menu item. The list excludes the given item and its children. + * + * @param $mid + * The menu item id for which to generate a list of parents. + * If $mid == 0 then the complete tree is returned. + * @param $pid + * The menu item id of the menu item at which to start the tree. + * If $pid > 0 then this item will be included in the tree. + * @param $depth + * The current depth in the tree - used when recursing to indent the tree. + * @return + * An array of menu titles keyed on the mid. + */ +function menu_parent_options($mid, $pid = 0, $depth = 0) { + $options = array(0 => t('Root')); + // Exclude $mid and its children from the list unless $mid is 0. + if ($mid && $mid == $pid) { + return $options; + } + $sql = 'SELECT m.*, me.disabled FROM {menu} m LEFT JOIN {menu_edit} me ON m.path = me.path WHERE (m.visible = 1 OR (me.disabled = 1 AND me.admin = 0))'; + if (!$mid) { + $params = array(); + } + elseif ($item = menu_get_item_by_mid($mid)) { + $sql .=' AND (mleft < %d OR %d < mright)'; + $params = array($item->mleft, $item->mright); + } + else { + return $options; + } + if ($parent_item = menu_get_item_by_mid($pid)) { + $sql .= ' AND %d <= mleft AND %d <= mright'; + $params[] = $parent_item->mleft; + $params[] = $parent_item->mright; + } + $sql .= ' ORDER BY mleft'; + $result = db_query($sql, $params); + $map = arg(); + + while ($item = db_fetch_object($result)) { + _menu_translate($item, $map, MENU_RENDER_LINK); + $title = str_repeat('--', $item->depth) .' '. $item->title; + if ($item->disabled) { + $title .= ' ('. t('disabled') .')'; + } + $options[$item->mid] = $title; + } + return $options; +} + +/** + * Save changes to a menu item into the database. + * + * @return mid + */ +function menu_edit_item_save($edit) { + if (isset($edit['expanded'])) { + if ($edit['expanded']) { + $edit['type'] |= MENU_EXPANDED; + } + else { + $edit['type'] &= ~MENU_EXPANDED; + } + } + + $edit['type'] = $edit['type'] | MENU_MODIFIED_BY_ADMIN; + + $parent = $edit['pid'] ? db_result(db_query('SELECT path FROM {menu} WHERE mid = %d', $edit['pid'])) : ''; + $t_args = array('%title' => $edit['title']); + if (!empty($edit['original_path']) && db_num_rows(db_query("SELECT * FROM {menu_edit} WHERE path='%s'", $edit['original_path']))) { + db_query("UPDATE {menu_edit} SET parent = '%s', title = '%s', description = '%s', weight = %d, type = %d, path = '%s' WHERE path = '%s'", $parent, $edit['title'], $edit['description'], $edit['weight'], $edit['type'], isset($edit['path']) ? $edit['path'] : $edit['original_path'], $edit['original_path']); + } + else { + db_query("INSERT INTO {menu_edit} (parent, path, title, description, weight, type, admin) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $parent, isset($edit['path']) ? $edit['path'] : $edit['original_path'], $edit['title'], $edit['description'], $edit['weight'], $edit['type'], isset($edit['path'])); + } + watchdog('menu', t('Saved menu item %title.', $t_args), WATCHDOG_NOTICE, l(t('view'), 'admin/build/menu')); + drupal_set_message(t('The menu item %title has been saved.', $t_args)); + menu_rebuild(); +} + +/** + * Remove the menu item. + */ +function menu_node_form_delete($node) { + menu_delete_item(array('path' => 'node/'. $node->nid)); +} + +/** + * Menu callback; handle the adding/editing of a new menu. + */ +function menu_edit_menu_form($type, $mid = 0) { + if ($type == 'edit') { + if (!$item = menu_get_item_by_mid($mid)) { + drupal_not_found(); + return; + } + } + else { + $item = array('mid' => 0, 'pid' => 0, 'path' => '', 'weight' => 0, 'type' => MENU_CUSTOM_MENU); + } + $form['title'] = array('#type' => 'textfield', + '#title' => t('Title'), + '#default_value' => $item['title'], + '#description' => t('The name of the menu.'), + '#required' => TRUE, + ); + $form['mid'] = array('#type' => 'value', '#value' => $item['mid']); + $form['pid'] = array('#type' => 'value', '#value' => $item['pid']); + $form['path'] = array('#type' => 'value', '#value' => $item['path']); + $form['weight'] = array('#type' => 'value', '#value' => $item['weight']); + $form['type'] = array('#type' => 'value', '#value' => $item['type']); + $form['submit'] = array('#type' => 'submit', '#value' => t('Submit')); + // Reuse the submit function of menu_edit_item_form. + $form['#submit']['menu_edit_item_form_submit'] = array(); + $form['#validate']['menu_edit_item_form_validate'] = array(); + $form['#theme'] = 'menu_edit_item_form'; + + return $form; +} + +/** + * Menu callback; delete a single custom item. + */ +function menu_item_delete_form($mid) { + if (!($menu = db_fetch_object(db_query('SELECT type, path, title FROM {menu} WHERE mid = %d', $mid)))) { + drupal_not_found(); + return; + } + + $form['path'] = array('#type' => 'value', '#value' => $menu->path); + $form['type'] = array('#type' => 'value', '#value' => $menu->type); + $form['title'] = array('#type' => 'value', '#value' => $menu->title); + + if ($menu->type & MENU_IS_ROOT) { + $message = t('Are you sure you want to delete the menu %item?', array('%item' => $menu->title)); + } + else { + $message = t('Are you sure you want to delete the custom menu item %item?', array('%item' => $menu->title)); + } + + return confirm_form($form, $message, 'admin/build/menu', t('This action cannot be undone.'), t('Delete')); +} + +/** + * Process menu delete form submissions. + */ +function menu_item_delete_form_submit($form_id, $form_values) { + menu_delete_item($form_values['path']); + + $t_args = array('%title' => $form_values['title']); + if ($form_values['type'] & MENU_IS_ROOT) { + drupal_set_message(t('The menu %title has been deleted.', $t_args)); + watchdog('menu', t('Deleted menu %title.', $t_args), WATCHDOG_NOTICE); + } + else { + drupal_set_message(t('The menu item %title has been deleted.', $t_args)); + watchdog('menu', t('Deleted menu item %title.', $t_args), WATCHDOG_NOTICE); + } + + return 'admin/build/menu'; } /** + * Menu callback; reset a single modified item. + */ +function menu_reset_item($mid) { + if (isset($mid) && $item = db_fetch_object(db_query('SELECT path, title FROM {menu} WHERE mid = %d', $mid))) { + $form['mid'] = array('#type' => 'value', '#value' => $item->path); + return confirm_form($form, t('Are you sure you want to reset the item %item to its default values?', array('%item' => $item->title)), 'admin/build/menu', t('Any customizations will be lost. This action cannot be undone.'), t('Reset')); + } + else { + drupal_not_found(); + } +} + +/** + * Process menu reset item form submissions. + */ +function menu_reset_item_submit($form_id, $form_values) { + menu_delete_item($form_values['mid']); + drupal_set_message(t('The menu item was reset to its default settings.')); + + return 'admin/build/menu'; +} + +/** + * Delete a menu item from the database. If $item['mid'] is specified, then + * this is used to find the existing item; otherwise, $item['path'] is used. + * + * @param $item + * The path to the menu item to be deleted. + */ +function menu_delete_item($path) { + db_query("DELETE FROM {menu_edit} WHERE path = '%s'", $path); + menu_rebuild(); +} + +// Conversion ends here. + +/** * Implementation of hook_block(). */ -function menu_block($op = 'list', $delta = 0) { +function _menu_block($op = 'list', $delta = 0) { if ($op == 'list') { $blocks = array(); $root_menus = menu_get_root_menus(); @@ -136,7 +554,7 @@ function menu_block($op = 'list', $delta = 0) { /** * Implementation of hook_nodeapi(). */ -function menu_nodeapi(&$node, $op) { +function _menu_nodeapi(&$node, $op) { if (user_access('administer menu')) { switch ($op) { @@ -162,17 +580,10 @@ function menu_nodeapi(&$node, $op) { } /** - * Implementation of hook_perm(). - */ -function menu_perm() { - return array('administer menu'); -} - -/** * Implementation of hook_form_alter(). * Add menu item fields to the node form. */ -function menu_form_alter(&$form, $form_id) { +function _menu_form_alter(&$form, $form_id) { if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) { $item = array(); if ($form['nid']['#value'] > 0) { @@ -299,304 +710,9 @@ function menu_configure() { } /** - * Menu callback; handle the adding/editing of a new menu. - */ -function menu_edit_menu_form($type, $mid = 0) { - if ($type == 'edit') { - if (!($item = db_fetch_array(db_query('SELECT * FROM {menu} WHERE mid = %d', $mid)))) { - drupal_not_found(); - return; - } - } - else { - $item = array('mid' => 0, 'pid' => 0, 'path' => '', 'weight' => 0, 'type' => MENU_CUSTOM_MENU); - } - $form['title'] = array('#type' => 'textfield', - '#title' => t('Title'), - '#default_value' => $item['title'], - '#description' => t('The name of the menu.'), - '#required' => TRUE, - ); - $form['mid'] = array('#type' => 'value', '#value' => $item['mid']); - $form['pid'] = array('#type' => 'value', '#value' => $item['pid']); - $form['path'] = array('#type' => 'value', '#value' => $item['path']); - $form['weight'] = array('#type' => 'value', '#value' => $item['weight']); - $form['type'] = array('#type' => 'value', '#value' => $item['type']); - $form['submit'] = array('#type' => 'submit', '#value' => t('Submit')); - // Reuse the submit function of menu_edit_item_form. - $form['#submit']['menu_edit_item_form_submit'] = array(); - $form['#validate']['menu_edit_item_form_validate'] = array(); - $form['#theme'] = 'menu_edit_item_form'; - - return $form; -} - -/** - * Present the menu item editing form. - */ -function menu_edit_item_form($type, $mid = 0) { - if ($type == 'edit') { - if (!($item = db_fetch_array(db_query('SELECT * FROM {menu} WHERE mid = %d', $mid)))) { - drupal_not_found(); - return; - } - } - else { - // This is an add form. - // The mid argument (if set) will be the default pid to use. - // Otherwise, we default to the "Navigation" menu (pid #1). - $default_pid = $mid ? $mid : 1; - $item = array('mid' => 0, 'pid' => $default_pid, 'weight' => 0, 'type' => MENU_CUSTOM_ITEM); - } - - $form['title'] = array('#type' => 'textfield', - '#title' => t('Title'), - '#default_value' => $item['title'], - '#description' => t('The name of the menu item.'), - '#required' => TRUE, - ); - $form['description'] = array('#type' => 'textfield', - '#title' => t('Description'), - '#default_value' => $item['description'], - '#description' => t('The description displayed when hovering over a menu item.'), - ); - - if ($item['type'] & MENU_CREATED_BY_ADMIN) { - $form['path'] = array('#type' => 'textfield', - '#title' => t('Path'), - '#default_value' => $item['path'], - '#description' => t('The path this menu item links to. This can be an internal Drupal path such as %add-node or an external URL such as %drupal. Enter %front to link to the front page.', array('%front' => '<front>', '%add-node' => 'node/add', '%drupal' => 'http://drupal.org')), - '#required' => TRUE, - ); - } - else { - $form['_path'] = array('#type' => 'item', - '#title' => t('Path'), - '#description' => l($item['path'], $item['path']), - ); - $form['path'] = array('#type' => 'value', '#value' => $item['path']); - } - - $expanded = $item['type'] & MENU_EXPANDED ? 1 : 0; - $form['expanded'] = array('#type' => 'checkbox', - '#title' => t('Expanded'), - '#default_value' => $expanded, - '#description' => t('If selected and this menu item has children, the menu will always appear expanded.'), - ); - - // Generate a list of possible parents (not including this item or descendants). - $options = menu_parent_options($item['mid']); - $form['pid'] = array('#type' => 'select', - '#title' => t('Parent item'), - '#default_value' => $item['pid'], - '#options' => $options, - ); - $form['weight'] = array('#type' => 'weight', - '#title' => t('Weight'), - '#default_value' => $item['weight'], - '#description' => t('Optional. In the menu, the heavier items will sink and the lighter items will be positioned nearer the top.'), - ); - - // Always enable menu items (but not menus) when editing them. - if (!($item['type'] & MENU_IS_ROOT)) { - $item['type'] |= MENU_VISIBLE_IN_TREE | MENU_VISIBLE_IN_BREADCRUMB; - } - - $form['type'] = array('#type' => 'value', '#value' => $item['type']); - $form['mid'] = array('#type' => 'value', '#value' => $item['mid']); - $form['submit'] = array('#type' => 'submit', '#value' => t('Submit')); - - return $form; -} - -/** - * Process menu and menu item add/edit form submissions. - */ -function menu_edit_item_form_submit($form_id, $form_values) { - menu_edit_item_save($form_values); - return 'admin/build/menu'; -} - -/** - * Menu callback; delete a single custom item. - */ -function menu_item_delete_form($mid) { - if (!($menu = db_fetch_object(db_query('SELECT type, title FROM {menu} WHERE mid = %d', $mid)))) { - drupal_not_found(); - return; - } - - $form['mid'] = array('#type' => 'value', '#value' => $mid); - $form['type'] = array('#type' => 'value', '#value' => $menu->type); - $form['title'] = array('#type' => 'value', '#value' => $menu->title); - - if ($menu->type & MENU_IS_ROOT) { - $message = t('Are you sure you want to delete the menu %item?', array('%item' => $menu->title)); - } - else { - $message = t('Are you sure you want to delete the custom menu item %item?', array('%item' => $menu->title)); - } - - return confirm_form($form, $message, 'admin/build/menu', t('This action cannot be undone.'), t('Delete')); -} - -/** - * Process menu delete form submissions. - */ -function menu_item_delete_form_submit($form_id, $form_values) { - menu_delete_item($form_values['mid']); - - $t_args = array('%title' => $form_values['title']); - if ($form_values['type'] & MENU_IS_ROOT) { - drupal_set_message(t('The menu %title has been deleted.', $t_args)); - watchdog('menu', t('Deleted menu %title.', $t_args), WATCHDOG_NOTICE); - } - else { - drupal_set_message(t('The menu item %title has been deleted.', $t_args)); - watchdog('menu', t('Deleted menu item %title.', $t_args), WATCHDOG_NOTICE); - } - - return 'admin/build/menu'; -} - -/** - * Menu callback; reset a single modified item. - */ -function menu_reset_item($mid) { - if (isset($mid) && $title = db_result(db_query('SELECT title FROM {menu} WHERE mid = %d', $mid))) { - $form['mid'] = array('#type' => 'value', '#value' => $mid); - return confirm_form($form, t('Are you sure you want to reset the item %item to its default values?', array('%item' => $title)), 'admin/build/menu', t('Any customizations will be lost. This action cannot be undone.'), t('Reset')); - } - else { - drupal_not_found(); - } -} - -/** - * Process menu reset item form submissions. - */ -function menu_reset_item_submit($form_id, $form_values) { - menu_delete_item($form_values['mid']); - drupal_set_message(t('The menu item was reset to its default settings.')); - - return 'admin/build/menu'; -} - -/** - * Menu callback; hide a menu item. - */ -function menu_disable_item($mid) { - $item = menu_get_item($mid); - $type = $item['type']; - $type &= ~MENU_VISIBLE_IN_TREE; - $type &= ~MENU_VISIBLE_IN_BREADCRUMB; - $type |= MENU_MODIFIED_BY_ADMIN; - db_query('UPDATE {menu} SET type = %d WHERE mid = %d', $type, $mid); - drupal_set_message(t('The menu item has been disabled.')); - drupal_goto('admin/build/menu'); -} - -/** - * Menu callback; present the main menu management page. - */ -function menu_overview() { - menu_rebuild(); - - return menu_overview_tree(); -} - -/** - * Save changes to a menu item into the database. - * - * @return mid - */ -function menu_edit_item_save($edit) { - if (isset($edit['expanded'])) { - if ($edit['expanded']) { - $edit['type'] |= MENU_EXPANDED; - } - else { - $edit['type'] &= ~MENU_EXPANDED; - } - } - - $edit['type'] = $edit['type'] | MENU_MODIFIED_BY_ADMIN; - - $status = menu_save_item($edit); - - $t_args = array('%title' => $edit['title']); - if ($status == SAVED_UPDATED) { - drupal_set_message(t('The menu item %title has been updated.', $t_args)); - } - elseif ($status == SAVED_NEW) { - drupal_set_message(t('The menu item %title has been added.', $t_args)); - watchdog('menu', t('Added menu item %title.', $t_args), WATCHDOG_NOTICE, l(t('view'), 'admin/build/menu')); - } - return $edit['mid']; -} - -/** - * Save a menu item to the database. - * - * @param $item - * The menu item to be saved. This is passed by reference, so that the newly - * generated $item['mid'] can be accessed after an insert takes place. - * - * @return $status - * The operation that was performed in saving. Either SAVED_NEW (if a new - * menu item was created), or SAVED_UPDATED (if an existing menu item was - * updated). - */ -function menu_save_item(&$item) { - $existing_item = NULL; - - // Check that the item already exists in the menu tree, if $item['mid'] is - // specified. - if (isset($item['mid'])) { - $existing_item = menu_get_item($item['mid']); - } - - if ($item['mid'] && !empty($existing_item)) { - db_query("UPDATE {menu} SET pid = %d, path = '%s', title = '%s', description = '%s', weight = %d, type = %d WHERE mid = %d", $item['pid'], $item['path'], $item['title'], $item['description'], $item['weight'], $item['type'], $item['mid']); - return SAVED_UPDATED; - } - else { - $item['mid'] = db_next_id('{menu}_mid'); - // Check explicitly for mid <= 2. If the database was improperly prefixed, - // this would cause a nasty infinite loop or duplicate mid errors. - // TODO: have automatic prefixing through an installer to prevent this. - while ($item['mid'] <= 2) { - $item['mid'] = db_next_id('{menu}_mid'); - } - db_query("INSERT INTO {menu} (mid, pid, path, title, description, weight, type) VALUES (%d, %d, '%s', '%s', '%s', %d, %d)", $item['mid'], $item['pid'], $item['path'], $item['title'], $item['description'], $item['weight'], $item['type']); - return SAVED_NEW; - } -} - -/** - * Delete a menu item from the database. If $item['mid'] is specified, then - * this is used to find the existing item; otherwise, $item['path'] is used. - * - * @param $item - * The menu item to be deleted. - */ -function menu_delete_item($item) { - if (!is_array($item)) { - $item = array('mid' => $item); - } - - if ($item['mid']) { - db_query('DELETE FROM {menu} WHERE mid = %d', $item['mid']); - } - elseif ($item['path']) { - db_query("DELETE FROM {menu} WHERE path = '%s'", $item['path']); - } -} - -/** * Present the menu tree, rendered along with links to edit menu items. */ -function menu_overview_tree() { +function _menu_overview_tree() { $menu = menu_get_menu(); $root_menus = menu_get_root_menus(); $header = array(t('Menu item'), t('Expanded'), array('data' => t('Operations'), 'colspan' => '3')); @@ -621,152 +737,3 @@ function menu_overview_tree() { } return $output; } - -function menu_overview_tree_rows($pid = 0, $depth = 0) { - $parent_item = menu_get_item($pid); - $rows = array(); - - if (isset($parent_item) && isset($parent_item['children'])) { - usort($parent_item['children'], '_menu_sort'); - foreach ($parent_item['children'] as $mid) { - $item = menu_get_item($mid); - // Populate the title field. - $title = ''; - if ($pid == 0) { - // Top-level items are menu names, and don't have an associated path. - $title .= check_plain($item['title']); - } - else { - $title .= l($item['title'], $item['path']); - } - if ($depth > 0) { - $title = '- '. $title; - } - for ($i = 1; $i < $depth; $i++) { - $title = ' '. $title; - } - - // Populate the operations field. - $operations = array(); - if (!($item['type'] & MENU_MODIFIABLE_BY_ADMIN)) { - $operations[] = array('data' => t('locked'), 'colspan' => '3', 'align' => 'center'); - } - else { - // Set the edit column. - if ($item['type'] & (MENU_VISIBLE_IN_TREE | MENU_VISIBLE_IF_HAS_CHILDREN)) { - $operations[] = array('data' => l(t('edit'), 'admin/build/menu/item/edit/'. $mid)); - } - else { - $operations[] = array('data' => ''); - } - - // Set the disable column. - if ($item['type'] & (MENU_IS_ROOT | MENU_VISIBLE_IF_HAS_CHILDREN)) { - // Disabling entire menus is done from block admin page. - // MENU_VISIBLE_IF_HAS_CHILDREN menus are always enabled so hide this operation. - $operations[] = array('data' => ''); - } - else if ($item['type'] & MENU_VISIBLE_IN_TREE) { - $operations[] = array('data' => l(t('disable'), 'admin/build/menu/item/disable/'. $mid)); - } - else { - $operations[] = array('data' => l(t('enable'), 'admin/build/menu/item/edit/'. $mid)); - } - - // Set the reset column. - if ($item['type'] & MENU_CREATED_BY_ADMIN) { - $operations[] = array('data' => l(t('delete'), 'admin/build/menu/item/delete/'. $mid)); - } - else if ($item['type'] & MENU_MODIFIED_BY_ADMIN) { - $operations[] = array('data' => l(t('reset'), 'admin/build/menu/item/reset/'. $mid)); - } - else { - $operations[] = array('data' => ''); - } - } - - // Call out disabled items. - if ($item['type'] & (MENU_VISIBLE_IN_TREE | MENU_VISIBLE_IF_HAS_CHILDREN)) { - $class = 'menu-enabled'; - } - else { - $title .= ' ('. t('disabled') .')'; - $class = 'menu-disabled'; - } - - if ($item['type'] & (MENU_MODIFIABLE_BY_ADMIN | MENU_VISIBLE_IN_TREE)) { - $row = array(array('data' => $title, 'class' => $class), array('data' => ($item['children'] ? (($item['type'] & MENU_EXPANDED) ? t('Yes') : t('No')) : ''), 'class' => $class)); - foreach ($operations as $operation) { - $operation['class'] = $class; - $row[] = $operation; - } - $rows[] = $row; - $rows = array_merge($rows, menu_overview_tree_rows($mid, $depth + 1)); - } - else { - // Skip items that are hidden and locked; admins will never care about them. - $rows = array_merge($rows, menu_overview_tree_rows($mid, $depth)); - } - } - } - - return $rows; -} - -/** - * Return a list of menu items that are valid possible parents for the - * given menu item. The list excludes the given item and its children. - * - * @param $mid - * The menu item id for which to generate a list of parents. - * If $mid == 0 then the complete tree is returned. - * @param $pid - * The menu item id of the menu item at which to start the tree. - * If $pid > 0 then this item will be included in the tree. - * @param $depth - * The current depth in the tree - used when recursing to indent the tree. - * @return - * An array of menu titles keyed on the mid. - */ -function menu_parent_options($mid, $pid = 0, $depth = 0) { - $options = array(); - - if (!($parent_item = menu_get_item($pid))) { - return $options; - } - - // Exclude $mid and its children from the list unless $mid is 0. - if ($mid && $mid == $pid) { - return $options; - } - - // Add the current $pid to the list. - if ($pid > 0 && ($parent_item['type'] & (MENU_MODIFIABLE_BY_ADMIN | MENU_IS_ROOT))) { - $title = ' '. $parent_item['title']; - for ($i = 0; $i < $depth; $i++) { - $title = '--'. $title; - } - if (!($parent_item['type'] & MENU_VISIBLE_IN_TREE)) { - $title .= ' ('. t('disabled') .')'; - } - $options[$pid] = $title; - $depth ++; - } - - // Add children of $pid to the list recursively. - if (isset($parent_item['children'])) { - usort($parent_item['children'], '_menu_sort'); - foreach ($parent_item['children'] as $child) { - $options += menu_parent_options($mid, $child, $depth); - } - } - - return $options; -} - -/** - * Remove the menu item. - */ -function menu_node_form_delete($node) { - menu_delete_item(array('path' => 'node/'. $node->nid)); -} diff --git a/modules/node/node.module b/modules/node/node.module index 88284bb6d..19cb9b232 100644 --- a/modules/node/node.module +++ b/modules/node/node.module @@ -527,7 +527,7 @@ function node_load($param = array(), $revision = NULL, $reset = NULL) { $node = db_fetch_object(db_query('SELECT n.nid, n.vid, n.type, n.status, n.created, n.changed, n.comment, n.promote, n.sticky, r.timestamp AS revision_timestamp, r.title, r.body, r.teaser, r.log, r.format, u.uid, u.name, u.picture, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.vid = n.vid WHERE '. $cond, $arguments)); } - if ($node->nid) { + if ($node && $node->nid) { // Call the node specific callback (if any) and piggy-back the // results to the node or overwrite some values. if ($extra = node_invoke($node, 'load')) { diff --git a/modules/system/system.module b/modules/system/system.module index bbad3def2..02fc04681 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -378,7 +378,7 @@ function system_main_admin_page($arg = NULL) { function system_admin_menu_block($item) { $map = arg(NULL); $content = array(); - $result = db_query('SELECT * FROM {menu} WHERE depth = %d AND %d < mleft AND mright < %d ORDER BY mleft', $item->depth + 1, $item->mleft, $item->mright); + $result = db_query('SELECT * FROM {menu} WHERE depth = %d AND %d < mleft AND mright < %d AND visible = 1 ORDER BY mleft', $item->depth + 1, $item->mleft, $item->mright); while ($item = db_fetch_object($result)) { _menu_translate($item, $map, MENU_RENDER_LINK); if (!$item->access) { |