menu.module 26.7 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'];
  }

109
110
111
112
113
  $form['settings_links'] = array(
    '#type' => 'fieldset',
    '#title' => t('Primary links settings'),
  );

114
  $form['settings_links']['intro'] = array(
115
116
    '#type' => 'item',
    '#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 post authoring form.', array('%menu' => url('admin/menu'))),
117
118
119
120
121
122
  );

  $form['settings_links']['menu_primary_menu'] = array(
    '#type' => 'select',
    '#title' => t('Menu containing primary links'),
    '#default_value' => variable_get('menu_primary_menu', 0),
123
    '#options' => $primary_options,
124
125
126
127
128
  );

  $secondary_options[0] = t('No secondary links');
  foreach ($menu['items'][0]['children'] as $mid) {
    $secondary_options[$mid] = $menu['items'][$mid]['title'];
129
  }
130
131
132
133
134
135

  $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,
136
137
138
139
140
141
142
143
144
145
146
    '#description' => t('If you select the same menu as primary links then secondary links will display the appropriate second level of your navigation hierarchy.'),
  );

  $form['settings_authoring'] = array(
    '#type' => 'fieldset',
    '#title' => t('Post authoring form settings'),
  );

  $form['settings_authoring']['intro'] = array(
    '#type' => 'item',
    '#value' => t('On each post authoring form there is a menu settings pane. This setting allows you to limit what is displayed in the parent item drop-down menu of that pane. This can be used to force new menu items to be created in the primary links menu or to hide admin menu items.'),
147
148
  );

149
150
151
152
153
154
155
156
157
158
159
160
161
  $authoring_options = array(0 => t('Show all menus'));
  foreach ($menu['items'][0]['children'] as $mid) {
    $authoring_options[$mid] = $menu['items'][$mid]['title'];
  }

  $form['settings_authoring']['menu_parent_items'] = array(
    '#type' => 'select',
    '#title' => t('Restrict parent items to'),
    '#default_value' => variable_get('menu_parent_items', 0),
    '#options' => $authoring_options,
    '#description' => t('Choose the menu from which parent items will be made available. Only this menu item and its children will be shown.'),
   );

162
  return system_settings_form('menu_configure', $form);
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
}

/**
 * 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;
  }
181
  else if ($op == 'view') {
182
    $data['subject'] = $menu['items'][$delta]['title'];
183
    $data['content'] = '<div class="menu">'. theme('menu_tree', $delta) .'</div>' ;
184
185
186
187
    return $data;
  }
}

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/**
 * Implementation of hook_nodeapi().
 */
function menu_nodeapi(&$node, $op) {

  if (user_access('administer menu')) {
    switch ($op) {
      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;
    }
  }
}

216
217
218
219
220
221
222
223
/**
 * Implementation of hook_perm().
 */
function menu_perm() {
  return array('administer menu');
}

/**
224
 * Menu callback; present the main menu management page.
225
226
227
228
 */
function menu_overview() {
  menu_rebuild();

Dries's avatar
   
Dries committed
229
  return menu_overview_tree();
230
231
232
}

/**
233
 * Menu callback; clear the database, resetting the menu to factory defaults.
234
235
 */
function menu_reset() {
236
  $op = isset($_POST['op']) ? $_POST['op'] : '';
237
  switch ($op) {
238
    case t('Reset all'):
239
      db_query('DELETE FROM {menu}');
240
241
242
      $mid = menu_edit_item_save(array('title' => t('Primary menu links'), 'pid' => 0, 'type' => MENU_CUSTOM_MENU));
      variable_set('menu_primary_menu', $mid);
      variable_set('menu_secondary_menu', $mid);
243
      drupal_set_message(t('The menu items have been reset to their default settings.'));
Dries's avatar
   
Dries committed
244
      drupal_goto('admin/menu');
245
246
      break;
    default:
247
248
249
250
      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'));
251
252
253
254
  }
}

/**
255
 * Menu callback; handle the adding of a new menu.
256
257
 */
