You are here

simplified_menu_admin.module in Simplified Menu Administration 7

Simplifies the Menu and Shortcut modules by merging "List links" and "Edit menu" into a single administration page.

File

simplified_menu_admin.module
View source
<?php

/**
 * @file
 * Simplifies the Menu and Shortcut modules by merging "List links" and "Edit menu" into a single administration page.
 */

/**
 * Implements hook_menu_alter().
 */
function simplified_menu_admin_menu_alter(&$items) {

  // Remove the Menu module's "list links" local task, and make the page for
  // editing the menu become the default local task.
  unset($items['admin/structure/menu/manage/%menu/list']);
  if (isset($items['admin/structure/menu/manage/%menu/edit'])) {
    $items['admin/structure/menu/manage/%menu/edit'] = array(
      'title' => $items['admin/structure/menu/manage/%menu/edit']['title'],
      'weight' => -10,
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
    );
  }

  // Remove the Shortcut module's "list links" local task, and make the page
  // for editing the shortcut set become the default local task.
  unset($items['admin/config/user-interface/shortcut/%shortcut_set/links']);
  if (isset($items['admin/config/user-interface/shortcut/%shortcut_set/edit'])) {
    $items['admin/config/user-interface/shortcut/%shortcut_set/edit'] = array(
      'title' => 'Edit shortcut set',
      'weight' => -10,
      'type' => MENU_DEFAULT_LOCAL_TASK,
    );
  }
}

/**
 * Implements hook_theme().
 */
function simplified_menu_admin_theme() {
  return array(
    'simplified_menu_admin_menu_overview_form' => array(
      'render element' => 'form',
    ),
  );
}

/**
 * Implements MODULE_preprocess_HOOK().
 */
