Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.166
diff -u -p -r1.166 menu.inc
--- includes/menu.inc 16 May 2007 13:45:16 -0000 1.166
+++ includes/menu.inc 19 May 2007 02:43:06 -0000
@@ -149,11 +149,6 @@ define('MENU_SITE_OFFLINE', 4);
* @} End of "Menu status codes".
*/
-
-/**
- * @} End of "Menu operations."
- */
-
/**
* @Name Menu tree parameters
* @{
@@ -898,6 +893,25 @@ function menu_secondary_local_tasks() {
return menu_local_tasks(1);
}
+/**
+ * Returns the rendered local tasks. The default implementation renders
+ * them as tabs.
+ *
+ * @ingroup themeable
+ */
+function theme_menu_local_tasks() {
+ $output = '';
+
+ if ($primary = menu_primary_local_tasks()) {
+ $output .= "
\n";
+ }
+ if ($secondary = menu_secondary_local_tasks()) {
+ $output .= "\n";
+ }
+
+ return $output;
+}
+
function menu_set_active_menu_name($menu_name = NULL) {
static $active;
@@ -1004,32 +1018,11 @@ function menu_get_active_title() {
function menu_get_item_by_mlid($mlid) {
if ($item = db_fetch_object(db_query("SELECT * FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE mlid = %d", $mlid))) {
_menu_link_translate($item);
- if ($item->access) {
- return $item;
- }
+ return $item;
}
return FALSE;
}
-/**
- * Returns the rendered local tasks. The default implementation renders
- * them as tabs.
- *
- * @ingroup themeable
- */
-function theme_menu_local_tasks() {
- $output = '';
-
- if ($primary = menu_primary_local_tasks()) {
- $output .= "\n";
- }
- if ($secondary = menu_secondary_local_tasks()) {
- $output .= "\n";
- }
-
- return $output;
-}
-
function menu_cache_clear($menu_name = 'navigation') {
// TODO: starting stub. This will be called whenever an item is added to or
// moved from a named menu
@@ -1074,15 +1067,17 @@ function _menu_navigation_links_rebuild(
if ($item['type'] == MENU_CALLBACK || $item['type'] == MENU_SUGGESTED_ITEM) {
$item['hidden'] = $item['type'];
}
+ // Note, we set this as 'system', so that we can be sure to distinguish all
+ // the menu links generated automatically from entries in {menu_router}.
+ $item['module'] = 'system';
$item += array(
- 'menu name' => 'navigation',
+ 'menu_name' => 'navigation',
'link_title' => $item['title'],
'href' => $path,
- 'module' => 'system',
'hidden' => 0,
);
// We add nonexisting items.
- if ($item['_visible'] && !db_result(db_query("SELECT COUNT(*) FROM {menu_links} WHERE menu_name = '%s' AND href = '%s'", $item['menu name'], $item['href']))) {
+ if ($item['_visible'] && !db_result(db_query("SELECT COUNT(*) FROM {menu_links} WHERE menu_name = '%s' AND href = '%s'", $item['menu_name'], $item['href']))) {
$menu_links[$path] = $item;
$sort[$path] = $item['_number_parts'];
}
@@ -1106,7 +1101,7 @@ function _menu_navigation_links_rebuild(
* @param $item
* An array representing a menu link item. The only mandatory keys are href
* and link_title. Possible keys are
- * menu name default is navigation
+ * menu_name default is navigation
* weight default is 0
* expanded whether the item is expanded.
* options An array of options, @see l for more.
@@ -1130,7 +1125,7 @@ function menu_link_save(&$item, $_menu =
$item['_external'] = menu_path_is_external($item['href']);
// Load defaults.
$item += array(
- 'menu name' => 'navigation',
+ 'menu_name' => 'navigation',
'weight' => 0,
'link_title' => '',
'hidden' => 0,
@@ -1138,26 +1133,26 @@ function menu_link_save(&$item, $_menu =
'expanded' => 0,
'options' => empty($item['description']) ? array() : array('attributes' => array('title' => $item['description'])),
);
- $existing_item = array();
+ $menu_name = $item['menu_name'];
+ $existing_item = FALSE;
if (isset($item['mlid'])) {
$existing_item = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $item['mlid']));
}
else {
- $existing_item = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE menu_name = '%s' AND href = '%s'", $item['menu name'], $item['href']));
+ $existing_item = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE menu_name = '%s' AND href = '%s'", $menu_name, $item['href']));
}
- if (empty($existing_item)) {
+ if ($existing_item) {
$item['mlid'] = db_next_id('{menu_links}_mlid');
}
- $menu_name = $item['menu name'];
$new_path = !$existing_item || ($existing_item['href'] != $item['href']);
// Find the parent.
if (isset($item['plid'])) {
$parent = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $item['plid']));
}
- else { //
+ else {
$parent_path = $item['href'];
do {
$parent_path = substr($parent_path, 0, strrpos($parent_path, '/'));
@@ -1180,18 +1175,21 @@ function menu_link_save(&$item, $_menu =
}
else {
// Cannot add beyond the maximum depth.
- if ($parent['depth'] >= (MENU_MAX_DEPTH)) {
+ if ($item['has_children'] && $existing_item) {
+ $limit = MENU_MAX_DEPTH - menu_children_relative_depth($existing_item) - 1;
+ }
+ else {
+ $limit = MENU_MAX_DEPTH - 1;
+ }
+ if ($parent['depth'] > $limit) {
return FALSE;
}
$item['depth'] = $parent['depth'] + 1;
- _menu_parents_copy($item, $parent);
- $item['p'. $item['depth']] = $item['mlid'];
+ _menu_link_parents_set($item, $parent);
}
-
- if ($item['plid'] != $existing_item['plid']) {
-
- // TODO: UPDATE the parents of the children of the current item
- // TODO: check the has_children status of the previous parent
+ // Need to check both plid and menu_name, since plid can be 0 in any menu.
+ if ($existing_item && ($item['plid'] != $existing_item['plid'] || $menu_name != $existing_item['menu_name'])) {
+ _menu_link_move_children($item, $existing_item);
}
// Find the callback.
if (empty($item['router_path']) || $new_path) {
@@ -1213,13 +1211,13 @@ function menu_link_save(&$item, $_menu =
}
}
}
- if (!empty($existing_item)) {
+ if ($existing_item) {
db_query("UPDATE {menu_links} SET menu_name = '%s', plid = %d, href = '%s',
router_path = '%s', hidden = %d, external = %d, has_children = %d,
expanded = %d, weight = %d, depth = %d,
p1 = %d, p2 = %d, p3 = %d, p4 = %d, p5 = %d, p6 = %d,
module = '%s', link_title = '%s', options = '%s' WHERE mlid = %d",
- $item['menu name'], $item['plid'], $item['href'],
+ $item['menu_name'], $item['plid'], $item['href'],
$item['router_path'], $item['hidden'], $item['_external'], $item['has_children'],
$item['expanded'],$item['weight'], $item['depth'],
$item['p1'], $item['p2'], $item['p3'], $item['p4'], $item['p5'], $item['p6'],
@@ -1237,18 +1235,19 @@ function menu_link_save(&$item, $_menu =
%d, %d, %d,
%d, %d, %d, %d, %d, %d,
'%s', '%s', '%s')",
- $item['menu name'], $item['mlid'], $item['plid'], $item['href'],
+ $item['menu_name'], $item['mlid'], $item['plid'], $item['href'],
$item['router_path'], $item['hidden'], $item['_external'], $item['has_children'],
$item['expanded'],$item['weight'], $item['depth'],
$item['p1'], $item['p2'], $item['p3'], $item['p4'], $item['p5'], $item['p6'],
$item['module'], $item['link_title'], serialize($item['options']));
- }
-
- if ($item['plid'] && !$item['hidden']) {
- db_query("UPDATE {menu_links} SET has_children = 1 WHERE mlid = %d", $item['plid']);
+ }
+ // Check the has_children status of the parent.
+ if ($item['plid']) {
+ $parent_has_children = (bool)db_result(db_query("SELECT COUNT(*) FROM {menu_links} WHERE plid = %d AND hidden = 0", $item['plid']));
+ db_query("UPDATE {menu_links} SET has_children = %d WHERE mlid = %d", $parent_has_children, $item['plid']);
}
- // Keep track of which menus have expanded items
+ // Keep track of which menus have expanded items.
$names = array();
$result = db_query("SELECT menu_name FROM {menu_links} WHERE expanded != 0 GROUP BY menu_name");
while ($n = db_fetch_array($result)) {
@@ -1258,13 +1257,94 @@ function menu_link_save(&$item, $_menu =
return TRUE;
}
-function _menu_parents_copy(&$dest, $source, $offset = 0){
- $i = 1 + $offset;
- $depth = 0;
- for ($j = 1; $i <= MENU_MAX_DEPTH; $i++) {
- $dest['p'. $i] = $source['p'. $j];
- $j++;
- }
+/**
+ * Find the depth of an item's children relative to its depth. For example, if
+ * the item has a depth of 2, and the maximum of any child in the menu link tree
+ * is 5, the relative depth is 3.
+ *
+ * @param $item
+ * An array representing a menu link item.
+ * @return
+ * The relative depth, or zero.
+ *
+ */
+function menu_link_children_relative_depth($item) {
+ $i = 1;
+ $match = '';
+ $args[] = $item['menu_name'];
+ $p = 'p1';
+ while ($i <= MENU_MAX_DEPTH && $item[$p]) {
+ $match .= " AND $p = %d";
+ $args[] = $item[$p];
+ $p = 'p'. ++$i;
+ }
+
+ $max_depth = db_result(db_query_range("SELECT depth FROM {menu_links} WHERE menu_name = '%s'". $match ." ORDER BY depth DESC", $args, 0, 1));
+
+ return ($max_depth > $item['depth']) ? $max_depth - $item['depth'] : 0;
+}
+
+/**
+ * Update the menu name, parents (p1 - p6), and depth for the children of
+ * a menu link that's being moved in the tree and check the has_children status
+ * of the previous parent.
+ */
+function _menu_link_move_children($item, $existing_item) {
+
+ $args[] = $item['menu_name'];
+ $set = '';
+ $shift = $item['depth'] - $existing_item['depth'];
+ if ($shift < 0) {
+ $args[] = -$shift;
+ $set = ', depth = depth - %d';
+ }
+ elseif ($shift > 0) {
+ $args[] = $shift;
+ $set = ', depth = depth + %d';
+ }
+ $i = 1;
+ while ($i <= $item['depth']) {
+ $p = 'p'. $i++;
+ $set .= ", $p = %d";
+ $args[] = $item[$p];
+ }
+ $j = $existing_item['depth'] + 1;
+ while ($i <= MENU_MAX_DEPTH && $j <= MENU_MAX_DEPTH) {
+ $set .= ', p'. $i++ .' = p'. $j++;
+ }
+ while ($i <= MENU_MAX_DEPTH) {
+ $set .= ', p'. $i++ .' = 0';
+ }
+
+ $args[] = $existing_item['menu_name'];
+ $i = 1;
+ while ($i <= MENU_MAX_DEPTH && $existing_item[$p]) {
+ $p = 'p'. $i++;
+ $match .= " AND $p = %d";
+ $args[] = $existing_item[$p];
+ }
+
+ db_query("UPDATE {menu_links} SET menu_name = '%s'". $set ." WHERE menu_name = '%s'". $match, $args);
+
+ if ($existing_item['plid']) {
+ $parent_has_children = (bool)db_result(db_query("SELECT COUNT(*) FROM {menu_links} WHERE plid = %d AND hidden = 0 AND mlid != %d",$existing_item['plid'], $existing_item['mlid']));
+ db_query("UPDATE {menu_links} SET has_children = %d WHERE mlid = %d", $parent_has_children, $existing_item['plid']);
+ }
+}
+
+function _menu_link_parents_set(&$item, $parent){
+ $i = 1;
+ while ($i < $item['depth']) {
+ $p = 'p'. $i++;
+ $item[$p] = $parent[$p];
+ }
+ $p = 'p'. $i++;
+ // The parent (p1 - p6) corresponding to the depth always equals the mlid.
+ $item[$p] = $item['mlid'];
+ while ($i <= MENU_MAX_DEPTH) {
+ $p = 'p'. $i++;
+ $item[$p] = 0;
+ }
}
function _menu_router_build($callbacks) {