#178608 by chx: convert menu overview page to a form to overcome any CSRF vulnerabilities
parent
0ff81a7e13
commit
a42a9d3efd
|
@ -838,7 +838,6 @@ function menu_tree_page_data($menu_name = 'navigation') {
|
|||
* Recursive helper function - collect node links.
|
||||
*/
|
||||
function menu_tree_collect_node_links(&$tree, &$node_links) {
|
||||
|
||||
foreach ($tree as $key => $v) {
|
||||
if ($tree[$key]['link']['router_path'] == 'node/%') {
|
||||
$nid = substr($tree[$key]['link']['link_path'], 5);
|
||||
|
@ -911,7 +910,6 @@ function _menu_tree_check_access(&$tree) {
|
|||
* See menu_tree_page_data for a description of the data structure.
|
||||
*/
|
||||
function menu_tree_data($result = NULL, $parents = array(), $depth = 1) {
|
||||
|
||||
list(, $tree) = _menu_tree_data($result, $parents, $depth);
|
||||
return $tree;
|
||||
}
|
||||
|
@ -930,16 +928,19 @@ function _menu_tree_data($result, $parents, $depth, $previous_element = '') {
|
|||
// We need to determine if we're on the path to root so we can later build
|
||||
// the correct active trail and breadcrumb.
|
||||
$item['in_active_trail'] = in_array($item['mlid'], $parents);
|
||||
|
||||
$index = $previous_element ? ($previous_element['mlid']) : '';
|
||||
// The current item is the first in a new submenu.
|
||||
if ($item['depth'] > $depth) {
|
||||
// _menu_tree returns an item and the menu tree structure.
|
||||
list($item, $below) = _menu_tree_data($result, $parents, $item['depth'], $item);
|
||||
$tree[$index] = array(
|
||||
'link' => $previous_element,
|
||||
'below' => $below,
|
||||
);
|
||||
if ($previous_element) {
|
||||
$tree[$previous_element['mlid']] = array(
|
||||
'link' => $previous_element,
|
||||
'below' => $below,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$tree = $below;
|
||||
}
|
||||
// We need to fall back one level.
|
||||
if (!isset($item) || $item['depth'] < $depth) {
|
||||
return array($item, $tree);
|
||||
|
@ -951,7 +952,7 @@ function _menu_tree_data($result, $parents, $depth, $previous_element = '') {
|
|||
elseif ($item['depth'] == $depth) {
|
||||
if ($previous_element) {
|
||||
// Only the first time.
|
||||
$tree[$index] = array(
|
||||
$tree[$previous_element['mlid']] = array(
|
||||
'link' => $previous_element,
|
||||
'below' => FALSE,
|
||||
);
|
||||
|
|
|
@ -21,11 +21,12 @@ function menu_overview_page() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Shows for one menu the menu items accessible to the current user and relevant operations.
|
||||
* Form for editing an entire menu tree at once.
|
||||
*
|
||||
* Shows for one menu the menu items accessible to the current user and
|
||||
* relevant operations.
|
||||
*/
|
||||
function menu_overview($menu) {
|
||||
|
||||
$header = array(t('Menu item'), t('Expanded'), array('data' => t('Operations'), 'colspan' => '3'));
|
||||
function menu_overview_form(&$form_state, $menu) {
|
||||
$sql ="
|
||||
SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, ml.*
|
||||
FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path
|
||||
|
@ -37,81 +38,120 @@ function menu_overview($menu) {
|
|||
$node_links = array();
|
||||
menu_tree_collect_node_links($tree, $node_links);
|
||||
menu_tree_check_access($tree, $node_links);
|
||||
$rows = _menu_overview_tree($tree);
|
||||
$output = theme('table', $header, $rows);
|
||||
$output .= theme('pager', NULL, 200, 0);
|
||||
return $output;
|
||||
|
||||
$form = _menu_overview_tree_form($tree);
|
||||
if (element_children($form)) {
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Save configuration'),
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['empty_menu'] = array('#value' => t('There are no menu items yet.'));
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive helper function for menu_overview().
|
||||
* Recursive helper function for menu_overview_form().
|
||||
*/
|
||||
function _menu_overview_tree($tree) {
|
||||
static $rows = array();
|
||||
function _menu_overview_tree_form($tree) {
|
||||
static $form = array('#tree' => TRUE);
|
||||
foreach ($tree as $data) {
|
||||
$title = '';
|
||||
$item = $data['link'];
|
||||
// Don't show callbacks; these have $item['hidden'] < 0.
|
||||
if ($item && $item['hidden'] >= 0) {
|
||||
$title = str_repeat(' ', $item['depth'] - 1) . ($item['depth'] > 1 ? '- ' : '');
|
||||
$title .= l($item['title'], $item['href'], $item['options']);
|
||||
// Populate the operations field.
|
||||
$mlid = $item['mlid'];
|
||||
$form[$mlid]['#item'] = $item;
|
||||
$form[$mlid]['#attributes'] = $item['hidden'] ? array('class' => 'menu-disabled') : array('class' => 'menu-enabled');
|
||||
$form[$mlid]['title']['#value'] = l($item['title'], $item['href'], $item['options']) . ($item['hidden'] ? ' ('. t('disabled') .')' : '');
|
||||
$form[$mlid]['hidden'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => !$item['hidden'],
|
||||
);
|
||||
$form[$mlid]['expanded'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $item['has_children'] && $item['expanded'],
|
||||
);
|
||||
// Build a list of operations.
|
||||
$operations = array();
|
||||
// Set the edit column.
|
||||
$operations[] = array('data' => l(t('edit'), 'admin/build/menu/item/'. $item['mlid'] .'/edit'));
|
||||
if ($item['hidden']) {
|
||||
$title .= ' ('. t('disabled') .')';
|
||||
$class = 'menu-disabled';
|
||||
$operations[] = array('data' => l(t('enable'), 'admin/build/menu/item/'. $item['mlid'] .'/enable'));
|
||||
}
|
||||
else {
|
||||
$class = 'menu-enabled';
|
||||
$operations[] = array('data' => l(t('disable'), 'admin/build/menu/item/'. $item['mlid'] .'/disable'));
|
||||
}
|
||||
$operations['edit'] = l(t('edit'), 'admin/build/menu/item/'. $item['mlid'] .'/edit');
|
||||
// Only items created by the menu module can be deleted.
|
||||
if ($item['module'] == 'menu') {
|
||||
$operations[] = array('data' => l(t('delete'), 'admin/build/menu/item/'. $item['mlid'] .'/delete'));
|
||||
$operations['delete'] = l(t('delete'), 'admin/build/menu/item/'. $item['mlid'] .'/delete');
|
||||
}
|
||||
// Set the reset column.
|
||||
elseif ($item['module'] == 'system' && $item['customized']) {
|
||||
$operations[] = array('data' => l(t('reset'), 'admin/build/menu/item/'. $item['mlid'] .'/reset'));
|
||||
$operations['reset'] = l(t('reset'), 'admin/build/menu/item/'. $item['mlid'] .'/reset');
|
||||
}
|
||||
else {
|
||||
$operations[] = array('data' => '');
|
||||
|
||||
$form[$mlid]['operations'] = array();
|
||||
foreach ($operations as $op => $value) {
|
||||
$form[$mlid]['operations'][$op] = array('#value' => $value);
|
||||
}
|
||||
$row = array(
|
||||
array('data' => $title, 'class' => $class),
|
||||
array('data' => ($item['has_children'] ? (($item['expanded']) ? t('Yes') : t('No')) : ''), 'class' => $class),
|
||||
);
|
||||
foreach ($operations as $operation) {
|
||||
$operation['class'] = $class;
|
||||
$row[] = $operation;
|
||||
}
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
if ($data['below']) {
|
||||
_menu_overview_tree($data['below']);
|
||||
_menu_overview_tree_form($data['below']);
|
||||
}
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
function menu_overview_form_submit($form) {
|
||||
foreach (element_children($form) as $mlid) {
|
||||
if (isset($form[$mlid]['hidden'])) {
|
||||
$element = $form[$mlid];
|
||||
if ($element['hidden']['#value'] != $element['hidden']['#default_value']) {
|
||||
$element['#item']['hidden'] = !$element['hidden']['#value'];
|
||||
menu_link_save($element['#item']);
|
||||
}
|
||||
if ($element['expanded']['#value'] != $element['expanded']['#default_value']) {
|
||||
$element['#item']['expanded'] = $element['expanded']['#value'];
|
||||
menu_link_save($element['#item']);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; enable/disable a menu link.
|
||||
*
|
||||
* @param $hide
|
||||
* TRUE to not show in the menu tree. FALSE to make the item and its children
|
||||
* reappear in menu tree.
|
||||
* @param $item
|
||||
* The menu item.
|
||||
* Theme the menu overview form into a table.
|
||||
*/
|
||||
function menu_flip_item($hide, $item) {
|
||||
function theme_menu_overview_form($form) {
|
||||
$header = array(t('Enabled'), t('Expanded'), t('Menu item'), array('data' => t('Operations'), 'colspan' => '3'));
|
||||
$rows = array();
|
||||
foreach (element_children($form) as $mlid) {
|
||||
if (isset($form[$mlid]['hidden'])) {
|
||||
$element = &$form[$mlid];
|
||||
// Build a list of operations.
|
||||
$operations = array();
|
||||
foreach (element_children($element['operations']) as $op) {
|
||||
$operations[] = drupal_render($element['operations'][$op]);
|
||||
}
|
||||
while (count($operations) < 2) {
|
||||
$operations[] = '';
|
||||
}
|
||||
|
||||
$item['hidden'] = (bool)$hide;
|
||||
$item['customized'] = 1;
|
||||
menu_link_save($item);
|
||||
drupal_set_message($hide ? t('The menu item has been disabled.') : t('The menu item has been enabled.'));
|
||||
drupal_goto('admin/build/menu-customize/'. $item['menu_name']);
|
||||
$row = array();
|
||||
$row[] = array('data' => drupal_render($element['hidden']), 'align' => 'center');
|
||||
$row[] = array('data' => drupal_render($element['expanded']), 'align' => 'center');
|
||||
$depth = $element['#item']['depth'];
|
||||
$indentation = str_repeat(' ', $depth - 1) . ($depth > 1 ? '- ' : '');
|
||||
$row[] = $indentation . drupal_render($element['title']);
|
||||
$row = array_merge($row, $operations);
|
||||
|
||||
$row = array_merge(array('data' => $row), $element['#attributes']);
|
||||
$rows[] = $row;
|
||||
}
|
||||
}
|
||||
$output = '';
|
||||
if ($rows) {
|
||||
$output .= theme('table', $header, $rows, array('id' => 'menu-overview'));
|
||||
$output .= theme('pager', NULL, 200, 0);
|
||||
}
|
||||
$output .= drupal_render($form);
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -80,8 +80,8 @@ function menu_menu() {
|
|||
);
|
||||
$items['admin/build/menu-customize/%menu'] = array(
|
||||
'title' => 'Customize menu',
|
||||
'page callback' => 'menu_overview',
|
||||
'page arguments' => array(3),
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('menu_overview_form', 3),
|
||||
'title callback' => 'menu_overview_title',
|
||||
'title arguments' => array(3),
|
||||
'access arguments' => array('administer menu'),
|
||||
|
@ -115,20 +115,6 @@ function menu_menu() {
|
|||
'type' => MENU_CALLBACK,
|
||||
'file' => 'menu.admin.inc',
|
||||
);
|
||||
$items['admin/build/menu/item/%menu_link/disable'] = array(
|
||||
'title' => 'Disable menu item',
|
||||
'page callback' => 'menu_flip_item',
|
||||
'page arguments' => array(TRUE, 4),
|
||||
'type' => MENU_CALLBACK,
|
||||
'file' => 'menu.admin.inc',
|
||||
);
|
||||
$items['admin/build/menu/item/%menu_link/enable'] = array(
|
||||
'title' => 'Enable menu item',
|
||||
'page callback' => 'menu_flip_item',
|
||||
'page arguments' => array(FALSE, 4),
|
||||
'type' => MENU_CALLBACK,
|
||||
'file' => 'menu.admin.inc',
|
||||
);
|
||||
$items['admin/build/menu/item/%menu_link/edit'] = array(
|
||||
'title' => 'Edit menu item',
|
||||
'page callback' => 'drupal_get_form',
|
||||
|
@ -154,6 +140,18 @@ function menu_menu() {
|
|||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemenation of hook_theme().
|
||||
*/
|
||||
function menu_theme() {
|
||||
return array(
|
||||
'menu_overview_form' => array(
|
||||
'file' => 'menu.admin.inc',
|
||||
'arguments' => array('form' => NULL),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_enable()
|
||||
*
|
||||
|
|
|
@ -47,7 +47,7 @@ html.js fieldset.collapsed {
|
|||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
td.menu-disabled {
|
||||
tr.menu-disabled {
|
||||
/* Use filter to emulate CSS3 opacity */
|
||||
filter: alpha(opacity=50);
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ html.js fieldset.collapsed {
|
|||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
td.menu-disabled {
|
||||
tr.menu-disabled {
|
||||
/* Use filter to emulate CSS3 opacity */
|
||||
filter: alpha(opacity=50);
|
||||
}
|
||||
|
|
|
@ -779,15 +779,15 @@ ul.links li, ul.inline li {
|
|||
/**
|
||||
* Menu.module
|
||||
*/
|
||||
tr.menu-disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
tr.odd td.menu-disabled {
|
||||
background-color: #edf5fa;
|
||||
}
|
||||
tr.even td.menu-disabled {
|
||||
background-color: #fff;
|
||||
}
|
||||
td.menu-disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll.module
|
||||
|
|
Loading…
Reference in New Issue