diff options
author | Gábor Hojtsy <gabor@hojtsy.hu> | 2007-11-09 22:14:41 +0000 |
---|---|---|
committer | Gábor Hojtsy <gabor@hojtsy.hu> | 2007-11-09 22:14:41 +0000 |
commit | a42a9d3efd6b705ad4d53f347348779114666332 (patch) | |
tree | acf45e186ceda210ecce073c053e9849d7c35943 | |
parent | 0ff81a7e1393073edc8944a8c9389524625d77c9 (diff) | |
download | brdo-a42a9d3efd6b705ad4d53f347348779114666332.tar.gz brdo-a42a9d3efd6b705ad4d53f347348779114666332.tar.bz2 |
#178608 by chx: convert menu overview page to a form to overcome any CSRF vulnerabilities
-rw-r--r-- | includes/menu.inc | 19 | ||||
-rw-r--r-- | modules/menu/menu.admin.inc | 146 | ||||
-rw-r--r-- | modules/menu/menu.module | 30 | ||||
-rw-r--r-- | themes/garland/fix-ie-rtl.css | 2 | ||||
-rw-r--r-- | themes/garland/fix-ie.css | 2 | ||||
-rw-r--r-- | themes/garland/style.css | 6 |
6 files changed, 122 insertions, 83 deletions
diff --git a/includes/menu.inc b/includes/menu.inc index ac835c243..1fb8b972d 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -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, ); diff --git a/modules/menu/menu.admin.inc b/modules/menu/menu.admin.inc index 776fc8d4b..c43de5148 100644 --- a/modules/menu/menu.admin.inc +++ b/modules/menu/menu.admin.inc @@ -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' => ''); - } - $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; + + $form[$mlid]['operations'] = array(); + foreach ($operations as $op => $value) { + $form[$mlid]['operations'][$op] = array('#value' => $value); } - $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; } /** diff --git a/modules/menu/menu.module b/modules/menu/menu.module index f729945d4..7204cd7ba 100644 --- a/modules/menu/menu.module +++ b/modules/menu/menu.module @@ -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', @@ -155,6 +141,18 @@ function menu_menu() { } /** + * 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() * * Add a link for each custom menu. diff --git a/themes/garland/fix-ie-rtl.css b/themes/garland/fix-ie-rtl.css index 50eced058..370d7a821 100644 --- a/themes/garland/fix-ie-rtl.css +++ b/themes/garland/fix-ie-rtl.css @@ -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); } diff --git a/themes/garland/fix-ie.css b/themes/garland/fix-ie.css index ca6bbed94..47812ee52 100644 --- a/themes/garland/fix-ie.css +++ b/themes/garland/fix-ie.css @@ -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); } diff --git a/themes/garland/style.css b/themes/garland/style.css index 308d9342e..b01e2af36 100644 --- a/themes/garland/style.css +++ b/themes/garland/style.css @@ -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 |