Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.842
diff -u -p -r1.842 common.inc
--- includes/common.inc 5 Jan 2009 22:23:58 -0000 1.842
+++ includes/common.inc 9 Jan 2009 00:07:43 -0000
@@ -3330,6 +3330,21 @@ function element_children($element) {
}
/**
+ * Determine whether help topics for a given module exist.
+ *
+ * @param $module
+ * The name of the module (without the .module extension).
+ * @return
+ * TRUE if the module is enabled and provides help topics, and the help module is enabled.
+ */
+function help_exists($module) {
+ if (drupal_function_exists('help_get_topics') && module_exists($module)) {
+ $topics = help_get_topics();
+ return isset($topics[$module]);
+ }
+}
+
+/**
* Provide theme registration for themes across .inc files.
*/
function drupal_common_theme() {
@@ -3398,8 +3413,8 @@ function drupal_common_theme() {
'item_list' => array(
'arguments' => array('items' => array(), 'title' => NULL, 'type' => 'ul', 'attributes' => NULL),
),
- 'more_help_link' => array(
- 'arguments' => array('url' => NULL),
+ 'help_link' => array(
+ 'arguments' => array('module' => NULL, 'topic' => NULL, 'title' => NULL, 'popup' => NULL, 'attributes' => NULL),
),
'xml_icon' => array(
'arguments' => array('url' => NULL),
Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.310
diff -u -p -r1.310 menu.inc
--- includes/menu.inc 4 Jan 2009 20:04:32 -0000 1.310
+++ includes/menu.inc 9 Jan 2009 00:07:46 -0000
@@ -1296,10 +1296,9 @@ function menu_get_active_help() {
if ($help = $function($router_path, $arg)) {
$output .= $help . "\n";
}
- // Add "more help" link on admin pages if the module provides a
- // standalone help page.
- if ($arg[0] == "admin" && module_exists('help') && $function('admin/help#' . $arg[2], $empty_arg) && $help) {
- $output .= theme("more_help_link", url('admin/help/' . $arg[2]));
+ // Add "more help" link on admin pages if the module provides help topics.
+ if ($arg[0] == "admin" && help_exists($arg[2]) && $help) {
+ $output .= theme("help_link", $arg[2]);
}
}
return $output;
Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.460
diff -u -p -r1.460 theme.inc
--- includes/theme.inc 4 Jan 2009 16:19:39 -0000 1.460
+++ includes/theme.inc 9 Jan 2009 00:07:48 -0000
@@ -1571,13 +1571,6 @@ function theme_item_list($items = array(
}
/**
- * Returns code that emits the 'more help'-link.
- */
-function theme_more_help_link($url) {
- return '
' . t('
More help ', array('@link' => check_url($url))) . '
';
-}
-
-/**
* Return code that emits an XML icon.
*
* For most use cases, this function has been superseded by theme_feed_icon().
Index: modules/help/help-popup.css
===================================================================
RCS file: modules/help/help-popup.css
diff -N modules/help/help-popup.css
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/help/help-popup.css 9 Jan 2009 00:07:48 -0000
@@ -0,0 +1,156 @@
+/* $Id: help-popup.css,v 1.4 2008/04/28 20:40:59 merlinofchaos Exp $ */
+
+body {
+ background: #edf5fa;
+ color: #494949;
+ font: 12px/170% Verdana, sans-serif;
+ margin: 0;
+ padding: 0;
+}
+
+input {
+ color: #494949;
+ font: 12px/100% Verdana, sans-serif;
+}
+
+textarea, select {
+ color: #494949;
+ font: 12px/160% Verdana, sans-serif;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-weight: normal;
+ font-family: Helvetica, Arial, sans-serif;
+ margin: 0;
+ padding: 0;
+}
+
+h1 {
+ font-size: 170%;
+}
+
+h2 {
+ font-size: 160%;
+ line-height: 130%;
+}
+
+h3 {
+ font-size: 140%;
+}
+
+h4 {
+ font-size: 130%;
+}
+
+h5 {
+ font-size: 120%;
+}
+
+h6 {
+ font-size: 110%;
+}
+
+ul, ol, quote, code, fieldset {
+ margin: .5em 0;
+}
+
+p {
+ margin: 0.6em 0 1.2em;
+ padding: 0;
+}
+
+a:link, a:visited {
+ color: #027AC6;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #0062A0;
+ text-decoration: underline;
+}
+
+a:active, a.active {
+ color: #5895be;
+}
+
+hr {
+ background: #5294c1;
+ border: none;
+ height: 1px;
+ margin: 0;
+ padding: 0;
+}
+
+ol li, ul li {
+ margin: 0.4em 0 0.4em .5em; /* LTR */
+}
+
+code, pre {
+ background: #f1f1f1;
+ border: 1px solid #444;
+ display: block;
+ margin: 1em;
+ padding: .2em;
+}
+
+div#breadcrumb {
+ background-color: white;
+ border-bottom: 1px solid #ccc;
+ height: 2em;
+ padding-left: 1em;
+ position: fixed;
+ top: 0;
+ width: 100%;
+}
+
+div#breadcrumb .breadcrumb {
+ padding: 0;
+ margin: 0;
+}
+
+#content {
+ margin: 3em 1em 1em 1em;
+}
+
+#content #page-title {
+ margin-bottom: .5em;
+}
+
+#content .toc {
+ background: #fff url(gradient.png) repeat-x scroll 0% 100%;
+ border: 1px solid #D0EBFF;
+ display: table;
+ margin: 5px 10px;
+ padding: 5px 10px 5px 30px;
+}
+
+#content .toc-block {
+ background: #fff url(gradient.png) repeat-x scroll 0% 100%;
+ border: 1px solid #D0EBFF;
+ float: right;
+ margin: 10px;
+ padding: 5px 10px;
+}
+
+div.admin-panel {
+ background: #fff url(gradient.png) repeat-x scroll 0% 100%;
+ border: 1px solid #D0EBFF;
+ margin: 5px 0;
+ padding: 1em 1em 1.5em;
+}
+
+div.admin-panel .description {
+ color: #898989;
+ font-size: 0.92em;
+ line-height: 150%;
+ margin-bottom: 1em;
+}
+
+div.admin-panel .body {
+ margin: 0;
+ padding: 0;
+}
+
+ol.toc li, ul.toc li {
+ margin: 0;
+}
Index: modules/help/help-popup.tpl.php
===================================================================
RCS file: modules/help/help-popup.tpl.php
diff -N modules/help/help-popup.tpl.php
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/help/help-popup.tpl.php 9 Jan 2009 00:07:48 -0000
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: modules/help/help-rtl.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/help/help-rtl.css,v
retrieving revision 1.2
diff -u -p -r1.2 help-rtl.css
--- modules/help/help-rtl.css 27 Nov 2007 12:09:26 -0000 1.2
+++ modules/help/help-rtl.css 9 Jan 2009 00:07:49 -0000
@@ -9,3 +9,23 @@
padding-right: 0;
padding-left: 0;
}
+
+.help-topic .toc-block {
+ float: left;
+}
+
+.help-left {
+ float: right;
+}
+
+.help-right {
+ float: left;
+}
+
+.help-previous {
+ float: right;
+}
+
+.help-next {
+ float: left;
+}
Index: modules/help/help.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/help/help.admin.inc,v
retrieving revision 1.7
diff -u -p -r1.7 help.admin.inc
--- modules/help/help.admin.inc 26 Oct 2008 18:06:38 -0000 1.7
+++ modules/help/help.admin.inc 9 Jan 2009 00:07:49 -0000
@@ -3,74 +3,638 @@
/**
* @file
- * Admin page callbacks for the help module.
+ * Page callbacks for the help module.
*/
/**
- * Menu callback; prints a page listing a glossary of Drupal terminology.
+ * Menu callback; returns a page displaying available help topics for modules.
*/
-function help_main() {
- // Add CSS
- drupal_add_css(drupal_get_path('module', 'help') . '/help.css', array('preprocess' => FALSE));
- $output = '' . t('Help topics') . ' ' . t('Help is available on the following items:') . '
' . help_links_as_list();
+function help_by_module() {
+ $items = array();
+ $menu_items = array();
+
+ $topics = help_get_topics();
+ $settings = help_get_settings();
+
+ help_get_topic_hierarchy($topics);
+
+ $modules = module_rebuild_cache();
+ foreach ($modules as $file) {
+ $module = $file->name;
+ if (empty($topics[$module]) || !empty($settings[$module]['hide'])) {
+ continue;
+ }
+
+ // Fetch help links.
+ $items = help_get_tree($topics, $topics[$module]['']['children'], array(), 0);
+
+ // Sort in ascending order of keys.
+ ksort($items);
+
+ // Retrieve the name to use.
+ if (isset($settings[$module]['index name'])) {
+ $name = $settings[$module]['index name'];
+ }
+ elseif (isset($settings[$module]['name'])) {
+ $name = $settings[$module]['name'];
+ }
+ else {
+ $name = t($file->info['name']);
+ }
+
+ $menu_items[$name] = array($file->info['description'], $items);
+ }
+
+ // Render the page differently for popup display.
+ if (!empty($_GET['popup'])) {
+ drupal_set_breadcrumb(array());
+ print theme('help_popup', theme('system_admin_by_module', $menu_items));
+ return;
+ }
+
+ return theme('system_admin_by_module', $menu_items);
+}
+
+/**
+ * Menu callback; returns a page with help topic for a module.
+ */
+function help_topic_page($module, $topic = NULL) {
+ $info = help_get_topic_info($module, $topic);
+ if (isset($topic) && !$info) {
+ // Return error 404 if the topic does not exist.
+ return drupal_not_found();
+ }
+
+ $popup = !empty($_GET['popup']);
+
+ drupal_set_title($info['title']);
+
+ // Set up breadcrumb.
+ $breadcrumb = array();
+
+ $parent = $info;
+ $parent_module = $module;
+
+ $checked = array();
+ // Crawl up parent tree looking for the breadcrumb trail.
+ while (!empty($parent['parent'])) {
+ if (strpos($parent['parent'], '%')) {
+ list($parent_module, $parent_topic) = explode('%', $parent['parent']);
+ }
+ else {
+ $parent_topic = $parent['parent'];
+ }
+
+ // Mark the topic as checked to prevent processing again.
+ if (!empty($checked[$parent_module][$parent_topic])) {
+ break;
+ }
+ $checked[$parent_module][$parent_topic] = TRUE;
+
+ $parent = help_get_topic_info($parent_module, $parent_topic);
+ if (!$parent) {
+ break;
+ }
+
+ $breadcrumb[] = help_l($parent['title'], "admin/help/$parent_module/$parent_topic");
+ }
+
+ $breadcrumb[] = help_l(help_get_module_name($parent_module), "admin/help/$parent_module");
+ $breadcrumb[] = help_l(t('Help'), "admin/help");
+
+ // Set the default topic and title is no topic is given.
+ if (!isset($topic)) {
+ $topic = 'about';
+ drupal_set_title(t('About @module', array('@module' => help_get_module_name($module))));
+ }
+
+ $output = help_view_topic($module, $topic, $popup);
+ if (empty($output)) {
+ if ($topic == 'about') {
+ $output = help_view_module($module, $popup);
+ }
+ else {
+ $output = t('No such help topic found.');
+ }
+ }
+
+ if ($popup) {
+ drupal_set_breadcrumb(array_reverse($breadcrumb));
+ print theme('help_popup', $output);
+ return;
+ }
+
+ $breadcrumb[] = help_l(t('Administer'), 'admin');
+ $breadcrumb[] = l(t('Home'), '');
+ drupal_set_breadcrumb(array_reverse($breadcrumb));
+ drupal_add_css(drupal_get_path('module', 'help') . '/help.css');
+
return $output;
}
/**
- * Menu callback; prints a page listing general help for a module.
+ * Load and render a help topics listing.
*/
-function help_page($name) {
+function help_view_module($module, $popup = FALSE) {
$output = '';
- if (module_hook($name, 'help')) {
- $module = drupal_parse_info_file(drupal_get_path('module', $name) . '/' . $name . '.info');
- drupal_set_title($module['name']);
-
- $temp = module_invoke($name, 'help', "admin/help#$name", drupal_help_arg());
- if (empty($temp)) {
- $output .= t("No help is available for module %module.", array('%module' => $module['name']));
+ $items = array();
+ $topics = help_get_topics();
+
+ help_get_topic_hierarchy($topics);
+
+ if (!empty($topics[$module])) {
+ $items = help_get_tree($topics, $topics[$module]['']['children'], array(), 0);
+ $output = theme('item_list', $items, NULL, 'ul', array('class' => 'toc'));
+ }
+ else {
+ $output = t('No help topics found.');
+ }
+
+ return $output;
+}
+
+/**
+ * Load and render a help topic.
+ */
+function help_view_topic($module, $topic, $popup = FALSE) {
+ $file_info = help_get_topic_file_info($module, $topic);
+ if ($file_info) {
+ $info = help_get_topic_info($module, $topic);
+ $file = "./$file_info[path]/$file_info[file]";
+
+ // @todo Is this trusted output?
+ $output = file_get_contents($file);
+
+ // Make some exchanges. The strtr is because url() translates $ into %24
+ // but we need to change it back for the regex replacement.
+ // Change 'topic:' to the URL for another help topic.
+ if ($popup) {
+ $output = preg_replace('/&topic:([^"]+)&/', strtr(url('admin/help/$1', array('query' => 'popup=1')), array('%24' => '$')), $output);
}
else {
- $output .= $temp;
+ $output = preg_replace('/&topic:([^"]+)&/', strtr(url('admin/help/$1'), array('%24' => '$')), $output);
}
- // Only print list of administration pages if the module in question has
- // any such pages associated to it.
- $admin_tasks = system_get_module_admin_tasks($name);
- if (!empty($admin_tasks)) {
- ksort($admin_tasks);
- $output .= theme('item_list', $admin_tasks, t('@module administration pages', array('@module' => $module['name'])));
+ global $base_path;
+
+ // Change 'path:' to the URL to the base help directory.
+ $output = preg_replace('/&path&([^"]+)/', $base_path . $info['path'] . '/$1', $output);
+
+ // Change 'base_url:' to the URL to the site.
+ $output = preg_replace('/&base_url&([^"]+)/', strtr(url('$1'), array('%24' => '$')), $output);
+
+ // Change 'path:' to the URL to the base help directory.
+ $output = str_replace('&path&', $base_path . $info['path'] . '/', $output);
+
+ // Change 'trans_path:' to the URL to the actual help directory.
+ $output = str_replace('&trans_path&', $base_path . $file_info['path'] . '/', $output);
+
+ // Change 'base_url:' to the URL to the site.
+ $output = str_replace('&base_url&', $base_path, $output);
+
+ // Run the line break filter if requested
+ if (!empty($info['line break'])) {
+ // Remove the header since it adds an extra to the filter.
+ $output = preg_replace('/^\n/', '', $output);
+
+ $output = _filter_autop($output);
}
+ if (!empty($info['navigation'])) {
+ $topics = help_get_topics();
+ help_get_topic_hierarchy($topics);
+
+ if (!empty($topics[$module]['']['children'])) {
+ $tree = array($topic);
+ if (!empty($topics[$module][$topic]['parent'])) {
+ array_push($tree, $topics[$module][$topic]['parent']);
+ }
+ $items = help_get_tree($topics, $topics[$module]['']['children'], $tree);
+ if (count($items) > 1) {
+ // Render the table of contents block to display links to parent and sibling topics.
+ $output = theme('item_list', $items, NULL, 'ul', array('class' => 'toc-block')) . $output;
+ }
+ }
+
+ if (!empty($topics[$module][$topic]['children'])) {
+ $items = help_get_tree($topics, $topics[$module][$topic]['children']);
+ // Render an ordered list to display links to immediate children.
+ $output .= theme('item_list', $items, NULL, 'ol', array('class' => 'toc'));
+ }
+
+ // Determine the path for "Up" link.
+ list($parent_module, $parent_topic) = $topics[$module][$topic]['_parent'];
+ if ($parent_topic) {
+ // Link to a parent topic.
+ $parent = $topics[$module][$topic]['_parent'];
+ $up = "admin/help/$parent[0]/$parent[1]";
+ }
+ elseif ($topic == 'about') {
+ // Link to the main help page, if we are on the about page.
+ $up = 'admin/help';
+ }
+ else {
+ $up = "admin/help/$module";
+ }
+
+ $siblings = $topics[$parent_module][$parent_topic]['children'];
+ // Sort topics according to weight.
+ uasort($siblings, '_help_uasort');
+ $prev = $next = NULL;
+ $found = FALSE;
+ // Find the previous and next topic.
+ foreach ($siblings as $sibling) {
+ list($sibling_module, $sibling_topic) = $sibling;
+ if ($found) {
+ $next = $sibling;
+ break;
+ }
+ if ($sibling_module == $module && $sibling_topic == $topic) {
+ $found = TRUE;
+ continue;
+ }
+ $prev = $sibling;
+ }
+
+ // Bottom navigation links.
+ if ($prev || $up || $next) {
+ $navigation = '';
+
+ if ($prev) {
+ $navigation .= help_l('<< ' . $topics[$prev[0]][$prev[1]]['title'], "admin/help/$prev[0]/$prev[1]", array('attributes' => array('class' => 'help-left')));
+ }
+ if ($up) {
+ $navigation .= help_l(t('Up'), $up, array('attributes' => array('class' => $prev ? 'help-up' : 'help-up-noleft')));
+ }
+ if ($next) {
+ $navigation .= help_l($topics[$next[0]][$next[1]]['title'] . ' >>', "admin/help/$next[0]/$next[1]", array('attributes' => array('class' => 'help-right')));
+ }
+
+ $navigation .= '
';
+
+ $output .= $navigation;
+ }
+ }
+
+ if (!empty($info['css'])) {
+ drupal_add_css($info['path'] . '/' . $info['css']);
+ }
+
+ return '' . $output . '
';
}
- return $output;
}
-function help_links_as_list() {
- $empty_arg = drupal_help_arg();
- $module_info = module_rebuild_cache();
-
- $modules = array();
- foreach (module_implements('help', TRUE) as $module) {
- if (module_invoke($module, 'help', "admin/help#$module", $empty_arg)) {
- $modules[$module] = $module_info[$module]->info['name'];
- }
- }
- asort($modules);
-
- // Output pretty four-column list
- $count = count($modules);
- $break = ceil($count / 4);
- $output = '';
- $i = 0;
- foreach ($modules as $module => $name) {
- $output .= '' . l($name, 'admin/help/' . $module) . ' ';
- if (($i + 1) % $break == 0 && ($i + 1) != $count) {
- $output .= ' ';
+/**
+ * Build a tree of help topics.
+ */
+function help_get_tree($topics, $topic_ids, $tree_parents = array(), $max_depth = -1, $depth = 0) {
+ $items = array();
+
+ if (!empty($topic_ids)) {
+ uasort($topic_ids, '_help_uasort');
+ foreach ($topic_ids as $info) {
+ list($module, $topic) = $info;
+ $item = help_l($topics[$module][$topic]['title'], "admin/help/$module/$topic");
+ if (!empty($tree_parents) && $topic == end($tree_parents)) {
+ $children = !empty($topics[$module][$topic]['children']) ? $topics[$module][$topic]['children'] : array();
+ $item .= theme('item_list', help_get_tree($topics, $children, $tree_parents, $max_depth, $depth + 1));
+ }
+ elseif (empty($tree_parents) && !empty($topics[$module][$topic]['children']) && ($max_depth == -1 || $depth < $max_depth)) {
+ $item .= theme('item_list', help_get_tree($topics, $topics[$module][$topic]['children'], $tree_parents, $max_depth, $depth + 1));
+ }
+
+ $items[] = $item;
}
- $i++;
}
- $output .= ' ';
- return $output;
+ return $items;
}
+/**
+ * Build a hierarchy for a single module's topics.
+ */
+function help_get_topic_hierarchy(&$topics) {
+ foreach ($topics as $module => $module_topics) {
+ foreach ($module_topics as $topic => $info) {
+ $parent_module = $module;
+ // We have a blank topic that we don't want parented to
+ // itself.
+ if (!$topic) {
+ continue;
+ }
+
+ if (empty($info['parent'])) {
+ $parent = '';
+ }
+ elseif (strpos($info['parent'], '%')) {
+ list($parent_module, $parent) = explode('%', $info['parent']);
+ if (empty($topics[$parent_module][$parent])) {
+ // If it doesn't exist, top level.
+ $parent = '';
+ }
+ }
+ else {
+ $parent = $info['parent'];
+ if (empty($module_topics[$parent])) {
+ // If it doesn't exist, top level.
+ $parent = '';
+ }
+ }
+
+ if (!isset($topics[$parent_module][$parent]['children'])) {
+ $topics[$parent_module][$parent]['children'] = array();
+ }
+ $topics[$parent_module][$parent]['children'][] = array($module, $topic);
+ $topics[$module][$topic]['_parent'] = array($parent_module, $parent);
+ }
+ }
+}
+
+/**
+ * Get the information for a single help topic.
+ */
+function help_get_topic_info($module, $topic) {
+ $topics = help_get_topics();
+ if (!empty($topics[$module][$topic])) {
+ return $topics[$module][$topic];
+ }
+}
+
+/**
+ * Helper function to check for existence of default help file.
+ */
+function _help_check_default_file(&$info, $module, &$path) {
+ if (isset($path) && !isset($info['about']) && file_exists("$path/about.html")) {
+ $info['about'] = array(
+ 'title' => t('About @module', array('@module' => help_get_module_name($module))),
+ 'file' => 'about',
+ 'weight' => -20,
+ );
+ }
+ elseif (!isset($info) && !isset($path)) {
+ $info = array();
+ $module_path = drupal_get_path('module', $module);
+ if (file_exists("$module_path/help/about.html")) {
+ $path = "$module_path/help";
+ _help_check_default_file($info, $module, $path);
+ }
+ }
+}
+
+/**
+ * Search the system for all available help topics.
+ */
+function help_get_topics() {
+ $cache = _help_parse_ini();
+ return $cache['topics'];
+}
+
+/**
+ * Retrieve settings for help topics.
+ */
+function help_get_settings() {
+ $cache = _help_parse_ini();
+ return $cache['settings'];
+}
+
+/**
+ * Parse data in help definition file.
+ */
+function _help_parse_ini() {
+ static $cache = NULL;
+
+ if (!isset($cache)) {
+ $cache = array('topics' => array(), 'settings' => array());
+
+ $topics = array();
+
+ foreach (module_list() as $module) {
+ $module_path = drupal_get_path('module', $module);
+ $info = array();
+ $path = '';
+ if (file_exists("$module_path/help/$module.help")) {
+ $path = "$module_path/help";
+ $info = parse_ini_file("./$module_path/help/$module.help", TRUE);
+ _help_check_default_file($info, $module, $path);
+ }
+ else {
+ _help_check_default_file($info, $module, $path);
+ }
+
+ if (!empty($info)) {
+ global $language;
+ $translation = array();
+
+ // Get translated titles.
+ if (file_exists("$module_path/translations/help/$language->language/$module.help")) {
+ $translation = drupal_parse_info_file("$module_path/translations/help/$language->language/$module.help", TRUE);
+ }
+ $cache['settings'][$module] = array();
+ if (!empty($info['help settings'])) {
+ $cache['settings'][$module] = $info['help settings'];
+ unset($info['help settings']);
+
+ // Check translated strings for translatable global settings.
+ if (isset($translation['help settings']['name'])) {
+ $cache['settings']['name'] = $translation['help settings']['name'];
+ }
+ if (isset($translation['help settings']['index name'])) {
+ $cache['settings']['index name'] = $translation['help settings']['index name'];
+ }
+ }
+
+ foreach ($info as $name => $topic) {
+ // Each topic should have a name, a title, a file and of course the path.
+ $file = !empty($topic['file']) ? $topic['file'] : $name;
+ $cache['topics'][$module][$name] = array(
+ 'name' => $name,
+ 'title' => !empty($translation[$name]['title']) ? $translation[$name]['title'] : $topic['title'],
+ 'weight' => isset($topic['weight']) ? $topic['weight'] : 0,
+ 'parent' => isset($topic['parent']) ? $topic['parent'] : 0,
+ 'file' => $file . '.html', // require extension
+ 'path' => $path, // not in .ini file
+ 'line break' => isset($topic['line break']) ? $topic['line break'] : (isset($cache['settings'][$module]['line break']) ? $cache['settings'][$module]['line break'] : FALSE),
+ 'navigation' => isset($topic['navigation']) ? $topic['navigation'] : (isset($cache['settings'][$module]['navigation']) ? $cache['settings'][$module]['navigation'] : TRUE),
+ 'css' => isset($topic['css']) ? $topic['css'] : (isset($cache['settings'][$module]['css']) ? $cache['settings'][$module]['css'] : NULL),
+ );
+ }
+ }
+ $path = '';
+ $info = array();
+ }
+ // Allow modules to alter data using hook_help_topic_info_alter().
+ drupal_alter('help_topic_info', $cache);
+ }
+
+ return $cache;
+}
+
+/**
+ * Sort topic information array in ascending order.
+ */
+function _help_uasort($id_a, $id_b) {
+ $topics = help_get_topics();
+
+ list($module_a, $topic_a) = $id_a;
+ $a = $topics[$module_a][$topic_a];
+
+ list($module_b, $topic_b) = $id_b;
+ $b = $topics[$module_b][$topic_b];
+
+ $a_weight = isset($a['weight']) ? $a['weight'] : 0;
+ $b_weight = isset($b['weight']) ? $b['weight'] : 0;
+ // Sort by topic weight when weights are unequal.
+ if ($a_weight != $b_weight) {
+ return ($a_weight < $b_weight) ? -1 : 1;
+ }
+
+ // Otherwise sort by the title.
+ if ($a['title'] != $b['title']) {
+ return ($a['title'] < $b['title']) ? -1 : 1;
+ }
+ return 0;
+}
+
+/**
+ * Return help topic filename.
+ */
+function help_get_topic_filename($module, $topic) {
+ $info = help_get_topic_file_info($module, $topic);
+ if ($info) {
+ return "./$info[path]/$info[file]";
+ }
+}
+
+/**
+ * Return information about the help topic file.
+ *
+ * This function checks a list of possible locations for a help topic file,
+ * allowing translations and the current theme to override the default location of the file.
+ *
+ */
+function help_get_topic_file_info($module, $topic) {
+ init_theme();
+ global $language;
+
+ $info = help_get_topic_info($module, $topic);
+ if (empty($info)) {
+ return;
+ }
+
+ // Search paths:
+ $paths = array(
+ path_to_theme() . '/help', // Allow theme override.
+ drupal_get_path('module', $module) . "/translations/help/$language->language", // Translations.
+ $info['path'], // In same directory as .inc file.
+ );
+
+ foreach ($paths as $path) {
+ if (file_exists("./$path/$info[file]")) {
+ return array('path' => $path, 'file' => $info['file']);
+ }
+ }
+}
+
+/**
+ * Helper function to get a module's proper name.
+ */
+function help_get_module_name($module) {
+ $settings = help_get_settings();
+ if (isset($settings[$module]['name'])) {
+ $name = $settings[$module]['name'];
+ }
+ else {
+ $info = db_fetch_object(db_query("SELECT * FROM {system} WHERE name = :name", array(':name' => $module)));
+ $info = unserialize($info->info);
+ $name = t($info['name']);
+ }
+ return $name;
+}
+
+/**
+ * Format a link but preserve popup identity.
+ */
+function help_l($text, $dest, $options = array()) {
+ if (!empty($_GET['popup'])) {
+ if (empty($options['query'])) {
+ $options['query'] = array();
+ }
+
+ if (is_array($options['query'])) {
+ $options['query'] += array('popup' => TRUE);
+ }
+ else {
+ $options['query'] += '&popup=1';
+ }
+ }
+
+ return l($text, $dest, $options);
+}
+
+/**
+ * Format a URL but preserve popup identity.
+ */
+function help_url($dest, $options = array()) {
+ if (!empty($_GET['popup'])) {
+ if (empty($options['query'])) {
+ $options['query'] = array();
+ }
+
+ $options['query'] += array('popup' => TRUE);
+ }
+
+ return url($dest, $options);
+}
+
+/**
+ * Fill in a bunch of page variables for our specialized popup page.
+ */
+function template_preprocess_help_popup(&$variables) {
+ // Add favicon.
+ if (theme_get_setting('toggle_favicon')) {
+ drupal_set_html_head(' ');
+ }
+
+ global $theme;
+ // Construct page title.
+ if (drupal_get_title()) {
+ $head_title = array(strip_tags(drupal_get_title()), variable_get('site_name', 'Drupal'));
+ }
+ else {
+ $head_title = array(variable_get('site_name', 'Drupal'));
+ if (variable_get('site_slogan', '')) {
+ $head_title[] = variable_get('site_slogan', '');
+ }
+ }
+
+ $module_path = drupal_get_path('module', 'help');
+ drupal_add_css($module_path . '/help-popup.css');
+ drupal_add_css($module_path . '/help.css');
+
+ $variables['head_title'] = implode(' | ', $head_title);
+ $variables['base_path'] = base_path();
+ $variables['front_page'] = url();
+ $variables['breadcrumb'] = theme('breadcrumb', drupal_get_breadcrumb());
+ $variables['feed_icons'] = drupal_get_feeds();
+ $variables['head'] = drupal_get_html_head();
+ $variables['language'] = $GLOBALS['language'];
+ $variables['language']->dir = $GLOBALS['language']->direction ? 'rtl' : 'ltr';
+ $variables['logo'] = theme_get_setting('logo');
+ $variables['messages'] = theme('status_messages');
+ $variables['site_name'] = (theme_get_setting('toggle_name') ? variable_get('site_name', 'Drupal') : '');
+ $variables['css'] = drupal_add_css();
+ $css = drupal_add_css();
+
+ // Remove theme css.
+ foreach ($css as $media => $types) {
+ if (isset($css[$media]['theme'])) {
+ $css[$media]['theme'] = array();
+ }
+ }
+
+ $variables['styles'] = drupal_get_css($css);
+ $variables['scripts'] = drupal_get_js();
+ $variables['title'] = drupal_get_title();
+ // Closure should be filled last.
+ $variables['closure'] = theme('closure');
+}
Index: modules/help/help.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/help/help.css,v
retrieving revision 1.2
diff -u -p -r1.2 help.css
--- modules/help/help.css 27 May 2007 17:57:48 -0000 1.2
+++ modules/help/help.css 9 Jan 2009 00:07:49 -0000
@@ -5,6 +5,84 @@
width: 22%;
padding-right: 3%; /* LTR */
}
+
.help-items-last {
padding-right: 0; /* LTR */
}
+
+.help-topic h3,
+.help-topic h4,
+.help-topic h5,
+.help-topic h6,
+.help-topic dt {
+ font-weight: bold;
+}
+
+.help-topic li h3,
+.help-topic li h4,
+.help-topic li h5,
+.help-topic li h6 {
+ font-weight: normal;
+}
+
+.help-topic code,
+.help-topic pre {
+ background: #f1f1f1;
+ border: 1px solid #444;
+ display: block;
+ margin: 1em;
+ padding: .2em;
+}
+
+.help-topic .toc-block {
+ background-color: #EDF5FA;
+ border: 1px solid #D0EBFF;
+ float: right; /* LTR */
+ margin: 5px;
+ padding: 5px;
+}
+
+.help-left {
+ display: block;
+ float: left; /* LTR */
+ text-align: left;
+ width: 42%;
+}
+
+.help-right {
+ display: block;
+ float: right; /* LTR */
+ text-align: right;
+ width: 42%;
+}
+
+.help-up {
+ display: block;
+ float: left; /* LTR */
+ margin: 0 5%;
+ width: 4%;
+}
+
+.help-up-noleft {
+ display: block;
+ float: left; /* LTR */
+ margin: 0 5%;
+ text-align: right;
+ width: 42%;
+}
+
+.help-box {
+ margin: .5em;
+}
+
+.help-navigation {
+ border-top: 1px dotted #ccc;
+}
+
+.help-previous {
+ float: left; /* LTR */
+}
+
+.help-next {
+ float: right; /* LTR */
+}
Index: modules/help/help.info
===================================================================
RCS file: /cvs/drupal/drupal/modules/help/help.info,v
retrieving revision 1.7
diff -u -p -r1.7 help.info
--- modules/help/help.info 11 Oct 2008 02:32:47 -0000 1.7
+++ modules/help/help.info 9 Jan 2009 00:07:49 -0000
@@ -1,6 +1,6 @@
; $Id: help.info,v 1.7 2008/10/11 02:32:47 webchick Exp $
name = Help
-description = Manages the display of online help.
+description = Manages the display of help topics.
package = Core
version = VERSION
core = 7.x
Index: modules/help/help.js
===================================================================
RCS file: modules/help/help.js
diff -N modules/help/help.js
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/help/help.js 9 Jan 2009 00:07:49 -0000
@@ -0,0 +1,11 @@
+// $Id: $
+
+Drupal.behaviors.help = {
+ attach: function() {
+ $('a.help-link-popup').bind('click', function() {
+ var url = this.href + (this.href.indexOf('?') != -1 ? '&' : '?') + "popup=1";
+ window.open(url, 'help_window', 'width=600,height=550,scrollbars,resizable').focus();
+ return false;
+ });
+ }
+};
\ No newline at end of file
Index: modules/help/help.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/help/help.module,v
retrieving revision 1.81
diff -u -p -r1.81 help.module
--- modules/help/help.module 6 May 2008 12:18:47 -0000 1.81
+++ modules/help/help.module 9 Jan 2009 00:07:49 -0000
@@ -3,29 +3,58 @@
/**
* @file
- * Manages displaying online help.
+ * Manages displaying help topics.
*/
/**
+ * Implementation of hook_perm().
+ */
+function help_perm() {
+ return array('access help' =>
+ array(
+ 'title' => 'Access help',
+ 'description' => t('View help content.'),
+ )
+ );
+}
+
+/**
+ * Implementation of hook_theme().
+ */
+function help_theme() {
+ return array(
+ 'help_popup' => array(
+ 'arguments' => array('content' => NULL),
+ 'template' => 'help-popup',
+ 'file' => 'help.admin.inc',
+ ),
+ );
+}
+
+/**
* Implementation of hook_menu().
*/
function help_menu() {
+ $items = array();
+
$items['admin/help'] = array(
'title' => 'Help',
- 'page callback' => 'help_main',
- 'access arguments' => array('access administration pages'),
+ 'page callback' => 'help_by_module',
+ 'access arguments' => array('access help'),
'weight' => 9,
);
-
- foreach (module_implements('help', TRUE) as $module) {
- $items['admin/help/' . $module] = array(
- 'title' => $module,
- 'page callback' => 'help_page',
- 'page arguments' => array(2),
- 'access arguments' => array('access administration pages'),
- 'type' => MENU_CALLBACK,
- );
- }
+ $items['admin/help/%'] = array(
+ 'page callback' => 'help_topic_page',
+ 'page arguments' => array(2),
+ 'access arguments' => array('access help'),
+ 'type' => MENU_CALLBACK,
+ );
+ $items['admin/help/%/%'] = array(
+ 'page callback' => 'help_topic_page',
+ 'page arguments' => array(2, 3),
+ 'access arguments' => array('access help'),
+ 'type' => MENU_CALLBACK,
+ );
return $items;
}
@@ -36,11 +65,58 @@ function help_menu() {
function help_help($path, $arg) {
switch ($path) {
case 'admin/help':
- $output = '' . t('This guide provides context sensitive help on the use and configuration of Drupal and its modules, and is a supplement to the more extensive online Drupal handbook . The online handbook may contain more up-to-date information, is annotated with helpful user-contributed comments, and serves as the definitive reference point for all Drupal documentation.', array('@drupal' => 'http://drupal.org', '@handbook' => 'http://drupal.org/handbook')) . '
';
- return $output;
- case 'admin/help#help':
- $output = '' . t('The help module provides context sensitive help on the use and configuration of Drupal and its modules, and is a supplement to the more extensive online Drupal handbook . The online handbook may contain more up-to-date information, is annotated with helpful user-contributed comments, and serves as the definitive reference point for all Drupal documentation.', array('@drupal' => 'http://drupal.org', '@handbook' => 'http://drupal.org/handbook')) . '
';
- $output .= '' . t('For more information, see the online handbook entry for Help module .', array('@help' => 'http://drupal.org/handbook/modules/help/')) . '
';
- return $output;
+ return '' . t('This guide provides context sensitive help on the use and configuration of Drupal and its modules, and is a supplement to the more extensive online Drupal handbook . The online handbook may contain more up-to-date information, is annotated with helpful user-contributed comments, and serves as the definitive reference point for all Drupal documentation.', array('@drupal' => 'http://drupal.org', '@handbook' => 'http://drupal.org/handbook')) . '
';
}
}
+
+/**
+ * Return code that emits a link to view a topic in a popup.
+ *
+ * @param $module
+ * The module that owns this help topic.
+ * @param $topic
+ * Optional identifier for the topic. NULL value displays all available topics.
+ * @param $title
+ * Optional title or label for the link. Default is "More help".
+ * @param $popup
+ * Optional boolean value to open the link in a popup.
+ * @param $attributes
+ * An array of attributes to include in hyperlink.
+ */
+function theme_help_link($module, $topic = NULL, $title = NULL, $popup = TRUE, $attributes = array()) {
+ static $js_added = FALSE;
+
+ if (!isset($title)) {
+ $title = t('More help');
+ }
+
+ if ($popup) {
+ // Set class for links to be opened in popup.
+ $popup_class = !empty($attributes['class']) ? $attributes['class'] . ' help-link-popup' : 'help-link-popup';
+ $attributes += array('class' => $popup_class);
+ }
+
+ // Check for the function existence and include help.admin.inc.
+ drupal_function_exists('help_get_topic_info');
+ // Fetch the information on the module/topic.
+ $info = help_get_topic_info($module, $topic);
+
+ if (isset($topic) && !$info) {
+ // Return if the explicitly specified topic doesn't exist.
+ return;
+ }
+
+ // Set the topic title as the hyperlink's title attribute.
+ $attributes += array('title' => $info['title']);
+
+ if (!$js_added) {
+ // Include JavaScript for opening topics in a popup for hyperlinks with the class 'help-link-popup'.
+ drupal_add_js('modules/help/help.js');
+ $js_added = TRUE;
+ }
+
+ // Trim the trailing slash if no topic is specified.
+ $output = l($title, trim("admin/help/$module/$topic", '/'), array('attributes' => $attributes));
+
+ return '' . $output . '
';
+}
Index: modules/help/help.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/help/help.test,v
retrieving revision 1.4
diff -u -p -r1.4 help.test
--- modules/help/help.test 11 Dec 2008 20:35:37 -0000 1.4
+++ modules/help/help.test 9 Jan 2009 00:07:49 -0000
@@ -8,7 +8,7 @@ class HelpTestCase extends DrupalWebTest
function getInfo() {
return array(
'name' => t('Help functionality'),
- 'description' => t('Verify help display and user access to help based on persmissions.'),
+ 'description' => t('Verify help display and user access to help based on permissions.'),
'group' => t('Help'),
);
}
@@ -19,13 +19,10 @@ class HelpTestCase extends DrupalWebTest
function setUp() {
parent::setUp();
- // Loading these (and other?) modules will result in failures?
-// $this->drupalModuleEnable('blog');
-// $this->drupalModuleEnable('poll');
$this->getModuleList();
// Create users.
- $this->big_user = $this->drupalCreateUser(array('access administration pages')); // 'administer blocks', 'administer site configuration',
+ $this->big_user = $this->drupalCreateUser(array('access administration pages', 'access help')); // 'administer blocks', 'administer site configuration',
$this->any_user = $this->drupalCreateUser(array());
}
@@ -35,15 +32,38 @@ class HelpTestCase extends DrupalWebTest
function testHelp() {
// Login the admin user.
$this->drupalLogin($this->big_user);
+ $this->verifyHelpPopup();
$this->verifyHelp();
// Login the regular user.
$this->drupalLogin($this->any_user);
+ $this->verifyHelpPopup(403);
$this->verifyHelp(403);
}
/**
- * Verify the logged in user has the desired access to the various help nodes and the nodes display help.
+ * Verify the logged in user has the desired access to the help popup and the popup displays help.
+ *
+ * @param integer $response HTTP response code.
+ */
+ private function verifyHelpPopup($response = 200) {
+ $crumb = '›';
+
+ foreach ($this->modules as $module => $name) {
+ // View module help node.
+ $this->drupalGet('admin/help/' . $module, array('query' => array('popup' => TRUE)));
+ $this->assertResponse($response);
+ if ($response == 200) {
+ drupal_set_message('' . print_r($this, true) . ' ');
+ $this->assertTitle('About ' . $name, t('[' . $module . '] Popup title was displayed'));
+ $this->assertRaw('About ' . t($name) . ' ', t('[' . $module . '] Popup heading was displayed'));
+ $this->assertText(t('Help ' . $crumb . ' ' . $name), t('[' . $module . '] Popup breadcrumbs were displayed'));
+ }
+ }
+ }
+
+ /**
+ * Verify the logged in user has the desired access to the various help pages and the pages display help.
*
* @param integer $response HTTP response code.
*/
@@ -55,13 +75,9 @@ class HelpTestCase extends DrupalWebTest
$this->drupalGet('admin/help/' . $module);
$this->assertResponse($response);
if ($response == 200) {
- // NOTE: The asserts fail on blog and poll because the get returns the 'admin/help' node instead of the indicated node???
-// if ($module == 'blog' || $module == 'poll') {
-// continue;
-// }
- $this->assertTitle($name . ' | Drupal', t('[' . $module . '] Title was displayed'));
- $this->assertRaw('' . t($name) . ' ', t('[' . $module . '] Heading was displayed'));
- $this->assertText(t('Home ' . $crumb . ' Administer ' . $crumb . ' Help'), t('[' . $module . '] Breadcrumbs were displayed'));
+ $this->assertTitle('About ' . $name . ' | Drupal', t('[' . $module . '] Title was displayed'));
+ $this->assertRaw('About ' . t($name) . ' ', t('[' . $module . '] Heading was displayed'));
+ $this->assertText(t('Home ' . $crumb . ' Administer ' . $crumb . ' Help ' . $crumb . ' ' . $name), t('[' . $module . '] Breadcrumbs were displayed'));
}
}
}
Index: modules/system/system.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v
retrieving revision 1.112
diff -u -p -r1.112 system.admin.inc
--- modules/system/system.admin.inc 6 Jan 2009 13:33:06 -0000 1.112
+++ modules/system/system.admin.inc 9 Jan 2009 00:07:52 -0000
@@ -85,10 +85,8 @@ function system_admin_menu_block_page()
* Menu callback; prints a listing of admin tasks for each installed module.
*/
function system_admin_by_module() {
-
$modules = module_rebuild_cache();
$menu_items = array();
- $help_arg = module_exists('help') ? drupal_help_arg() : FALSE;
foreach ($modules as $file) {
$module = $file->name;
@@ -101,8 +99,8 @@ function system_admin_by_module() {
// Only display a section if there are any available tasks.
if (count($admin_tasks)) {
- // Check for help links.
- if ($help_arg && module_invoke($module, 'help', "admin/help#$module", $help_arg)) {
+ // Check for help topics.
+ if (help_exists($module)) {
$admin_tasks[100] = l(t('Get help'), "admin/help/$module");
}
@@ -634,9 +632,6 @@ function system_modules($form_state = ar
$modules = array();
$form['modules'] = array('#tree' => TRUE);
- // Used when checking if module implements a help page.
- $help_arg = module_exists('help') ? drupal_help_arg() : FALSE;
-
// Iterate through each of the modules.
foreach ($files as $filename => $module) {
$extra = array();
@@ -656,12 +651,10 @@ function system_modules($form_state = ar
}
}
}
- // Generate link for module's help page, if there is one.
- if ($help_arg && $module->status && in_array($filename, module_implements('help'))) {
- if (module_invoke($filename, 'help', "admin/help#$filename", $help_arg)) {
- // Module has a help page.
- $extra['help'] = theme('more_help_link', url("admin/help/$filename"));
- }
+ // Generate link for module's help topics, if there are any .
+ if (help_exists($filename)) {
+ // Module has help topics.
+ $extra['help'] = theme('help_link', $filename, NULL, t('Get help'));
}
// Mark dependents disabled so user can not remove modules being depended on.
$dependents = array();
@@ -777,7 +770,7 @@ function _system_modules_build_row($info
$form['description']['#markup'] .= theme('system_modules_incompatible', $status_long);
}
- // Show a "more help" link for modules that have them.
+ // Show a help link for modules that have them.
if ($extra['help']) {
$form['help'] = array(
'#markup' => $extra['help'],