function menu_add_menu() {
258
259
  $op = isset($_POST['op']) ? $_POST['op'] : '';
  $edit = isset($_POST['edit']) ? $_POST['edit'] : '';
260
261
262
263
  $output = '';

  switch ($op) {
    case t('Submit'):
Dries's avatar
   
Dries committed
264
265
266
267
268
269
      menu_edit_item_validate($edit);
      if (!form_get_errors()) {
        menu_edit_item_save($edit);
        drupal_goto('admin/menu');
      }
      // Fall through.
270
271
    default:
      $edit['pid'] = 0;
Dries's avatar
   
Dries committed
272
      $edit['type'] = MENU_CUSTOM_MENU;
273
274
275
      $output .= menu_edit_item_form($edit);
  }

Dries's avatar
   
Dries committed
276
  return $output;
277
278
279
}

/**
280
 * Menu callback; reset a single modified item.
281
282
 */
function menu_reset_item($mid) {
283
  $op = isset($_POST['op']) ? $_POST['op'] : '';
284
285
286
  switch ($op) {
    case t('Reset'):
      db_query('DELETE FROM {menu} WHERE mid = %d', $mid);
287
      drupal_set_message(t("The menu item was reset to its default settings."));
Dries's avatar
   
Dries committed
288
      drupal_goto('admin/menu');
289
290
      break;
    default:
291
      $title = db_result(db_query('SELECT title FROM {menu} WHERE mid = %d', $mid));
292
293
294
295
      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'));
296
297
298
299
  }
}

/**
300
 * Menu callback; delete a single custom item.
301
302
 */
function menu_delete_item($mid) {
303
  $op = isset($_POST['op']) ? $_POST['op'] : '';
304
305
306
307
308
  $result = db_query('SELECT type, title FROM {menu} WHERE mid = %d', $mid);
  $menu = db_fetch_object($result);
  if (!$menu) {
    drupal_goto('admin/menu');
  }
309
310
311
  switch ($op) {
    case t('Delete'):
      db_query('DELETE FROM {menu} WHERE mid = %d', $mid);
312
      if ($menu->type & MENU_IS_ROOT) {
313
        drupal_set_message(t('The menu has been removed.'));
314
315
      }
      else {
316
        drupal_set_message(t('The menu item has been removed.'));
317
      }
Dries's avatar
   
Dries committed
318
      drupal_goto('admin/menu');
319
320
      break;
    default:
321
      if ($menu->type & MENU_IS_ROOT) {
322
        $message = t('Are you sure you want to delete the menu %item?', array('%item' => theme('placeholder', $menu->title)));
323
324
      }
      else {
325
        $message = t('Are you sure you want to delete the custom menu item %item?', array('%item' => theme('placeholder', $menu->title)));
326
      }
327
      return confirm_form('menu_confirm_delete', $form, $message, 'admin/menu', t('This action cannot be undone.'), t('Delete'));
328
329
330
331
  }
}

/**
332
 * Menu callback; hide a menu item.
333
334
 */
function menu_disable_item($mid) {
Dries's avatar
   
Dries committed
335
336
337
338
  $menu = menu_get_menu();
  $type = $menu['items'][$mid]['type'];
  $type &= ~MENU_VISIBLE_IN_TREE;
  $type &= ~MENU_VISIBLE_IN_BREADCRUMB;
Dries's avatar
   
Dries committed
339
  $type |= MENU_MODIFIED_BY_ADMIN;
Dries's avatar
   
Dries committed
340
  db_query('UPDATE {menu} SET type = %d WHERE mid = %d', $type, $mid);
341
  drupal_set_message(t('The menu item has been disabled.'));
Dries's avatar
   
Dries committed
342
  drupal_goto('admin/menu');
343
344
345
}

/**
346
 * Menu callback; dispatch to the appropriate menu item edit function.
347
 */
