From cad226e60bc5827050789d4900f1a17907c203d3 Mon Sep 17 00:00:00 2001
From: Dries Buytaert <dries@buytaert.net>
Date: Tue, 13 Oct 2009 01:25:58 +0000
Subject: [PATCH] - Patch #351249 by stBorchert, coreyp_1, BrightLoudNoise,
 catch, kkaefer, sign: finer control over the Parent Menu select box.

---
 modules/menu/menu.admin.js |  48 ++++++++++++++++
 modules/menu/menu.module   | 115 ++++++++++++++++++++++++++++++++++---
 2 files changed, 156 insertions(+), 7 deletions(-)
 create mode 100644 modules/menu/menu.admin.js

diff --git a/modules/menu/menu.admin.js b/modules/menu/menu.admin.js
new file mode 100644
index 000000000000..681c4814d9d6
--- /dev/null
+++ b/modules/menu/menu.admin.js
@@ -0,0 +1,48 @@
+// $Id$
+
+(function ($) {
+
+  Drupal.behaviors.menuChangeParentItems = {
+    attach: function (context, settings) {
+      $('fieldset#edit-menu input').each(function () {
+        $(this).change(function () {
+          // Update list of available parent menu items.
+          Drupal.menu_update_parent_list();
+        });
+      });
+    }
+  }
+
+  /**
+   * Function to set the options of the menu parent item dropdown.
+   */
+  Drupal.menu_update_parent_list = function () {
+    var values = [];
+
+    $('input:checked', $('fieldset#edit-menu')).each(function () {
+      // Get the names of all checked menus.
+      values.push(Drupal.checkPlain($.trim($(this).val())));
+    });
+
+    var url = Drupal.settings.basePath + 'admin/structure/menu/parents';
+    $.ajax({
+      url: location.protocol + '//' + location.host + url,
+      type: 'POST',
+      data: {'menus[]' : values},
+      dataType: 'json',
+      success: function (options) {
+        // Save key of last selected element.
+        var selected = $('fieldset#edit-menu #edit-menu-parent :selected').val();
+        // Remove all exisiting options from dropdown.
+        $('fieldset#edit-menu #edit-menu-parent').children().remove();
+        // Add new options to dropdown.
+        jQuery.each(options, function(index, value) {
+          $('fieldset#edit-menu #edit-menu-parent').append(
+            $('<option ' + (index == selected ? ' selected="selected"' : '') + '></option>').val(index).text(value)
+          );
+        });
+      }
+    });
+  }
+
+})(jQuery);
diff --git a/modules/menu/menu.module b/modules/menu/menu.module
index 17967e26cd57..76af91d21bb2 100644
--- a/modules/menu/menu.module
+++ b/modules/menu/menu.module
@@ -56,6 +56,12 @@ function menu_menu() {
     'access arguments' => array('administer menu'),
     'file' => 'menu.admin.inc',
   );
