diff --git a/includes/common.inc b/includes/common.inc
index e380270..456cff6 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -3525,6 +3525,21 @@ function element_children(&$elements, $sort = FALSE) {
}
/**
+ * Determine whether help topics for a given module exist.
+ *
+ * @param $module
+ * The module name.
+ * @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() {
@@ -3596,9 +3611,9 @@ function drupal_common_theme() {
'list' => array(
'arguments' => array('elements' => NULL),
),
- 'more_help_link' => array(
- 'arguments' => array('url' => NULL),
- ),
+ 'help_link' => array(
+ 'arguments' => array('module' => NULL, 'topic' => NULL, 'title' => NULL, 'attributes' => NULL),
+ ),
'xml_icon' => array(
'arguments' => array('url' => NULL),
),
diff --git a/includes/menu.inc b/includes/menu.inc
index 9d50428..62cd96e 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -1299,10 +1299,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;
diff --git a/includes/theme.inc b/includes/theme.inc
index fd28cd1..0c43e3b 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -1590,13 +1590,6 @@ function theme_list($elements) {
}
/**
- * 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().
diff --git a/modules/blog/blog.test b/modules/blog/blog.test
index e8dd6dd..9b986b1 100644
--- a/modules/blog/blog.test
+++ b/modules/blog/blog.test
@@ -91,15 +91,6 @@ class BlogTestCase extends DrupalWebTestCase {
$response2 = ($admin) ? 200 : 403;
- // View blog help node.
- $this->drupalGet('admin/help/blog');
- $this->assertResponse($response2);
- if ($response2 == 200) {
- $this->assertTitle(t('Blog | Drupal'), t('Blog help node was displayed'));
- $this->assertText(t('Blog'), t('Blog help node was displayed'));
- $this->assertText(t('Home ' . $crumb . ' Administer ' . $crumb . ' Help'), t('Breadcrumbs were displayed'));
- }
-
// Verify the blog block was displayed.
$this->drupalGet('');
$this->assertResponse(200);
diff --git a/modules/dblog/dblog.test b/modules/dblog/dblog.test
index 1a15f30..4abd3a0 100644
--- a/modules/dblog/dblog.test
+++ b/modules/dblog/dblog.test
@@ -118,13 +118,6 @@ class DBLogTestCase extends DrupalWebTestCase {
private function verifyReports($response = 200) {
$quote = ''';
- // View dblog help node.
- $this->drupalGet('admin/help/dblog');
- $this->assertResponse($response);
- if ($response == 200) {
- $this->assertText(t('Database logging'), t('DBLog help was displayed'));
- }
-
// View dblog report node.
$this->drupalGet('admin/reports/dblog');
$this->assertResponse($response);
diff --git a/modules/forum/forum.test b/modules/forum/forum.test
index 2213a10..13ff613 100644
--- a/modules/forum/forum.test
+++ b/modules/forum/forum.test
@@ -279,15 +279,6 @@ class ForumTestCase extends DrupalWebTestCase {
$response2 = ($admin) ? 200 : 403;
- // View forum help node.
- $this->drupalGet('admin/help/forum');
- $this->assertResponse($response2);
- if ($response2 == 200) {
- $this->assertTitle(t('Forum | Drupal'), t('Forum help node was displayed'));
- $this->assertText(t('Forum'), t('Forum help node was displayed'));
- $this->assertText(t('Home ' . $crumb . ' Administer ' . $crumb . ' Help'), t('Breadcrumbs were displayed'));
- }
-
// Verify the forum blocks were displayed.
$this->drupalGet('');
$this->assertResponse(200);
diff --git a/modules/help/help-rtl.css b/modules/help/help-rtl.css
index e7162b8..858a9f8 100644
--- a/modules/help/help-rtl.css
+++ b/modules/help/help-rtl.css
@@ -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;
+}
\ No newline at end of file
diff --git a/modules/help/help.admin.inc b/modules/help/help.admin.inc
index 2d631b2..485b9b7 100644
--- a/modules/help/help.admin.inc
+++ b/modules/help/help.admin.inc
@@ -3,74 +3,677 @@
/**
* @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 for the help overview page.
+ *
+ * @return
+ * 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);
+ }
+
+ drupal_add_css(drupal_get_path('module', 'help') . '/help.css');
+ return theme('system_admin_by_module', $menu_items);
+}
+
+/**
+ * Menu callback. Returns a page with help topics for a module.
+ *
+ * @param $module
+ * The module that owns this help topic page.
+ * @param $topic
+ * Optional identifier for the topic, or NULL to display an index of available topics.
+ *
+ * @return
+ * Themed output of a help topic page.
+ */
+function help_topic_page($module, $topic = NULL) {
+ drupal_add_css(drupal_get_path('module', 'help') . '/help.css');
+
+ $info = help_get_topic_info($module, $topic);
+ if (isset($topic) && !$info) {
+ // Return error 404 if the topic does not exist.
+ return drupal_not_found();
+ }
+
+ 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;
+ }
+
+ // Add the current topic to the breadcrumb.
+ $breadcrumb[] = help_l($parent['title'], "admin/help/$parent_module/$parent_topic");
+ }
+
+ $output = help_view_topic($module, $topic);
+ if (empty($output)) {
+ $output = help_view_module($module);
+ drupal_set_title(t('@module', array('@module' => help_get_module_name($module))));
+ }
+ else {
+ $breadcrumb[] = help_l(help_get_module_name($parent_module), "admin/help/$parent_module");
+ }
+
+ $breadcrumb[] = help_l(t('Help'), "admin/help");
+ $breadcrumb[] = help_l(t('Administer'), 'admin');
+ $breadcrumb[] = l(t('Home'), '');
+
+ drupal_set_breadcrumb(array_reverse($breadcrumb));
+
return $output;
}
/**
- * Menu callback; prints a page listing general help for a module.
+ * Load and render a help topics listing.
+ *
+ * @param $module
+ * The module name of the topics to list.
+ *
+ * @return
+ * Themed output of links to help topics.
*/
-function help_page($name) {
+function help_view_module($module) {
$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 topic on this subject is available.');
+ }
+
+ return $output;
+ }
+
+/**
+ * Load and render a help topic.
+ *
+ * @param $module
+ * The module that owns this help topic.
+ * @param $topic
+ * The topic to render.
+ *
+ * @return
+ * Themed output of the help topic.
+ */
+function help_view_topic($module, $topic) {
+ $file_info = help_get_topic_file_info($module, $topic);
+ if (!$file_info) {
+ return;
+ }
+
+ $info = help_get_topic_info($module, $topic);
+ $file = './' . $file_info['path'] . '/' . $file_info['file'];
+ $content = 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.
+ $content = preg_replace('/\[topic:([^"]+)\]/', strtr(url('admin/help/$1'), array('%24' => '$')), $content);
+
+ global $base_path;
+
+ // Change '[url:X]' to the URL to the site.
+ $content = preg_replace('/\[url:([^"]+)\]/', strtr(url('$1'), array('%24' => '$')), $content);
+
+ // Change '[path]' to the URL to the base help directory.
+ $content = str_replace('[path]', $base_path . $info['path'] . '/', $content);
+
+ // Change '[trans_path]' to the URL to the actual help directory.
+ $content = str_replace('[trans_path]', $base_path . $file_info['path'] . '/', $content);
+
+ // Change '[base_url]' to the URL to the site.
+ $content = str_replace('[base_url]', $base_path, $content);
+
+ // Run the line break filter if requested.
+ if (!empty($info['line break'])) {
+ // Remove the header since it adds an extra
to the filter.
+ $content = preg_replace('/^\n/', '', $content);
+ // This calls the line break filter.
+ $content = filter_filter('process', 1, -1, $content);
+ }
+
+ $navigation = $children = $links = array();
+
+ 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) {
+ // Pass on the table of contents block to display links to parent and sibling topics.
+ $navigation = $items;
+ }
+ }
+
+ if (!empty($topics[$module][$topic]['children'])) {
+ // Pass on an ordered list to display links to immediate children.
+ $children = help_get_tree($topics, $topics[$module][$topic]['children']);
+ }
+
+ // 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]";
}
else {
- $output .= $temp;
+ $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;
}
- // 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'])));
+ // Bottom navigation links.
+ if ($prev || $up || $next) {
+ if ($prev) {
+ $links[] = array(
+ 'title' => '« ' . $topics[$prev[0]][$prev[1]]['title'],
+ 'href' => "admin/help/$prev[0]/$prev[1]",
+ 'attributes' => array('class' => 'help-left')
+ );
+ }
+ if ($up) {
+ $links[] = array(
+ 'title' => t('Up'),
+ 'href' => $up,
+ 'attributes' => array('class' => $prev ? 'help-up' : 'help-up-noleft'),
+ );
+ }
+ if ($next) {
+ $links[] = array(
+ 'title' => $topics[$next[0]][$next[1]]['title'] . ' »',
+ 'href' => "admin/help/$next[0]/$next[1]",
+ 'attributes' => array('class' => 'help-right'),
+ );
+ }
}
+ }
+ if (!empty($info['css'])) {
+ drupal_add_css($info['path'] . '/' . $info['css']);
+ }
+
+ return theme('help_topic', $content, $navigation, $children, $links);
+}
+
+/**
+ * Theme a help topic.
+ *
+ * @param $content
+ * The main help content.
+ * @param $navigation
+ * Array of entries for the floating navigation block.
+ * @param $children
+ * Array of links to the immediate children of the topic.
+ * @param $links
+ * Array of links for next, up, and previous topics.
+ */
+function theme_help_topic($content = '', $navigation = array(), $children = array(), $links = array()) {
+ $output = '';
+ // Render navigation block.
+ if (!empty($navigation)) {
+ $output .= theme('item_list', $navigation, NULL, 'ul', array('class' => 'toc-block'));
+ }
+ // Add main content.
+ $output .= $content;
+ // Render children links.
+ if (!empty($children)) {
+ $output .= theme('item_list', $children, NULL, 'ul', array('class' => 'toc'));
}
+ // Render next, up, previous links.
+ if (!empty($links)) {
+ $output .= '
';
+ foreach ($links as $link) {
+ $output .= l($link['title'], $link['href'], $link);
+ }
+ $output .= '
';
+ }
+
+ $output .= '
';
+
return $output;
}
-function help_links_as_list() {
- $empty_arg = drupal_help_arg();
- $module_info = module_rebuild_cache();
+/**
+ * Build a tree of help topics.
+ *
+ * @param $topics
+ * An array of topics.
+ * @param $topic_ids
+ * An array of child topic_ids.
+ * @param $tree_parents
+ *
+ * @param $max_depth
+ * The maximum depth of children.
+ * @param $depth
+ * The current depth.
+ *
+ * @return
+ * An array of 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;
+ }
+ }
+
+ return $items;
+ }
+
+/**
+ * Build a hierarchy for a single module's topics.
+ *
+ * @param topics
+ * Array of modules 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 this item's parent is unavailable,
+ // treat it as top level instead.
+ $parent = '';
+ }
+ }
+ else {
+ $parent = $info['parent'];
+ if (empty($module_topics[$parent])) {
+ // If this item's parent is unavailable,
+ // treat it as top level instead.
+ $parent = '';
+ }
+ }
- $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'];
+ 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);
}
}
- asort($modules);
+}
+
+/**
+ * Get the information for a single help topic.
+ *
+ * @param $module
+ * Module name of the topic.
+ * @param $topic
+ * Topic to retrieve.
+ *
+ * @return
+ * An array of the topics information, or NULL if the topic doesn't exist.
+ */
+function help_get_topic_info($module, $topic) {
+ $topics = help_get_topics();
+ if (!empty($topics[$module][$topic])) {
+ return $topics[$module][$topic];
+ }
+}
- // 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 .= '
';
+/**
+ * Search the system for all available help topics.
+ *
+ * @return
+ * An array of the topics information.
+ */
+function help_get_topics() {
+ $cache = _help_parse_ini();
+ return $cache['topics'];
+}
+
+/**
+ * Retrieve settings for help topics.
+ *
+ * @return
+ * An array of the settings for each module.
+ */
+function help_get_settings() {
+ $cache = _help_parse_ini();
+ return $cache['settings'];
+}
+
+/**
+ * Parse data in help definition file.
+ *
+ * @return
+ * An array of the topics information.
+ */
+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);
+ }
+
+ if (!empty($info)) {
+ global $language;
+ $translation = array();
+
+ // Get translated titles.
+ if (file_exists("$module_path/translations/help/$language->language/$module.help")) {
+ $translation = parse_ini_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",
+ 'path' => $path,
+ '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();
}
- $i++;
+ // Allow modules to alter data using hook_help_topic_info_alter().
+ drupal_alter('help_topic_info', $cache);
}
- $output .= '
';
- return $output;
+ return $cache;
+}
+
+/**
+ * Sort topic information array in ascending order.
+ *
+ * @param $id_a
+ * Module/topic 1
+ * @param $id_b
+ * Module/topic 2
+ *
+ * @return
+ * -1 = $id_a comes before $id_b.
+ * 1 = $id_b comes before $id_a.
+ */
+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.
+ *
+ * @param $module
+ * The module that owns the help topic.
+ * @param $topic
+ * Name of the topic.
+ *
+ * @return
+ * The path to the file of the topic.
+ */
+function help_get_topic_filename($module, $topic) {
+ $info = help_get_topic_file_info($module, $topic);
+ if ($info) {
+ return "./$info[path]/$info[file]";
+ }
+}
+
+/**
+ * Return information for the help topic file.
+ *
+ * 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.
+ *
+ * @param $module
+ * The module that owns the help topic.
+ * @param $topic
+ * Name of the topic.
+ *
+ * @return
+ * An array containing the path and filename of the topic.
+ *
+ */
+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.
+ *
+ * @param $module
+ * Module name to look up.
+ *
+ * @return
+ * The name of the module.
+ */
+function help_get_module_name($module) {
+ $settings = help_get_settings();
+ if (isset($settings[$module]['name'])) {
+ $name = $settings[$module]['name'];
+ }
+ else {
+ $info = db_query("SELECT * FROM {system} WHERE name = :name", array(':name' => $module))->fetchObject();
+ $info = unserialize($info->info);
+ $name = t($info['name']);
+ }
+ return $name;
+}
+
+/**
+ * Format a link.
+ *
+ * @param $text
+ * The text to be enclosed with the anchor tag.
+ * @param $path
+ * The Drupal path being linked to, such as "admin/content/node". Can be an
+ * external or internal URL.
+ * - If you provide the full URL, it will be considered an external URL.
+ * - If you provide only the path (e.g. "admin/content/node"), it is
+ * considered an internal link. In this case, it must be a system URL
+ * as the url() function will generate the alias.
+ * - If you provide '', it generates a link to the site's
+ * base URL (again via the url() function).
+ * - If you provide a path, and 'alias' is set to TRUE (see below), it is
+ * used as is.
+ * @param $options
+ * An associative array of additional options, with the following keys:
+ * - 'attributes'
+ * An associative array of HTML attributes to apply to the anchor tag.
+ * - 'query'
+ * A query string to append to the link, or an array of query key/value
+ * properties.
+ * - 'fragment'
+ * A fragment identifier (named anchor) to append to the link.
+ * Do not include the '#' character.
+ * - 'absolute' (default FALSE)
+ * Whether to force the output to be an absolute link (beginning with
+ * http:). Useful for links that will be displayed outside the site, such
+ * as in an RSS feed.
+ * - 'html' (default FALSE)
+ * Whether the title is HTML, or just plain-text. For example for making
+ * an image a link, this must be set to TRUE, or else you will see the
+ * escaped HTML.
+ * - 'alias' (default FALSE)
+ * Whether the given path is an alias already.
+ * @return
+ * an HTML string containing a link to the given path.
+ *
+ */
+function help_l($text, $dest, $options = array()) {
+ return l($text, $dest, $options);
}
diff --git a/modules/help/help.css b/modules/help/help.css
index 748e190..c15de7a 100644
--- a/modules/help/help.css
+++ b/modules/help/help.css
@@ -5,6 +5,94 @@
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;
+}
+
+div.item-list ul li {
+ margin: .15em 0 .15em 1.5em;
+}
+
+.help-topic code,
+.help-topic pre {
+ background: #f1f1f1;
+ border: 1px solid #BFBFBF;
+ display: block;
+ font-size: 1.15em;
+ margin: 1em;
+ padding: .2em;
+}
+
+.help-topic .toc-block, .help-topic .toc {
+ background-color: #fff;
+ border: 1px solid #D0EBFF;
+ float: right; /* LTR */
+ margin: 0 5px;
+ padding: 5px 10px 5px 5px;
+}
+
+.help-topic .toc {
+ display: table;
+ float: none;
+}
+
+.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 */
+}
diff --git a/modules/help/help.info b/modules/help/help.info
index 678088e..0978aeb 100644
--- a/modules/help/help.info
+++ b/modules/help/help.info
@@ -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
diff --git a/modules/help/help.module b/modules/help/help.module
index af3d35d..8e2a114 100644
--- a/modules/help/help.module
+++ b/modules/help/help.module
@@ -3,29 +3,56 @@
/**
* @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_topic' => array(
+ 'arguments' => array('content' => '', 'navigation' => array(), 'children' => array(), 'links' => array()),
+ ),
+ );
+}
/**
* 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 +63,44 @@ 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.
+ *
+ * @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 $attributes
+ * An array of attributes to include in hyperlink.
+ */
+function theme_help_link($module, $topic = NULL, $title = NULL, $attributes = array()) {
+ static $js_added = FALSE;
+
+ if (!isset($title)) {
+ $title = t('More help');
+ }
+
+ // 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']);
+
+ // Trim the trailing slash if no topic is specified.
+ $output = l($title, trim("admin/help/$module/$topic", '/'), array('attributes' => $attributes));
+
+ return '' . $output . '
';
+}
diff --git a/modules/help/help.test b/modules/help/help.test
index 9d13435..0fde7d2 100644
--- a/modules/help/help.test
+++ b/modules/help/help.test
@@ -8,77 +8,44 @@ class HelpTestCase extends DrupalWebTestCase {
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'),
);
}
/**
- * Enable modules and create users with specific permissions.
- */
- 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->any_user = $this->drupalCreateUser(array());
- }
-
- /**
* Login users, create dblog events, and test dblog functionality through the admin and user interfaces.
*/
function testHelp() {
// Login the admin user.
- $this->drupalLogin($this->big_user);
- $this->verifyHelp();
-
- // Login the regular user.
- $this->drupalLogin($this->any_user);
- $this->verifyHelp(403);
- }
-
- /**
- * Verify the logged in user has the desired access to the various help nodes and the nodes display help.
- *
- * @param integer $response HTTP response code.
- */
- private function verifyHelp($response = 200) {
- $crumb = '›';
-
- foreach ($this->modules as $module => $name) {
- // View module help node.
- $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'));
- }
+ $account = $this->drupalCreateUser(array('access administration pages', 'access help', 'administer blocks'));
+ $this->drupalLogin($account);
+ $sections = parse_ini_file('modules/help/help/help.help', TRUE);
+ foreach ($sections as $section => $data) {
+ $links[url("admin/help/help/$section")] = $data['title'];
}
- }
- /**
- * Get list of enabled modules.
- *
- * @return array Enabled modules.
- */
- private function getModuleList() {
- $this->modules = array();
- $result = db_query("SELECT name, filename, info FROM {system} WHERE type = 'module' AND status = 1 ORDER BY weight ASC, filename ASC");
- foreach ($result as $module) {
- if (file_exists($module->filename)) {
- $fullname = unserialize($module->info);
- $this->modules[$module->name] = $fullname['name'];
+ foreach ($sections as $section => $data) {
+ $this->drupalGet("admin/help/help/$section");
+ $this->assertTitle($data['title'] .' | Drupal', t('title matched'));
+ $help = file_get_contents("modules/help/help/$section.html");
+ if (!empty($data['line break'])) {
+ $help = preg_replace('/^\n/', '', $help);
+ $help = filter_filter('process', 1, -1, $help);
}
- }
+ // There are various replaces done on the help text. We do not test
+ // these now, but skip text inside [].
+ $help_pieces = preg_split('/\[[^\]]+\]/', $help);
+ foreach ($help_pieces as $piece) {
+ $this->assertRaw($piece, t('help text found'));
+ }
+ // Check the links in the table of contents.
+ foreach ($links as $href => $title) {
+ $this->assertTrue($this->xpath('//a[text()="'. $title .'" and @href="'. $href .'"]'), t('Link @href, @title found', array('@href' => $href, '@title' => $title)));
+ }
+ }
+ $this->drupalGet('admin/build/block');
+ $this->clickLink('More help');
+ $this->assertLink('About Block', 0, t('About Block link found'));
}
-}
+}
\ No newline at end of file
diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc
index 82eef0a..b31d360 100644
--- a/modules/system/system.admin.inc
+++ b/modules/system/system.admin.inc
@@ -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");
}
@@ -598,9 +596,6 @@ function system_modules($form_state = array()) {
$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();
@@ -618,13 +613,11 @@ function system_modules($form_state = array()) {
$extra['requires'][$requires] = t('@module (enabled)', array('@module' => $files[$requires]->info['name']));
}
}
- // 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 the user cannot remove required modules.
$dependents = array();
// If this module is required by other modules, list those, and then make it
@@ -744,7 +737,7 @@ function _system_modules_build_row($info, $extra) {
$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'],