Dries's avatar
Dries committed
348
function menu_edit_item($mid = 0) {
349
350
  $op = isset($_POST['op']) ? $_POST['op'] : '';
  $edit = isset($_POST['edit']) ? $_POST['edit'] : '';
Dries's avatar
   
Dries committed
351

352
353
354
355
  $output = '';

  switch ($op) {
    case t('Submit'):
Dries's avatar
   
Dries committed
356
357
358
359
360
      menu_edit_item_validate($edit);
      if (!form_get_errors()) {
        menu_edit_item_save($edit);
        drupal_goto('admin/menu');
      }
361
362
      $output .= menu_edit_item_form($edit);
      break;
363
364
365
366
367
368
369
370
    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
371
        $edit['description'] = $item->description;
372
        $edit['weight'] = $item->weight;
Dries's avatar
   
Dries committed
373
        $edit['type'] = $item->type;
374
375
376
377
      }
      else {
        $edit['mid'] = 0; // In case a negative ID was passed in.
        $edit['pid'] = 1; // default to "Navigation" menu.
Dries's avatar
   
Dries committed
378
        $edit['type'] = MENU_CUSTOM_ITEM;
379
380
381
382
      }
      $output .= menu_edit_item_form($edit);
  }

Dries's avatar
   
Dries committed
383
  return $output;
384
385
386
387
388
389
390
391
}

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

392
  $form['title'] = array('#type' => 'textfield', '#title' => t('Title'), '#default_value' => $edit['title'], '#description' => t('The name of the menu.'), '#required' => TRUE);
393
394
395

  if ($edit['pid'] == 0) {
    // Display a limited set of fields for menus (not items).
396
397
398
    $form['path'] = array('#type' => 'hidden', '#value' => '');
    $form['pid'] = array('#type' => 'hidden', '#value' => 0);
    $form['weight'] = array('#type' => 'hidden', '#value' => 0);
399
400
  }
  else {
401
    $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
402

Dries's avatar
   
Dries committed
403
404
    $path_description = t('The Drupal path this menu item links to.');

Dries's avatar
   
Dries committed
405
    if ($edit['type'] & MENU_CREATED_BY_ADMIN) {
406
      $form['path'] = array('#type' => 'textfield', '#title' => t('Path'), '#default_value' => $edit['path'], '#description' => $path_description, '#required' => TRUE);
407
408
    }
    else {
409
      $form['_path'] = array('#type' => 'item', '#title' => t('Path'), '#description' => l($edit['path'], $edit['path']));
410
      $form['path'] = array('#type' => 'hidden', '#value' => $edit['path']);
411
    }
412
    $expanded = $edit['type'] & MENU_EXPANDED ? 1 : 0;
413
    $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
414

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

419
    $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.'));
420
421
  }

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

424
  $form['mid'] = array('#type' => 'hidden', '#value' => $edit['mid']);
Dries's avatar
   
Dries committed
425
426
427
428
429
430

  // 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;
  }

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

433
  return drupal_get_form('menu_edit_item_form', $form);
434
435
}

Dries's avatar
   
Dries committed
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
/**
 * 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.'));
    }
  }
}

451
452
/**
 * Save changes to a menu item into the database.
453
454
 *
 * @return mid
455
456
 */
