menu.module 24.5 KB
Newer Older
1 2 3
<?php
// $Id$

Dries's avatar
 
Dries committed
4 5 6 7 8
/**
 * @file
 * Allows administrators to customize the site navigation menu.
 */

9
/**
Dries's avatar
 
Dries committed
10
 * Implementation of hook_menu().
11
 */
Dries's avatar
 
Dries committed
12
function menu_menu($may_cache) {
Dries's avatar
 
Dries committed
13
  $items = array();
Dries's avatar
 
Dries committed
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

  if ($may_cache) {
    $items[] = array('path' => 'admin/menu', 'title' => t('menus'),
      'callback' => 'menu_overview',
      'access' => user_access('administer menu'));
    $items[] = array('path' => 'admin/menu/item/edit', 'title' => t('edit menu item'),
      'callback' => 'menu_edit_item',
      'access' => user_access('administer menu'),
      'type' => MENU_CALLBACK);
    $items[] = array('path' => 'admin/menu/item/reset', 'title' => t('reset menu item'),
      'callback' => 'menu_reset_item',
      'access' => user_access('administer menu'),
      'type' => MENU_CALLBACK);
    $items[] = array('path' => 'admin/menu/item/disable', 'title' => t('disable menu item'),
      'callback' => 'menu_disable_item',
      'access' => user_access('administer menu'),
      'type' => MENU_CALLBACK);
    $items[] = array('path' => 'admin/menu/item/delete', 'title' => t('delete menu item'),
      'callback' => 'menu_delete_item',
      'access' => user_access('administer menu'),
      'type' => MENU_CALLBACK);

    $items[] = array('path' => 'admin/menu/list', 'title' => t('list'),
      'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
    $items[] = array('path' => 'admin/menu/menu/add', 'title' => t('add menu'),
      'callback' => 'menu_add_menu',
      'access' => user_access('administer menu'),
      'type' => MENU_LOCAL_TASK);
    $items[] = array('path' => 'admin/menu/item/add', 'title' => t('add menu item'),
      'callback' => 'menu_edit_item',
      'access' => user_access('administer menu'),
      'type' => MENU_LOCAL_TASK);
    $items[] = array('path' => 'admin/menu/reset', 'title' => t('reset menus'),
      'callback' => 'menu_reset',
      'access' => user_access('administer menu'),
      'type' => MENU_LOCAL_TASK);
50 51 52 53 54

    $items[] = array('path' => 'admin/settings/menu',
      'title' => t('menus'),
      'callback' => 'menu_configure',
      'access' => user_access('administer menu'));
Dries's avatar
 
Dries committed
55
  }
Dries's avatar
 
Dries committed
56 57

  return $items;
58 59 60 61 62 63 64
}

/**
 * Implementation of hook_help().
 */
function menu_help($section) {
  switch ($section) {
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
    case 'admin/help#menu':
      $output = t('<p>The menu module allows for customization of the menus.  Menus are useful for providing navigation in your site.  The main menu for navigation is the navigation menu.  Menus appear in blocks on your site.</p>
<ul>
<li>On the administer menu page administrators can \'\'\'edit\'\'\' to change the title, description, parent or weight of the menu item. Under the \'\'\'operations\'\'\' column, click on \'\'\'enable/disable\'\'\' to toggle the menu item on or off. Menu items which are disabled are not deleted; they are merely not available for navigating the site in the sidebar menu block.  Note that the default menu items generated by the menu module cannot be deleted, only disabled.</li>
<li>Using the \'\'\'add menu\'\'\' tab submit a title for a new custom menu. Once submitted, the new menu will appear in a list toward the bottom of the administer menu page underneath the main navigation menu.</li>
<li>Use the \'\'\'add menu item\'\'\' tab to create new links in either the navigation or a custom menu. Select the parent item to place the new link within an existing menu structure. For top level menu items, choose the name of the menu in which the link is to be added.</li>
<li>To turn off the navigation menu block, administer the block page.</li>
</ul>
');
      $output .= t('<p>You can</p>
<ul>
<li>administer menus at <a href="%admin-menu"> administer &gt;&gt; menus</a>.</li>
<li>turn menus blocks on and off in the <a href="%admin-block">administration &gt;&gt; block</a>.</li>
<li>add a menu at <a href="%admin-menu-menu-add">administer &gt;&gt; menus &gt;&gt; add menu</a>.</li>
<li>add a menu item at <a href="%admin-menu-item-add">administer &gt;&gt; menus &gt;&gt; add menu item</a>.</li>
</ul>
', array('%admin-menu' => url('admin/menu'), '%admin-block' => url('admin/block'), '%admin-menu-menu-add' => url('admin/menu/menu/add'), '%admin-menu-item-add' => url('admin/menu/item/add')));
      $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="%menu">Menu page</a>.', array('%menu' => 'http://www.drupal.org/handbook/modules/menu/')) .'</p>';
      return $output;
Dries's avatar
 
Dries committed
84
    case 'admin/modules#description':
85 86
      return t('Allows administrators to customize the site navigation menu.');
    case 'admin/menu':
87
      return t('<p>Select an operation from the list to move, change, or delete a menu item.</p>');
88
    case 'admin/menu/menu/add':
89
      return t('<p>Enter the name for your new menu. Remember to enable the newly created block in the %blocks administration page.</p>', array('%blocks' => l(t('blocks'), 'admin/block')));
90
    case 'admin/menu/item/add':
91
      return t('<p>Enter the title, path, position and the weight for your new menu item.</p>');
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
    case 'admin/settings/menu':
      return t('<p>Customize the menu settings.</p>');
  }
}


/**
 * Menu callback; presents menu configuration options.
 */
function menu_configure() {
  $menu = menu_get_menu();

  $primary_options[0] = t('No primary links');
  foreach ($menu['items'][0]['children'] as $mid) {
    $primary_options[$mid] = $menu['items'][$mid]['title'];
  }

Dries's avatar
Dries committed
109
  $form['settings_links'] = array('#type' => 'fieldset', '#title' => t('Primary links settings'));
110
  $form['settings_links']['intro'] = array(
Dries's avatar
Dries committed
111 112
    '#type' => 'markup',
    '#value' => t('Primary links is a navigation system which usually (depending on your theme) appears at the top-right of the browser window. There are usually two rows of links, primary and secondary. You may control which links appear in this area by choosing a menu from which the links will be generated and then placing your links into the menu using the <a href="%menu">menu administration</a> or the \'Menu settings\' pane on each edit node form.', array('%menu' => url('admin/menu')))
113 114 115 116 117 118
  );

  $form['settings_links']['menu_primary_menu'] = array(
    '#type' => 'select',
    '#title' => t('Menu containing primary links'),
    '#default_value' => variable_get('menu_primary_menu', 0),
Dries's avatar
Dries committed
119
    '#options' => $primary_options
120 121 122 123 124
  );

  $secondary_options[0] = t('No secondary links');
  foreach ($menu['items'][0]['children'] as $mid) {
    $secondary_options[$mid] = $menu['items'][$mid]['title'];
125
  }
126 127 128 129 130 131

  $form['settings_links']['menu_secondary_menu'] = array(
    '#type' => 'select',
    '#title' => t('Menu containing secondary links'),
    '#default_value' => variable_get('menu_secondary_menu', 0),
    '#options' => $secondary_options,
Dries's avatar
Dries committed
132
    '#description' => t('If you select the same menu as primary links then secondary links will display the appropriate second level of your navigation hierarchy.')
133 134 135
  );

  return system_settings_form('menu_configure', $form);
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
}

/**
 * Implementation of hook_block().
 */
function menu_block($op = 'list', $delta = 0) {
  $menu = menu_get_menu();

  if ($op == 'list') {
    $blocks = array();
    foreach ($menu['items'][0]['children'] as $mid) {
      // Default "Navigation" block is handled by user.module.
      if ($mid != 1) {
        $blocks[$mid]['info'] = $menu['items'][$mid]['title'];
      }
    }
    return $blocks;
  }
154
  else if ($op == 'view') {
155
    $data['subject'] = $menu['items'][$delta]['title'];
156
    $data['content'] = '<div class="menu">'. theme('menu_tree', $delta) .'</div>' ;
157 158 159 160
    return $data;
  }
}

161 162 163 164 165 166 167
/**
 * Implementation of hook_nodeapi().
 */
function menu_nodeapi(&$node, $op) {

  if (user_access('administer menu')) {
    switch ($op) {
168
      case 'form':
169 170
        $edit = isset($_POST['edit']) ? $_POST['edit'] : '';
        $edit['nid'] = isset($node->nid) ? $node->nid : '';
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
        return menu_node_form($edit);
        break;

      case 'insert':
      case 'update':
        if ($node->menu['delete']) {
          menu_node_form_delete($node);
          menu_rebuild();
        }
        elseif ($node->menu['title']) {
          $node->menu['path'] = ($node->menu['path']) ? $node->menu['path'] : "node/$node->nid";
          menu_edit_item_save($node->menu);
          menu_rebuild();
        }
        break;

      case 'delete':
        menu_node_form_delete($node);
        menu_rebuild();
        break;
    }
  }
}

195 196 197 198 199 200 201 202
/**
 * Implementation of hook_perm().
 */
function menu_perm() {
  return array('administer menu');
}

/**
203
 * Menu callback; present the main menu management page.
204 205 206 207
 */
function menu_overview() {
  menu_rebuild();

Dries's avatar
 
Dries committed
208
  return menu_overview_tree();
209 210 211
}

/**
212
 * Menu callback; clear the database, resetting the menu to factory defaults.
213 214
 */
function menu_reset() {
215
  $op = isset($_POST['op']) ? $_POST['op'] : '';
216
  switch ($op) {
217
    case t('Reset all'):
218
      db_query('DELETE FROM {menu}');
219
      drupal_set_message(t('The menu items have been reset to their default settings.'));
Dries's avatar
 
Dries committed
220
      drupal_goto('admin/menu');
221 222
      break;
    default:
223 224 225 226
      return confirm_form('menu_confirm_reset', array(),
        t('Are you sure you want to reset all menu items to their default settings?'),
        'admin/menu', t('Any custom additions or changes to the menu will be lost.'),
        t('Reset all'));
227 228 229 230
  }
}

/**
231
 * Menu callback; handle the adding of a new menu.
232 233
 */
function menu_add_menu() {
234 235
  $op = isset($_POST['op']) ? $_POST['op'] : '';
  $edit = isset($_POST['edit']) ? $_POST['edit'] : '';
236 237 238 239
  $output = '';

  switch ($op) {
    case t('Submit'):
Dries's avatar
 
Dries committed
240 241 242 243 244 245
      menu_edit_item_validate($edit);
      if (!form_get_errors()) {
        menu_edit_item_save($edit);
        drupal_goto('admin/menu');
      }
      // Fall through.
246 247
    default:
      $edit['pid'] = 0;
Dries's avatar
 
Dries committed
248
      $edit['type'] = MENU_CUSTOM_MENU;
249 250 251
      $output .= menu_edit_item_form($edit);
  }

Dries's avatar
 
Dries committed
252
  return $output;
253 254 255
}

/**
256
 * Menu callback; reset a single modified item.
257 258
 */
function menu_reset_item($mid) {
259
  $op = isset($_POST['op']) ? $_POST['op'] : '';
260 261 262
  switch ($op) {
    case t('Reset'):
      db_query('DELETE FROM {menu} WHERE mid = %d', $mid);
263
      drupal_set_message(t("The menu item was reset to its default settings."));
Dries's avatar
 
Dries committed
264
      drupal_goto('admin/menu');
265 266
      break;
    default:
267
      $title = db_result(db_query('SELECT title FROM {menu} WHERE mid = %d', $mid));
268 269 270 271
      return confirm_form('menu_item_confirm_reset', array(),
        t('Are you sure you want to reset the item %item to its default values?', array('%item' => theme('placeholder', $title))),
        'admin/menu', t('Any customizations will be lost. This action cannot be undone.'),
        t('Reset'));
272 273 274 275
  }
}

/**
276
 * Menu callback; delete a single custom item.
277 278
 */
function menu_delete_item($mid) {
279
  $op = isset($_POST['op']) ? $_POST['op'] : '';
280 281 282 283 284
  $result = db_query('SELECT type, title FROM {menu} WHERE mid = %d', $mid);
  $menu = db_fetch_object($result);
  if (!$menu) {
    drupal_goto('admin/menu');
  }
285 286 287
  switch ($op) {
    case t('Delete'):
      db_query('DELETE FROM {menu} WHERE mid = %d', $mid);
288
      if ($menu->type & MENU_IS_ROOT) {
289
        drupal_set_message(t('The menu has been removed.'));
290 291
      }
      else {
292
        drupal_set_message(t('The menu item has been removed.'));
293
      }
Dries's avatar
 
Dries committed
294
      drupal_goto('admin/menu');
295 296
      break;
    default:
297
      if ($menu->type & MENU_IS_ROOT) {
298
        $message = t('Are you sure you want to delete the menu %item?', array('%item' => theme('placeholder', $menu->title)));
299 300
      }
      else {
301
        $message = t('Are you sure you want to delete the custom menu item %item?', array('%item' => theme('placeholder', $menu->title)));
302
      }
303
      return confirm_form('menu_confirm_delete', $form, $message, 'admin/menu', t('This action cannot be undone.'), t('Delete'));
304 305 306 307
  }
}

/**
308
 * Menu callback; hide a menu item.
309 310
 */
function menu_disable_item($mid) {
Dries's avatar
 
Dries committed
311 312 313 314
  $menu = menu_get_menu();
  $type = $menu['items'][$mid]['type'];
  $type &= ~MENU_VISIBLE_IN_TREE;
  $type &= ~MENU_VISIBLE_IN_BREADCRUMB;
Dries's avatar
 
Dries committed
315
  $type |= MENU_MODIFIED_BY_ADMIN;
Dries's avatar
 
Dries committed
316
  db_query('UPDATE {menu} SET type = %d WHERE mid = %d', $type, $mid);
317
  drupal_set_message(t('The menu item has been disabled.'));
Dries's avatar
 
Dries committed
318
  drupal_goto('admin/menu');
319 320 321
}

/**
322
 * Menu callback; dispatch to the appropriate menu item edit function.
323
 */
Dries's avatar
Dries committed
324
function menu_edit_item($mid = 0) {
325 326
  $op = isset($_POST['op']) ? $_POST['op'] : '';
  $edit = isset($_POST['edit']) ? $_POST['edit'] : '';
Dries's avatar
 
Dries committed
327

328 329 330 331
  $output = '';

  switch ($op) {
    case t('Submit'):
Dries's avatar
 
Dries committed
332 333 334 335 336
      menu_edit_item_validate($edit);
      if (!form_get_errors()) {
        menu_edit_item_save($edit);
        drupal_goto('admin/menu');
      }
337 338
      $output .= menu_edit_item_form($edit);
      break;
339 340 341 342 343 344 345 346
    default:
      if ($mid > 0) {
        $item = db_fetch_object(db_query('SELECT * FROM {menu} WHERE mid = %d', $mid));

        $edit['mid'] = $item->mid;
        $edit['pid'] = $item->pid;
        $edit['path'] = $item->path;
        $edit['title'] = $item->title;
Dries's avatar
 
Dries committed
347
        $edit['description'] = $item->description;
348
        $edit['weight'] = $item->weight;
Dries's avatar
 
Dries committed
349
        $edit['type'] = $item->type;
350 351 352 353
      }
      else {
        $edit['mid'] = 0; // In case a negative ID was passed in.
        $edit['pid'] = 1; // default to "Navigation" menu.
Dries's avatar
 
Dries committed
354
        $edit['type'] = MENU_CUSTOM_ITEM;
355 356 357 358
      }
      $output .= menu_edit_item_form($edit);
  }

Dries's avatar
 
Dries committed
359
  return $output;
360 361 362 363 364 365 366 367
}

/**
 * Present the menu item editing form.
 */
function menu_edit_item_form($edit) {
  $menu = menu_get_menu();

368
  $form['title'] = array('#type' => 'textfield', '#title' => t('Title'), '#default_value' => $edit['title'], '#description' => t('The name of the menu.'), '#required' => TRUE);
369 370 371

  if ($edit['pid'] == 0) {
    // Display a limited set of fields for menus (not items).
372 373 374
    $form['path'] = array('#type' => 'hidden', '#value' => '');
    $form['pid'] = array('#type' => 'hidden', '#value' => 0);
    $form['weight'] = array('#type' => 'hidden', '#value' => 0);
375 376
  }
  else {
377
    $form['description'] = array('#type' => 'textfield', '#title' => t('Description'), '#default_value' => $edit['description'], '#description' => t('The description displayed when hovering over a menu item.'));
Dries's avatar
 
Dries committed
378

Dries's avatar
 
Dries committed
379
    $path_description = t('The Drupal path this menu item links to.');
Dries's avatar
 
Dries committed
380
    if (isset($edit['path']) && array_key_exists($edit['path'], $menu['path index']) && $menu['path index'][$edit['path']] != $edit['mid']) {
Dries's avatar
 
Dries committed
381 382 383 384 385
      $old_mid = $menu['path index'][$edit['path']];
      $old_item = $menu['items'][$old_mid];
      $path_description .= "\n". t('Since a menu item "%old" already exists for "%path", this menu item is shortcut to that location.', array('%old' => l($old_item['title'], 'admin/menu/item/edit/'. $old_mid), '%path' => $edit['path']));
    }

Dries's avatar
 
Dries committed
386
    if ($edit['type'] & MENU_CREATED_BY_ADMIN) {
387
      $form['path'] = array('#type' => 'textfield', '#title' => t('Path'), '#default_value' => $edit['path'], '#description' => $path_description, '#required' => TRUE);
388 389
    }
    else {
390 391
      $form['_path'] = array('#type' => 'item', '#title' => t('Path'), '#title' => l($edit['path'], $edit['path']));
      $form['path'] = array('#type' => 'hidden', '#value' => $edit['path']);
392
    }
393
    $expanded = $edit['type'] & MENU_EXPANDED ? 1 : 0;
394
    $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.'));
Dries's avatar
 
Dries committed
395

396 397
    // Generate a list of possible parents (not including this item or descendants).
    $options = menu_parent_options($edit['mid']);
398
    $form['pid'] = array('#type' => 'select', '#title' => t('Parent item'), '#default_value' =>  $edit['pid'], '#options' => $options);
399

400
    $form['weight'] = array('#type' => 'weight', '#title' => t('Weight'), '#default_value' => $edit['weight'], '#description' => t('Optional. In the menu, the heavier items will sink and the lighter items will be positioned nearer the top.'));
401 402
  }

403
  $form['submit'] = array('#type' => 'submit', '#value' => t('Submit'));
404

405
  $form['mid'] = array('#type' => 'hidden', '#value' => $edit['mid']);
Dries's avatar
 
Dries committed
406 407 408 409 410 411

  // Always enable menu items (but not menus) when editing them.
  if (!($edit['type'] & MENU_IS_ROOT)) {
    $edit['type'] |= MENU_VISIBLE_IN_TREE | MENU_VISIBLE_IN_BREADCRUMB;
  }

412
  $form['type'] = array('#type' => 'hidden', '#value' => $edit['type']);
413

414
  return drupal_get_form('menu_edit_item_form', $form);
415 416
}

Dries's avatar
 
Dries committed
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
/**
 * Confirm that an edited menu item has fields properly filled in.
 */
function menu_edit_item_validate($edit) {
  if (empty($edit['title'])) {
    form_set_error('title', t('You must specify a title.'));
  }

  if ($edit['pid'] != 0) {
    if (empty($edit['path'])) {
      form_set_error('path', t('You must specify a path.'));
    }
  }
}

432 433 434 435
/**
 * Save changes to a menu item into the database.
 */
function menu_edit_item_save($edit) {
Dries's avatar
 
Dries committed
436 437
  $menu = menu_get_menu();

Dries's avatar
 
Dries committed
438 439 440 441 442 443 444
  if ($edit['expanded']) {
    $edit['type'] |= MENU_EXPANDED;
  }
  else {
    $edit['type'] &= ~MENU_EXPANDED;
  }

445
  if ($edit['mid']) {
Dries's avatar
 
Dries committed
446
    db_query("UPDATE {menu} SET pid = %d, path = '%s', title = '%s', description = '%s', weight = %d, type = %d WHERE mid = %d", $edit['pid'], $edit['path'], $edit['title'], $edit['description'], $edit['weight'], $edit['type'] | MENU_MODIFIED_BY_ADMIN, $edit['mid']);
447
    drupal_set_message(t('The menu item %title has been updated.', array('%title' => theme('placeholder', $edit['title']))));
448 449
  }
  else {
Dries's avatar
 
Dries committed
450
    $mid = db_next_id('{menu}_mid');
Dries's avatar
 
Dries committed
451
    db_query("INSERT INTO {menu} (mid, pid, path, title, description, weight, type) VALUES (%d, %d, '%s', '%s', '%s', %d, %d)", $mid, $edit['pid'], $edit['path'], $edit['title'], $edit['description'], $edit['weight'], $edit['type'] | MENU_MODIFIED_BY_ADMIN);
452
    drupal_set_message(t('The menu item %title has been created.', array('%title' => theme('placeholder', $edit['title']))));
Dries's avatar
 
Dries committed
453 454 455
    if (array_key_exists($edit['path'], $menu['path index'])) {
      $old_mid = $menu['path index'][$edit['path']];
      $old_item = $menu['items'][$old_mid];
456
      drupal_set_message(t('Since a menu item %old already exists for %path, this new menu item was created as a shortcut to that location.', array('%old' => l(theme('placeholder', $old_item['title']), 'admin/menu/item/edit/'. $old_mid, array(), NULL, NULL, FALSE, TRUE), '%path' => theme('placeholder', $edit['path']))));
Dries's avatar
 
Dries committed
457
    }
458 459 460 461 462 463 464 465
  }
}

/**
 * Present the menu tree, rendered along with links to edit menu items.
 */
function menu_overview_tree() {
  $menu = menu_get_menu();
Dries's avatar
 
Dries committed
466
  $header = array(t('Menu item'), t('Expanded'), array('data' => t('Operations'), 'colspan' => '3'));
467 468 469 470
  $output = '';

  foreach ($menu['items'][0]['children'] as $mid) {
    $operations = array();
Dries's avatar
 
Dries committed
471
    if ($menu['items'][$mid]['type'] & MENU_MODIFIABLE_BY_ADMIN) {
472 473
      $operations[] = l(t('edit'), 'admin/menu/item/edit/'. $mid);
    }
Dries's avatar
 
Dries committed
474
    if ($menu['items'][$mid]['type'] & MENU_CREATED_BY_ADMIN) {
475 476 477 478 479 480 481 482 483 484 485 486 487 488
      $operations[] = l(t('delete'), 'admin/menu/item/delete/'. $mid);
    }
    $table = theme('item_list', $operations);
    $table .= theme('table', $header, menu_overview_tree_rows($mid));
    $output .= theme('box', $menu['items'][$mid]['title'], $table);
  }
  return $output;
}

function menu_overview_tree_rows($pid = 0, $depth = 0) {
  $menu = menu_get_menu();

  $rows = array();

489
  if (isset($menu['items'][$pid]) && isset($menu['items'][$pid]['children'])) {
490 491 492 493 494 495 496

    usort($menu['items'][$pid]['children'], '_menu_sort');
    foreach ($menu['items'][$pid]['children'] as $mid) {
      // Populate the title field.
      $title = '';
      if ($pid == 0) {
        // Top-level items are menu names, and don't have an associated path.
497
        $title .= $menu['items'][$mid]['title'];
498 499
      }
      else {
500
        $title .= l($menu['items'][$mid]['title'], $menu['items'][$mid]['path']);
501 502 503 504 505 506 507 508 509 510
      }
      if ($depth > 0) {
        $title = '-&nbsp;'. $title;
      }
      for ($i = 1; $i < $depth; $i++) {
        $title = '&nbsp;&nbsp;'. $title;
      }

      // Populate the operations field.
      $operations = array();
Dries's avatar
 
Dries committed
511
      if (!($menu['items'][$mid]['type'] & MENU_MODIFIABLE_BY_ADMIN)) {
Dries's avatar
 
Dries committed
512
        $operations[] = array('data' => t('locked'), 'colspan' => '3', 'align' => 'center');
513 514
      }
      else {
Dries's avatar
 
Dries committed
515
        if ($menu['items'][$mid]['type'] & MENU_VISIBLE_IN_TREE) {
516
          $operations[] = array('data' => l(t('edit'), 'admin/menu/item/edit/'. $mid));
Dries's avatar
 
Dries committed
517
          if ($menu['items'][$mid]['type'] & MENU_IS_ROOT) {
518 519 520 521 522 523 524
            // Disabling entire menus is done from block admin page.
            $operations[] = array('data' => '');
          }
          else {
            $operations[] = array('data' => l(t('disable'), 'admin/menu/item/disable/'. $mid));
          }
        }
Dries's avatar
 
Dries committed
525 526 527
        else {
          $operations[] = array('data' => '');
          $operations[] = array('data' => l(t('enable'), 'admin/menu/item/edit/'. $mid));
528
        }
Dries's avatar
 
Dries committed
529 530

        if ($menu['items'][$mid]['type'] & MENU_CREATED_BY_ADMIN) {
531 532
          $operations[] = array('data' => l(t('delete'), 'admin/menu/item/delete/'. $mid));
        }
Dries's avatar
 
Dries committed
533 534 535
        else if ($menu['items'][$mid]['type'] & MENU_MODIFIED_BY_ADMIN) {
          $operations[] = array('data' => l(t('reset'), 'admin/menu/item/reset/'. $mid));
        }
536 537 538 539 540 541
        else {
          $operations[] = array('data' => '');
        }
      }

      // Call out disabled items.
Dries's avatar
 
Dries committed
542 543
      if ($menu['items'][$mid]['type'] & MENU_VISIBLE_IN_TREE) {
        $class = 'menu-enabled';
544 545
      }
      else {
Dries's avatar
 
Dries committed
546 547
        $title .= ' ('. t('disabled') .')';
        $class = 'menu-disabled';
548 549
      }

Dries's avatar
 
Dries committed
550
      if ($menu['items'][$mid]['type'] & (MENU_MODIFIABLE_BY_ADMIN | MENU_VISIBLE_IN_TREE)) {
Dries's avatar
 
Dries committed
551
        $row = array(array('data' => $title, 'class' => $class), array('data' => ($menu['items'][$mid]['children'] ? (($menu['items'][$mid]['type'] & MENU_EXPANDED) ? t('Yes') : t('No')) : ''), 'class' => $class));
552 553 554 555 556 557 558
        foreach ($operations as $operation) {
          $operation['class'] = $class;
          $row[] = $operation;
        }
        $rows[] = $row;
        $rows = array_merge($rows, menu_overview_tree_rows($mid, $depth + 1));
      }
Dries's avatar
 
Dries committed
559 560 561 562
      else {
        // Skip items that are hidden and locked; admins will never care about them.
        $rows = array_merge($rows, menu_overview_tree_rows($mid, $depth));
      }
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
    }

  }

  return $rows;
}

/**
 * Return a list of menu items that are valid possible parents for the
 * given menu item.
 */
function menu_parent_options($mid, $pid = 0, $depth = 0) {
  $menu = menu_get_menu();

  $options = array();

  if (isset($menu['items'][$pid]) && $menu['items'][$pid]['children']) {
    usort($menu['items'][$pid]['children'], '_menu_sort');
    foreach ($menu['items'][$pid]['children'] as $child) {
      if ($child != $mid) {
Dries's avatar
 
Dries committed
583
        if ($child > 0 && ($menu['items'][$child]['type'] & (MENU_MODIFIABLE_BY_ADMIN | MENU_IS_ROOT))) {
584 585 586 587
          $title = ' '. $menu['items'][$child]['title'];
          for ($i = 0; $i < $depth; $i++) {
            $title = '--'. $title;
          }
Dries's avatar
 
Dries committed
588
          if (!($menu['items'][$child]['type'] & MENU_VISIBLE_IN_TREE)) {
589 590 591 592 593 594 595 596 597 598 599 600
            $title .= ' ('. t('disabled') .')';
          }
          $options[$child] = $title;
        }
        $options += menu_parent_options($mid, $child, $depth + 1);
      }
    }
  }

  return $options;
}

601 602 603 604 605 606 607 608
/**
 * Add menu item fields to the node form.
 */
function menu_node_form($edit = array()) {
  $item = array();
  if ($edit['nid'] > 0) {
    $item = db_fetch_array(db_query("SELECT * FROM {menu} WHERE path = 'node/%d'", $edit['nid']));
    if (is_array($edit['menu'])) {
609
      $item = !is_array($item) ? $edit['menu'] : (($_POST['op'] == t('Preview')) ? array_merge($item, $edit['menu']) : array_merge($edit['menu'], $item));
610 611 612
    }
  }

Dries's avatar
Dries committed
613
  $form['menu'] = array('#type' => 'fieldset', '#title' => t('Menu settings'), '#collapsible' => TRUE, '#collapsed' => TRUE, '#tree' => TRUE);
614

Dries's avatar
Dries committed
615
  $form['menu']['title'] = array('#type' => 'textfield', '#title' => t('Title'), '#default_value' => $item['title'], '#description' => t('The name to display for this link.'));
616

Dries's avatar
Dries committed
617 618 619 620 621 622
  // Generate a list of possible parents (not including this item or descendants).
  $options = menu_parent_options($edit['mid']);
  $form['menu']['pid'] = array('#type' => select, '#title' => t('Parent item'), '#default_value' => $item['pid'], '#options' => $options);
  $form['menu']['description'] = array('#type' => 'hidden', '#value' => $item['description']);
  $form['menu']['path'] = array('#type' => 'hidden', '#value' => $item['path']);
  $form['menu']['weight'] = array('#type' => 'hidden', '#value' => $item['weight'] ? $item['weight'] : 0);
623

Dries's avatar
Dries committed
624 625
  $form['menu']['mid'] = array('#type' => 'hidden', '#value' => $item['mid'] ? $item['mid'] : 0);
  $form['menu']['type'] = array('#type' => 'hidden', '#value' => $item['type'] ? $item['type'] : MENU_CUSTOM_ITEM);
626 627

  if ($item['mid'] > 0) {
Dries's avatar
Dries committed
628
    $form['menu']['delete'] = array('#type' => 'checkbox', '#title' => t('Check to delete this menu item.'), '#default_value' => $item['delete']);
629 630 631 632 633 634 635 636 637
  }

  return $form;
}

/**
 * Remove the menu item.
 */
function menu_node_form_delete($node) {
638
  db_query("DELETE FROM {menu} WHERE path = 'node/%s'", $node->nid);
639
}
640