295 lines
12 KiB
PHP
295 lines
12 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Create the clone form.
|
|
*
|
|
* @param form the form
|
|
* @param form_state reference to the state of the form
|
|
* @param menu the menu object received from hook_load()
|
|
* @see menu_clone_load()
|
|
*
|
|
* TODO: See if we can improve the $form['edit_menu']['edit_tree'] field. Use
|
|
* something else instead of 'markup'.
|
|
*/
|
|
function menu_clone_clone_form($form, &$form_state, $menu) {
|
|
$form['menu_name'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Menu name'),
|
|
'#default_value' => $menu['menu_name'],
|
|
'#maxlength' => MENU_MAX_MENU_NAME_LENGTH_UI - drupal_strlen('menu-'),
|
|
'#description' => t('The machine-readable name of this menu. This text will be used for constructing the URL of the <em>menu overview</em> page for this menu. This name must contain only lowercase letters, numbers, and hyphens, and must be unique.'),
|
|
'#required' => TRUE,
|
|
);
|
|
$form['title'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Title'),
|
|
'#default_value' => $menu['title'],
|
|
'#required' => TRUE,
|
|
);
|
|
$form['description'] = array(
|
|
'#type' => 'textarea',
|
|
'#title' => t('Description'),
|
|
'#default_value' => $menu['description'],
|
|
);
|
|
if (!empty($menu['tree'])) {
|
|
// Add language support if available.
|
|
$form['edit_menu'] = array(
|
|
'#type' => 'fieldset',
|
|
'#title' => t('Customise menu'),
|
|
'#description' => t('Before actually cloning the menu, you can customise it first.'),
|
|
'#collapsible' => FALSE,
|
|
'#collapsed' => FALSE,
|
|
'#tree' => TRUE,
|
|
);
|
|
if (module_exists('i18n_menu')) {
|
|
$form['edit_menu']['menu_lang'] = array(
|
|
'#type' => 'select',
|
|
'#title' => t('Change language'),
|
|
'#description' => t('You can globally change the language of <em>all</em> the available menu items.'),
|
|
'#options' => array_merge(array('' => t('No change')), i18n_language_list()),
|
|
);
|
|
}
|
|
// Append the tree form to the fieldset.
|
|
$form['edit_menu']['edit_tree'] = array(
|
|
'#markup' => '<div class="form-item"><label>' . t('Edit menu') . ':</label><div class="description">' . t('You can reorder the menu items and adjust basic settings here. Drag unwanted items below the <em>Ignore</em> row, or drag the <em>Ignore</em> row itself.') . '</div></div>',
|
|
);
|
|
module_load_include('inc', 'menu', 'menu.admin');
|
|
// In D6, the _menu_overview_tree_form() function also added the 'expanded'
|
|
// field. In D7 it has been removed from that function. If we want it back
|
|
// we will have to create a _menu_clone_overview_tree_form() and add an
|
|
// additional checkbox after $form[$mlid]['hidden'].
|
|
$form['edit_menu']['tree'] = _menu_overview_tree_form($menu['tree']);
|
|
_menu_clone_add_ignore_row($form['edit_menu']['tree']);
|
|
}
|
|
$form['submit'] = array(
|
|
'#type' => 'submit',
|
|
'#value' => t('Create new menu'),
|
|
);
|
|
return $form;
|
|
}
|
|
/**
|
|
* Add the ignore row to the menu tree.
|
|
*
|
|
* @param form the form to which to add the ignore row.
|
|
*/
|
|
function _menu_clone_add_ignore_row(&$form) {
|
|
// Add ignore row with fake mlid and plid fields to make the tabledrag work
|
|
// properly.
|
|
$form['ignore']['title'] = array(
|
|
'#markup' => '<strong>' . t("Ignore: the items below this row won't be cloned.") . '</strong>',
|
|
);
|
|
$form['ignore']['check'] = array(
|
|
'#type' => 'hidden',
|
|
'#value' => 'ignore',
|
|
);
|
|
$form['ignore']['weight'] = array(
|
|
'#type' => 'weight',
|
|
'#delta' => 50,
|
|
'#default_value' => 50,
|
|
);
|
|
$form['ignore']['mlid'] = array(
|
|
'#type' => 'hidden',
|
|
'#value' => 0,
|
|
);
|
|
$form['ignore']['plid'] = array(
|
|
'#type' => 'textfield',
|
|
'#default_value' => 0,
|
|
'#size' => 6,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Validation function for menu_clone_cone_form().
|
|
*
|
|
* @param form the form object
|
|
* @param form_state reference to the form state
|
|
* @see menu_clone_cone_form()
|
|
*/
|
|
function menu_clone_clone_form_validate($form, &$form_state) {
|
|
$menu = $form_state['values'];
|
|
if (preg_match('/[^a-z0-9-]/', $menu['menu_name'])) {
|
|
form_set_error('menu_name', t('The menu name may only consist of lowercase letters, numbers, and hyphens.'));
|
|
}
|
|
// SELECT menu_name FROM {menu_custom} WHERE menu_name = '%s'
|
|
$result = db_select('menu_custom', 'm')
|
|
->fields('m', array('menu_name'))
|
|
->condition('menu_name', 'menu-' . $menu['menu_name'], '=')
|
|
->execute()
|
|
->fetchField();
|
|
if (!empty($result)) {
|
|
form_set_error('menu_name', t("The machine-readable name '@menu_name' must be unique. A menu named '@menu_name' already exists.", array('@menu_name' => $menu['menu_name'])));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Submit function for menu_clone_cone_form(). Parts were taken from the Drupal
|
|
* core Menu module.
|
|
*
|
|
* @param form the form object
|
|
* @param form_state reference to the form state
|
|
* @see menu_clone_cone_form()
|
|
* @see Drupal core menu.admin.inc menu_overview_form_submit()
|
|
* @see Drupal core menu.admin.inc menu_edit_menu_submit()
|
|
*/
|
|
function menu_clone_clone_form_submit($form, &$form_state) {
|
|
// Create new menu.
|
|
// Begin code taken from menu_edit_menu_submit().
|
|
$menu = $form_state['values'];
|
|
if (isset($menu['edit_menu']['menu_lang']) && !empty($menu['edit_menu']['menu_lang'])) {
|
|
$menu['i18n_mode'] = I18N_MODE_MULTIPLE;
|
|
}
|
|
$path = 'admin/structure/menu/manage/';
|
|
// Add 'menu-' to the menu name to help avoid name-space conflicts.
|
|
$menu['menu_name'] = 'menu-' . $menu['menu_name'];
|
|
$link['link_title'] = $menu['title'];
|
|
$link['link_path'] = $path . $menu['menu_name'];
|
|
$link['router_path'] = $path . '%';
|
|
$link['module'] = 'menu';
|
|
$link['plid'] = db_query("SELECT mlid FROM {menu_links} WHERE link_path = :link AND module = :module", array(
|
|
':link' => 'admin/structure/menu',
|
|
':module' => 'system'
|
|
))
|
|
->fetchField();
|
|
|
|
menu_link_save($link);
|
|
menu_save($menu);
|
|
// End code taken from menu_edit_menu_submit().
|
|
|
|
// Add the menu items to the newly created menu.
|
|
if (!empty($form_state['input']['edit_menu']['tree'])) {
|
|
// When dealing with saving menu items, the order in which these items are
|
|
// saved is critical. If a changed child item is saved before its parent,
|
|
// the child item could be saved with an invalid path past its immediate
|
|
// parent. To prevent this, save items in the form in the same order they
|
|
// are sent by $_POST, ensuring parents are saved first, then their children.
|
|
// See http://drupal.org/node/181126#comment-632270
|
|
$order = array_flip(array_keys($form_state['input']['edit_menu']['tree'])); // Get the $_POST order.
|
|
$form['edit_menu']['tree'] = array_merge($order, $form['edit_menu']['tree']); // Update our original form with the new order.
|
|
|
|
//$order = array_flip(array_keys($form['#post']['edit_menu']['tree'])); // Get the $_POST order.
|
|
//$form['edit_menu']['tree'] = array_merge($order, $form['edit_menu']['tree']); // Update our original form with the new order.
|
|
|
|
$menu_items = array();
|
|
|
|
$fields = array('weight', 'plid');
|
|
foreach (element_children($form['edit_menu']['tree']) as $mlid) {
|
|
if (isset($form['edit_menu']['tree'][$mlid]['#item'])) {
|
|
$element = $form['edit_menu']['tree'][$mlid];
|
|
// Update any fields that might have changed in this menu item.
|
|
foreach ($fields as $field) {
|
|
$element['#item'][$field] = $element[$field]['#value'];
|
|
}
|
|
if (isset($menu['edit_menu']['menu_lang']) && !empty($menu['edit_menu']['menu_lang'])) {
|
|
$element['#item']['language'] = $menu['edit_menu']['menu_lang'];
|
|
}
|
|
// Hidden is a special case, the value needs to be reversed.
|
|
// Convert to integer rather than boolean due to PDO cast to string.
|
|
$element['#item']['hidden'] = $element['hidden']['#value'] ? 0 : 1;
|
|
// Make sure we create a new item and not overwrite an existing one and
|
|
// attach it to our new menu.
|
|
$element['#item']['menu_name'] = $menu['menu_name'];
|
|
$element['#item']['mlid'] = NULL;
|
|
$element['#item']['module'] = 'menu';
|
|
$menu_items[$mlid] = $element['#item'];
|
|
}
|
|
else if (isset($form['edit_menu']['tree'][$mlid]['check'])) {
|
|
// Check if we have reached the ignore field so we can stop.
|
|
if ($form['edit_menu']['tree'][$mlid]['check']['#value'] == 'ignore') {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Save the items being cloned to the database.
|
|
$depth_mlids = array(); // Keep track of the new mlids per depth and parent.
|
|
foreach ($menu_items as $item) {
|
|
if (intval($item['depth']) > 1 && !isset($depth_mlids[$item['depth']][$item['plid']])) {
|
|
// Item with a parent, so keep track of the original parent and the
|
|
// new mlid belonging to it.
|
|
$item['plid'] = $depth_mlids[$item['depth']][$item['plid']] = $new_mlid;
|
|
}
|
|
else if (intval($item['depth']) > 1) {
|
|
// Item with the same parent as we have aleady processed before.
|
|
$item['plid'] = $depth_mlids[$item['depth']][$item['plid']];
|
|
}
|
|
$item['customized'] = 1;
|
|
|
|
$new_mlid = menu_link_save($item);
|
|
}
|
|
}
|
|
|
|
$form_state['redirect'] = $path . $menu['menu_name'];
|
|
}
|
|
|
|
/**
|
|
* Theme the menu tree of the clone form into a table and display it inside its
|
|
* proper fieldset.
|
|
*
|
|
* @param form The form array to be themed
|
|
* @see menu_clone_clone_form()
|
|
* @ingroup themeable
|
|
*/
|
|
function theme_menu_clone_clone_form($variables) {
|
|
$form = $variables['form'];
|
|
|
|
// Theme only when necessary.
|
|
if (!empty($form['edit_menu'])) {
|
|
drupal_add_tabledrag('menu-clone', 'match', 'parent', 'menu-clone-plid', 'menu-clone-plid', 'menu-clone-mlid', TRUE, MENU_MAX_DEPTH - 1);
|
|
drupal_add_tabledrag('menu-clone', 'order', 'sibling', 'menu-clone-weight');
|
|
drupal_add_css(drupal_get_path('module', 'menu_clone') . '/css/menu_clone.css');
|
|
|
|
$header = array(
|
|
t('Menu item'),
|
|
array('data' => t('Enabled'), 'class' => array('checkbox')),
|
|
t('Weight'),
|
|
);
|
|
|
|
$rows = array();
|
|
foreach (element_children($form['edit_menu']['tree']) as $mlid) {
|
|
if (isset($form['edit_menu']['tree'][$mlid]['hidden'])) {
|
|
$element = &$form['edit_menu']['tree'][$mlid];
|
|
|
|
// Add special classes to be used for tabledrag.js.
|
|
$element['plid']['#attributes']['class'] = array('menu-clone-plid');
|
|
$element['mlid']['#attributes']['class'] = array('menu-clone-mlid');
|
|
$element['weight']['#attributes']['class'] = array('menu-clone-weight');
|
|
|
|
// Change the parent field to a hidden. This allows any value but hides
|
|
// the field.
|
|
$element['plid']['#type'] = 'hidden';
|
|
|
|
$row = array();
|
|
$row[] = theme('indentation', array('size' => $element['#item']['depth'] - 1)) . drupal_render($element['title']);
|
|
$row[] = array('data' => drupal_render($element['hidden']), 'class' => array('checkbox'));
|
|
$row[] = drupal_render($element['weight']) . drupal_render($element['plid']) . drupal_render($element['mlid']);
|
|
|
|
$row = array_merge(array('data' => $row), $element['#attributes']);
|
|
$row['class'][] = 'draggable';
|
|
$rows[] = $row;
|
|
}
|
|
}
|
|
// Add the Ignore row. The ignore row must be draggable as well to avoid
|
|
// situations where the ignore row is at the top of the table and no items
|
|
// can be dragged above it anymore.
|
|
// A draggable ignore row does also add the ability of simply dragging the
|
|
// ignore row to a spot in the menu, instead of having to dragg all the
|
|
// unnecessary elements below it.
|
|
$form['edit_menu']['tree']['ignore']['plid']['#attributes']['class'] = array('menu-clone-plid');
|
|
$form['edit_menu']['tree']['ignore']['mlid']['#attributes']['class'] = array('menu-clone-mlid');
|
|
$form['edit_menu']['tree']['ignore']['weight']['#attributes']['class'] = array('menu-clone-weight');
|
|
$row = array();
|
|
$row[] = array('data' => drupal_render($form['edit_menu']['tree']['ignore']['title']), 'colspan' => '2');
|
|
$row[] = drupal_render($form['edit_menu']['tree']['ignore']['check']) . drupal_render($form['edit_menu']['tree']['ignore']['weight']) . drupal_render($form['edit_menu']['tree']['ignore']['mlid']) . drupal_render($form['edit_menu']['tree']['ignore']['plid']);
|
|
$rows[] = array('data' => $row, 'class' => array('draggable', 'ignore'));
|
|
|
|
// Make sure the draggable table is rendered inside the fieldset. Having
|
|
// trouble with this? Check the possibilities here
|
|
// http://drupal.org/node/82916 and here http://drupal.org/node/98065. The
|
|
// latter worked for me, others did not.
|
|
$form['edit_menu']['tree']['#children'] = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'menu-clone')));
|
|
}
|
|
$output = drupal_render_children($form);
|
|
|
|
return $output;
|
|
}
|