function menu_edit_item_save($edit) {
Dries's avatar
   
Dries committed
457
458
  $menu = menu_get_menu();

Dries's avatar
   
Dries committed
459
460
461
462
463
464
465
  if ($edit['expanded']) {
    $edit['type'] |= MENU_EXPANDED;
  }
  else {
    $edit['type'] &= ~MENU_EXPANDED;
  }

466
  if ($edit['mid']) {
Dries's avatar
   
Dries committed
467
    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']);
468
    drupal_set_message(t('The menu item %title has been updated.', array('%title' => theme('placeholder', $edit['title']))));
469
470
  }
  else {
471
472
    $edit['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)", $edit['mid'], $edit['pid'], $edit['path'], $edit['title'], $edit['description'], $edit['weight'], $edit['type'] | MENU_MODIFIED_BY_ADMIN);
473
    drupal_set_message(t('The menu item %title has been created.', array('%title' => theme('placeholder', $edit['title']))));
474
  }
475
  return $edit['mid'];
476
477
478
479
480
481
482
}

/**
 * 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
483
  $header = array(t('Menu item'), t('Expanded'), array('data' => t('Operations'), 'colspan' => '3'));
484
485
486
487
  $output = '';

  foreach ($menu['items'][0]['children'] as $mid) {
    $operations = array();
Dries's avatar
   
Dries committed
488
    if ($menu['items'][$mid]['type'] & MENU_MODIFIABLE_BY_ADMIN) {
489
490
      $operations[] = l(t('edit'), 'admin/menu/item/edit/'. $mid);
    }
Dries's avatar
   
Dries committed
491
    if ($menu['items'][$mid]['type'] & MENU_CREATED_BY_ADMIN) {
492
493
494
495
496
497
498
499
500
501
502
503
504
505
      $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();

506
  if (isset($menu['items'][$pid]) && isset($menu['items'][$pid]['children'])) {
507
508
509
510
511
512
513

    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.
514
        $title .= $menu['items'][$mid]['title'];
515
516
      }
      else {
517
        $title .= l($menu['items'][$mid]['title'], $menu['items'][$mid]['path']);
518
519
520
521
522
523
524
525
526
527
      }
      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
528
      if (!($menu['items'][$mid]['type'] & MENU_MODIFIABLE_BY_ADMIN)) {
Dries's avatar
   
Dries committed
529
        $operations[] = array('data' => t('locked'), 'colspan' => '3', 'align' => 'center');
530
531
      }
      else {
532
533
        // Set the edit column.
        if ($menu['items'][$mid]['type'] & (MENU_VISIBLE_IN_TREE | MENU_VISIBLE_IF_HAS_CHILDREN)) {
534
535
          $operations[] = array('data' => l(t('edit'), 'admin/menu/item/edit/'. $mid));
        }
Dries's avatar
   
Dries committed
536
537
        else {
          $operations[] = array('data' => '');
538
539
540
541
542
543
544
545
546
547
548
549
        }

        // Set the disable column.
        if ($menu['items'][$mid]['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 ($menu['items'][$mid]['type'] & MENU_VISIBLE_IN_TREE) {
          $operations[] = array('data' => l(t('disable'), 'admin/menu/item/disable/'. $mid));
        }
        else {
Dries's avatar
   
Dries committed
550
          $operations[] = array('data' => l(t('enable'), 'admin/menu/item/edit/'. $mid));
551
        }
Dries's avatar
   
Dries committed
552

553
        // Set the reset column.
Dries's avatar
   
Dries committed
554
        if ($menu['items'][$mid]['type'] & MENU_CREATED_BY_ADMIN) {
555
556
          $operations[] = array('data' => l(t('delete'), 'admin/menu/item/delete/'. $mid));
        }
Dries's avatar
   
Dries committed
557
558
559
        else if ($menu['items'][$mid]['type'] & MENU_MODIFIED_BY_ADMIN) {
          $operations[] = array('data' => l(t('reset'), 'admin/menu/item/reset/'. $mid));
        }
560
561
562
563
564
565
        else {
          $operations[] = array('data' => '');
        }
      }

      // Call out disabled items.
566
      if ($menu['items'][$mid]['type'] & (MENU_VISIBLE_IN_TREE | MENU_VISIBLE_IF_HAS_CHILDREN)) {
Dries's avatar
   
Dries committed
567
        $class = 'menu-enabled';
568
569
      }
      else {
Dries's avatar
   
Dries committed
570
571
        $title .= ' ('. t('disabled') .')';
        $class = 'menu-disabled';
572
573
      }

Dries's avatar
   
Dries committed
574
      if ($menu['items'][$mid]['type'] & (MENU_MODIFIABLE_BY_ADMIN | MENU_VISIBLE_IN_TREE)) {
Dries's avatar
   
Dries committed
575
        $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));
576
577
578
579
580
581
582
        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
583
584
585
586
      else {
        // Skip items that are hidden and locked; admins will never care about them.
        $rows = array_merge($rows, menu_overview_tree_rows($mid, $depth));
      }
587
588
589
590
591
592
593
594
595
    }

  }

  return $rows;
}

/**
 * Return a list of menu items that are valid possible parents for the
596
597
598
599
600
601
602
603
604
605
606
607
 * 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.
608
609
610
611
612
613
 */
function menu_parent_options($mid, $pid = 0, $depth = 0) {
  $menu = menu_get_menu();

  $options = array();

614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
  if (!isset($menu['items'][$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 && ($menu['items'][$pid]['type'] & (MENU_MODIFIABLE_BY_ADMIN | MENU_IS_ROOT))) {
    $title = ' '. $menu['items'][$pid]['title'];
    for ($i = 0; $i < $depth; $i++) {
      $title = '--'. $title;
    }
    if (!($menu['items'][$pid]['type'] & MENU_VISIBLE_IN_TREE)) {
      $title .= ' ('. t('disabled') .')';
    }
    $options[$pid] = $title;
    $depth ++;
  }

  // Add children of $pid to the list recursively.
  if ($menu['items'][$pid]['children']) {
638
639
    usort($menu['items'][$pid]['children'], '_menu_sort');
    foreach ($menu['items'][$pid]['children'] as $child) {
640
      $options += menu_parent_options($mid, $child, $depth);
641
642
643
644
645
646
    }
  }

  return $options;
}

647
648
649
/**
 * Add menu item fields to the node form.
 */
650
function menu_form_alter($form_id, &$form) {
651
  if (user_access('administer menu') && isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) {
652
653
654
655
656
657
658
659
660
    $edit = isset($_POST['edit']) ? $_POST['edit'] : '';
    $edit['nid'] = $form['nid']['#value'];

    $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'])) {
        $item = !is_array($item) ? $edit['menu'] : (($_POST['op'] == t('Preview')) ? array_merge($item, $edit['menu']) : array_merge($edit['menu'], $item));
      }
661
662
    }

663
664
665
666
    $form['menu'] = array(
      '#type' => 'fieldset',
      '#title' => t('Menu settings'),
      '#collapsible' => TRUE,
667
      '#collapsed' => empty($item['title']),
668
      '#tree' => TRUE,
669
      '#weight' => 30,
670
    );
671

672
673
674
675
676
677
    $form['menu']['title'] = array(
      '#type' => 'textfield',
      '#title' => t('Title'),
      '#default_value' => $item['title'],
      '#description' => t('The name to display for this link.'),
    );
678

679
680
681
682
683
684
    $form['menu']['description'] = array(
      '#type' => 'textfield',
      '#title' => t('Description'),
      '#default_value' => $item['description'],
      '#description' => t('The description displayed when hovering over a menu item.'),
    );
685

686
687
    // Generate a list of possible parents.
    $options = menu_parent_options($item['mid'], variable_get('menu_parent_items', 0));
688

689
690
691
692
693
694
    $form['menu']['pid'] = array(
      '#type' => select,
      '#title' => t('Parent item'),
      '#default_value' => $item['pid'],
      '#options' => $options,
    );
695

696
697
698
699
    $form['menu']['path'] = array(
      '#type' => 'hidden',
      '#value' => $item['path'],
    );
700

701
702
703
704
705
706
707
    $form['menu']['weight'] = array(
      '#type' => 'weight',
      '#title' => t('Weight'),
      '#default_value' => $item['weight'],
      '#delta' => 10,
      '#description' => t('Optional. In the menu, the heavier items will sink and the lighter items will be positioned nearer the top.'),
    );
708

709
710
711
    $form['menu']['mid'] = array(
      '#type' => 'hidden',
      '#value' => $item['mid'] ? $item['mid'] : 0,
712
713
    );

714
715
716
    $form['menu']['type'] = array(
      '#type' => 'hidden',
      '#value' => $item['type'] ? $item['type'] : MENU_CUSTOM_ITEM,
717
    );
718

719
720
721
722
723
724
725
726
727
728
729
730
731
    if ($item['mid'] > 0) {
      $form['menu']['delete'] = array(
        '#type' => 'checkbox',
        '#title' => t('Check to delete this menu item.'),
        '#default_value' => $item['delete'],
      );

      $form['menu']['advanced'] = array(
        '#type' => 'item',
        '#value' => t('You may also <a href="%edit">edit the advanced settings</a> for this menu item.', array('%edit' => url("admin/menu/item/edit/{$item['mid']}"))),
      );
    }
  }
732
733
734
735
736
737
}

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