function simplified_menu_admin_preprocess_table(&$variables) {
  $item = menu_get_item();

  // Modify the table shown on the menu overview page to get rid of the "list
  // links" operation.
  if ($item['page_callback'] == 'menu_overview_page') {
    foreach ($variables['rows'] as $index => &$row) {
      unset($row[1]);
    }
    $variables['header'][1]['colspan']--;
  }
  elseif ($item['page_callback'] == 'shortcut_set_admin') {
    $shortcut_set_names = array_keys(shortcut_sets());
    foreach ($variables['rows'] as $index => &$row) {
      unset($row[1]);
      $set_name = $shortcut_set_names[$index];
      $row[2] = l(t('edit set'), "admin/config/user-interface/shortcut/{$set_name}/edit");
    }
    $variables['header'][1]['colspan']--;
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function simplified_menu_admin_form_menu_overview_form_alter(&$form, &$form_state) {

  // Merge in the menu_edit_menu() form, which allows editing the menu name and
  // description, to the current form (which allows editing the menu links).
  _simplified_menu_admin_add_form($form, $form_state, 'menu_edit_menu', 'edit', $form['#menu']);

  // Hide the menu description field unless an "edit description" checkbox is
  // selected. This prevents the list of menu links from being pushed too far
  // down the page.
  $form['description_toggle'] = array(
    '#type' => 'checkbox',
    '#title' => t('Edit description'),
  );
  if (isset($form['description']['#access'])) {
    $form['description_toggle']['#access'] = $form['description']['#access'];
  }
  $form['description']['#states']['visible'][':input[name="description_toggle"]']['checked'] = TRUE;

  // Modify the theming of the form so we can control the order in which the
  // items we've added are rendered.
  $form['#simplified_menu_admin']['original_theme'] = $form['#theme'];
  $form['#theme'] = 'simplified_menu_admin_menu_overview_form';
}

/**
 * Returns HTML for the combined form that allows editing a menu and its links.
 *
 * @param $variables
 *   An associative array containing:
 *   - form: A render element representing the form.
 *
 * @ingroup themeable
 */
function theme_simplified_menu_admin_menu_overview_form($variables) {

  // Render the items we added to the form at the top.
  $output = drupal_render($variables['form']['title']);
  $output .= drupal_render($variables['form']['menu_name']);
  $output .= drupal_render($variables['form']['description_toggle']);
  $output .= drupal_render($variables['form']['description']);

  // Then add the original form (with its original theming) at the bottom.
  $output .= theme($variables['form']['#simplified_menu_admin']['original_theme'], $variables);
  return $output;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function simplified_menu_admin_form_shortcut_set_customize_alter(&$form, &$form_state) {

  // Unfortunately we have to get this from the URL (it's not provided in $form
  // or $form_state).
  $shortcut_set = menu_get_object('shortcut_set', 4);

  // Add a submit handler that will run after the shortcut set's links are
  // saved, but before the shortcut set itself is saved.
  $form['#submit'][] = 'simplified_menu_admin_shortcut_set_customize_submit';

  // Merge in the shortcut_set_edit_form() form, which allows editing the
  // shortcut set name, to the current form (which allows editing the shortcut
  // set's links).
  _simplified_menu_admin_add_form($form, $form_state, 'shortcut_set_edit_form', $shortcut_set);
}

/**
 * Custom submit handler for shortcut_set_customize().
 */
function simplified_menu_admin_shortcut_set_customize_submit($form, &$form_state) {

  // This submit handler runs afer the shortcut set's links have been saved,
  // but before the set itself is saved in shortcut_set_edit_form_submit(). So
  // we need to reload the up-to-date set into $form_state['values'], to make
  // sure we don't lose the changes to the links the second time it is saved.
  $form_state['values']['shortcut_set'] = shortcut_set_load($form_state['values']['shortcut_set']->set_name);
}

/**
 * Merges in a new form to an existing one.
 *
 * @param $form
 *   The current form array.
 * @param $form_state
 *   An array representing the current state of the form.
 * @param $form_id
 *   The ID of the form to merge in.
 * @param ...
 *   Any additional arguments to pass to the form builder function.
 */
function _simplified_menu_admin_add_form(&$form, $form_state, $form_id) {

  // Get the additional arguments that will be passed to the form builder
  // function.
  $args = array_slice(func_get_args(), 3);

  // Keep track of all original form children.
  $original_children = element_children($form);

  // Keep track of whether the original form uses a hierarchical #tree
  // structure, then unset it temporarily so the new form's #tree can be
  // determined below.
  $original_tree = !empty($form['#tree']);
  unset($form['#tree']);

  // First call the form builder function and add the new form to the existing
  // $form array. Note that this will replace any common form elements (e.g.,
  // submit buttons) with ones from the second form, but so far that's exactly
  // what we want for this module.
  $form = call_user_func_array($form_id, array_merge(array(
    $form,
    &$form_state,
  ), $args));
  drupal_alter(array(
    'form',
    "form_{$form_id}",
  ), $form, $form_state, $form_id);

  // If there is a mismatch between the #tree setting for the original form and
  // the new form, all the new children should get the correct #tree explicitly
  // set, so they maintain their original behavior.
  $new_tree = !empty($form['#tree']);
  if ($new_tree != $original_tree) {
    foreach (element_children($form) as $key) {
      if (!in_array($key, $original_children) && !isset($form[$key]['#tree'])) {
        $form[$key]['#tree'] = $new_tree;
      }
    }
  }

  // Restore the top-level #tree setting from the original form.
  $form['#tree'] = $original_tree;

  // Now actually build a full copy of the form we're adding, and use it to
  // merge in that form's #validate and #submit handlers to the overall form.
  $built_form = call_user_func_array('drupal_get_form', array_merge(array(
    $form_id,
  ), $args));
  foreach (array(
    '#validate',
    '#submit',
  ) as $handler_type) {
    if (!empty($built_form[$handler_type])) {
      foreach ($built_form[$handler_type] as $handler) {

        // Do not add a handler that is already there, e.g. if it was added in
        // hook_form_alter() above.
        if (!isset($form[$handler_type]) || !in_array($handler, $form[$handler_type])) {
          $form[$handler_type][] = $handler;
        }
      }
    }
  }

  // The forms we're merging in this module each use drupal_set_message() to
  // indicate success. Add a submit handler that forces only the first such
  // message to be used.
  $form['#submit'][] = '_simplified_menu_admin_limit_to_one_status_message';
}

/**
 * Removes all the current user's status messages except the first one.
 *
 * This is useful when multiple forms are merged together, because each might
 * use drupal_set_message() in its submit handler to indicate success. This
 * function assumes that the first such message is the one you want to keep,
 * and it removes any other status messages that were previously set.
 */
function _simplified_menu_admin_limit_to_one_status_message() {
  if (!empty($_SESSION['messages']['status'])) {
    $first_message = array_shift($_SESSION['messages']['status']);
    $_SESSION['messages']['status'] = array(
      $first_message,
    );
  }
}

Functions

Namesort descending Description
simplified_menu_admin_form_menu_overview_form_alter Implements hook_form_FORM_ID_alter().
simplified_menu_admin_form_shortcut_set_customize_alter Implements hook_form_FORM_ID_alter().
simplified_menu_admin_menu_alter Implements hook_menu_alter().
simplified_menu_admin_preprocess_table Implements MODULE_preprocess_HOOK().
simplified_menu_admin_shortcut_set_customize_submit Custom submit handler for shortcut_set_customize().
simplified_menu_admin_theme Implements hook_theme().
theme_simplified_menu_admin_menu_overview_form Returns HTML for the combined form that allows editing a menu and its links.
_simplified_menu_admin_add_form Merges in a new form to an existing one.
_simplified_menu_admin_limit_to_one_status_message Removes all the current user's status messages except the first one.