+  $items['admin/structure/menu/parents'] = array(
+    'title' => 'Parent menu items',
+    'page callback' => 'menu_parent_options_js',
+    'type' => MENU_CALLBACK,
+    'access arguments' => array(TRUE),
+  );
   $items['admin/structure/menu/list'] = array(
     'title' => 'List menus',
     'type' => MENU_DEFAULT_LOCAL_TASK,
@@ -295,7 +301,7 @@ function menu_delete($menu) {
  * @param $menus
  *   An array of menu names and titles, such as from menu_get_menus().
  * @param $item
- *   The menu item for which to generate a list of parents.
+ *   The menu item or the node type for which to generate a list of parents.
  *   If $item['mlid'] == 0 then the complete tree is returned.
  * @return
  *   An array of menu link titles keyed on the a string containing the menu name
@@ -309,6 +315,45 @@ function menu_parent_options($menus, $item) {
   if (variable_get('menu_override_parent_selector', FALSE)) {
     return array();
   }
+
+  $available_menus = array();
+  if (is_array($item)) {
+    // If $item is an array fill it with all menus given to this function.
+    $available_menus = $menus;
+  }
+  else {
+    // If $item is a node type, get all available menus for this type and
+    // prepare a dummy menu item for _menu_parent_depth_limit().
+    $type_menus = variable_get('menu_options_' . $item, array('main-menu' => 'main-menu'));
+    foreach ($type_menus as $menu) {
+      $available_menus[$menu] = $menu;
+    }
+    $item = array('mlid' => 0);
+  }
+
+  return _menu_get_options($menus, $available_menus, $item);
+}
+
+/**
+ * Page callback.
+ * Get all available menus and menu items as Javascript array.
+ */
+function menu_parent_options_js() {
+  $available_menus = array();
+  if (isset($_POST['menus']) && count($_POST['menus'])) {
+    foreach ($_POST['menus'] as $menu) {
+      $available_menus[$menu] = $menu;
+    }
+  }
+  $options = _menu_get_options(menu_get_menus(), $available_menus, array('mlid' => 0));
+  error_log( var_export( $options, 1) );
+  print drupal_json_output($options);
+}
+
+/**
+ * Helper function to get the items of the given menu.
+ */
+function _menu_get_options($menus, $available_menus, $item) {
   // If the item has children, there is an added limit to the depth of valid parents.
   if (isset($item['parent_depth_limit'])) {
     $limit = $item['parent_depth_limit'];
@@ -317,10 +362,13 @@ function menu_parent_options($menus, $item) {
     $limit = _menu_parent_depth_limit($item);
   }
 
+  $options = array();
   foreach ($menus as $menu_name => $title) {
-    $tree = menu_tree_all_data($menu_name, NULL);
-    $options[$menu_name . ':0'] = '<' . $title . '>';
-    _menu_parents_recurse($tree, $menu_name, '--', $options, $item['mlid'], $limit);
+    if (isset($available_menus[$menu_name])) {
+      $tree = menu_tree_all_data($menu_name, NULL);
+      $options[$menu_name . ':0'] = '<' . $title . '>';
+      _menu_parents_recurse($tree, $menu_name, '--', $options, $item['mlid'], $limit);
+    }
   }
   return $options;
 }
@@ -486,6 +534,15 @@ function _menu_parent_depth_limit($item) {
  */
 function menu_form_alter(&$form, $form_state, $form_id) {
   if (!empty($form['#node_edit_form'])) {
+    // Generate a list of possible parents.
+    $type = $form['#node']->type;
+    $options = menu_parent_options(menu_get_menus(), $type);
+    if (count($options) == 0) {
+      // No possible parent menu items found so there is no need to display the
+      // menu options.
+      return;
+    }
+
     // Note - doing this to make sure the delete checkbox stays in the form.
     $form['#cache'] = TRUE;
 
@@ -527,9 +584,8 @@ function menu_form_alter(&$form, $form_state, $form_id) {
       '#description' => t('The link text corresponding to this item that should appear in the menu. Leave blank if you do not wish to add this post to the menu.'),
       '#required' => FALSE,
     );
-    // Generate a list of possible parents (not including this item or descendants).
-    $options = menu_parent_options(menu_get_menus(), $item);
-    $default = $item['menu_name'] . ':' . $item['plid'];
+
+    $default = ($item['mlid'] ? $item['menu_name'] . ':' . $item['plid'] : variable_get('menu_parent_' . $type, 'main-menu:0'));
     if (!isset($options[$default])) {
       $default = 'navigation:0';
     }
@@ -553,6 +609,51 @@ function menu_form_alter(&$form, $form_state, $form_id) {
   }
 }
 
+/**
+ * Implement hook_form_FORM_ID_alter() for the node type form.
+ * Adds menu options to the node type form.
+ */
+function menu_form_node_type_form_alter(&$form, $form_state) {
+  $menu_options = menu_get_menus();
+  $type = $form['#node_type'];
+  $form['menu'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Menu settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#attached' => array(
+      'js' => array(drupal_get_path('module', 'menu') . '/menu.admin.js'),
+    ),
+    '#group' => 'additional_settings',
+  );
+  $form['menu']['menu_options'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Available menus'),
+    '#default_value' => variable_get('menu_options_' . $type->type, array('main-menu' => 'main-menu')),
+    '#options' => $menu_options,
+    '#description' => t('The menus available to place links in for this content type.'),
+  );
+  // To avoid an 'illegal option' error after saving the form we have to load
+  // all available menu items.
+  // Otherwise it is not possible to dynamically add options to the list.
+  $options = menu_parent_options(menu_get_menus(), array('mlid' => 0));
+  $form['menu']['menu_parent'] = array(
+    '#type' => 'select',
+    '#title' => t('Default parent item'),
+    '#default_value' => variable_get('menu_parent_' . $type->type, 'main-menu:0'),
+    '#options' => $options,
+    '#description' => t('Choose the menu item to be the default parent for a new link in the content authoring form.'),
+    '#attributes' => array('class' => array('menu-title-select')),
+  );
+
+  // Call Drupal.menu_update_parent_list() to filter the list of
+  // available default parent menu items based on the selected menus.
+  drupal_add_js(
+    '(function ($) { Drupal.menu_update_parent_list(); })(jQuery);',
+    array('scope' => 'footer', 'type' => 'inline')
+  );
+}
+
 /**
  * Decompose the selected menu parent option into the menu_name and plid.
  */
-- 
GitLab