? drupal7-help-system_299050-224.patch
? drupal7-help-system_299050-225.patch
? drupal7-help-system_299050-226.patch
? modules/aggregator/help
? modules/block/help
? modules/blog/help
? modules/blogapi/help
? modules/book/help
? modules/color/help
? modules/comment/help
? modules/contact/help
? modules/dblog/help
? modules/filter/help
? modules/forum/help
? modules/help/help
? modules/locale/help
? modules/menu/help
? modules/node/help
? modules/openid/help
? modules/path/help
? modules/poll/help
? modules/profile/help
? modules/search/help
? modules/simpletest/help
? modules/statistics/help
? modules/syslog/help
? modules/system/help
? modules/taxonomy/help
? modules/tracker/help
? modules/translation/help
? modules/trigger/help
? modules/update/help
? modules/upload/help
? modules/user/help
? sites/default/files
? sites/default/settings.php
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.869
diff -u -p -r1.869 common.inc
--- includes/common.inc	18 Feb 2009 15:07:26 -0000	1.869
+++ includes/common.inc	20 Feb 2009 23:53:27 -0000
@@ -3512,6 +3512,21 @@ function element_children(&$elements, $s
 }
 
 /**
+ * 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() {
@@ -3583,8 +3598,8 @@ 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, '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.312
diff -u -p -r1.312 menu.inc
--- includes/menu.inc	9 Feb 2009 16:27:35 -0000	1.312
+++ includes/menu.inc	20 Feb 2009 23:53:28 -0000
@@ -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;
Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.469
diff -u -p -r1.469 theme.inc
--- includes/theme.inc	5 Feb 2009 03:42:56 -0000	1.469
+++ includes/theme.inc	20 Feb 2009 23:53:28 -0000
@@ -1590,13 +1590,6 @@ function theme_list($elements) {
 }
 
 /**
- * Returns code that emits the 'more help'-link.
- */
-function theme_more_help_link($url) {
-  return '<div class="more-help-link">' . t('<a href="@link">More help</a>', array('@link' => check_url($url))) . '</div>';
-}
-
-/**
  * Return code that emits an XML icon.
  *
  * For most use cases, this function has been superseded by theme_feed_icon().
Index: modules/blog/blog.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/blog/blog.test,v
retrieving revision 1.6
diff -u -p -r1.6 blog.test
--- modules/blog/blog.test	13 Feb 2009 02:22:09 -0000	1.6
+++ modules/blog/blog.test	20 Feb 2009 23:53:28 -0000
@@ -91,15 +91,6 @@ class BlogTestCase extends DrupalWebTest
 
     $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);
Index: modules/dblog/dblog.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/dblog/dblog.test,v
retrieving revision 1.14
diff -u -p -r1.14 dblog.test
--- modules/dblog/dblog.test	8 Jan 2009 08:42:12 -0000	1.14
+++ modules/dblog/dblog.test	20 Feb 2009 23:53:28 -0000
@@ -118,13 +118,6 @@ class DBLogTestCase extends DrupalWebTes
   private function verifyReports($response = 200) {
     $quote = '&#039;';
 
-    // 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);
Index: modules/forum/forum.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.test,v
retrieving revision 1.15
diff -u -p -r1.15 forum.test
--- modules/forum/forum.test	13 Feb 2009 05:42:24 -0000	1.15
+++ modules/forum/forum.test	20 Feb 2009 23:53:28 -0000
@@ -279,15 +279,6 @@ class ForumTestCase extends DrupalWebTes
 
     $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);
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	20 Feb 2009 23:53:28 -0000
@@ -0,0 +1,152 @@
+/* $Id$ */
+
+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, .item-list ul, .item-list 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: .2em 0 0 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;
+  border: 1px solid #D0EBFF;
+  display: table;
+  margin: 10px 0;
+  padding: 5px 10px 5px 5px;
+}
+
+#content .toc-block {
+  background: #fff;
+  border: 1px solid #D0EBFF;
+  float: right;
+  margin: 0 10px 10px;
+  padding: 5px;
+}
+
+div.admin-panel {
+  background: #fff;
+  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;
+}
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	20 Feb 2009 23:53:28 -0000
@@ -0,0 +1,34 @@
+<?php
+// $Id$
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $language->language ?>" lang="<?php print $language->language ?>" dir="<?php print $language->dir ?>">
+
+<head>
+  <title><?php print $title; ?></title>
+  <?php print $head; ?>
+  <?php print $styles; ?>
+  <?php print $scripts; ?>
+  <script type="text/javascript"><?php /* Needed to avoid Flash of Unstyled Content in IE */ ?> </script>
+</head>
+<body>
+  <div id="page">
+    <div id="header">
+      <?php if (!empty($search_box)): ?>
+        <div id="search-box"><?php print $search_box; ?></div>
+      <?php endif; ?>
+    </div> <!-- /header -->
+    <div id="breadcrumb"><?php print $breadcrumb; ?></div>
+
+    <div id="content">
+      <?php if (!empty($title)): ?><h1 class="title" id="page-title"><?php print $title; ?></h1><?php endif; ?>
+      <?php if (!empty($tabs)): ?><div class="tabs"><?php print $tabs; ?></div><?php endif; ?>
+      <?php if (!empty($messages)): print $messages; endif; ?>
+      <?php if (!empty($help)): print $help; endif; ?>
+      <div id="content-content" class="clear-block">
+        <?php print $content; ?>
+      </div> <!-- /content-content -->
+    </div> <!-- /content -->
+
+    <?php print $closure; ?>
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	20 Feb 2009 23:53:28 -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.8
diff -u -p -r1.8 help.admin.inc
--- modules/help/help.admin.inc	18 Feb 2009 14:28:22 -0000	1.8
+++ modules/help/help.admin.inc	20 Feb 2009 23:53:28 -0000
@@ -3,74 +3,581 @@
 
 /**
  * @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.
- */
-function help_main() {
-  // Add CSS
-  drupal_add_css(drupal_get_path('module', 'help') . '/help.css', array('preprocess' => FALSE));
-  $output = '<h2>' . t('Help topics') . '</h2><p>' . t('Help is available on the following items:') . '</p>' . help_links_as_list();
-  return $output;
+* Menu callback; returns a page displaying available help topics for modules.
+*/
+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 (isset($_GET['popup'])) {
+    drupal_set_breadcrumb(array());
+    print theme('help_popup', theme('system_admin_by_module', $menu_items));
+    return;
+  }
+
+  drupal_add_css(drupal_get_path('module', 'help') . '/help.css');
+  return theme('system_admin_by_module', $menu_items);
 }
 
 /**
- * Menu callback; prints a page listing general help for a module.
+ * Menu callback; returns a page with help topic for a module.
  */
-function help_page($name) {
-  $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']));
+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 = isset($_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 {
-      $output .= $temp;
+      $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;
 
-    // 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'])));
+    $parent = help_get_topic_info($parent_module, $parent_topic);
+    if (!$parent) {
+      break;
     }
 
+    $breadcrumb[] = help_l($parent['title'], "admin/help/$parent_module/$parent_topic");
+  }
+
+  $output = help_view_topic($module, $topic, $popup);
+  if (empty($output)) {
+    $output = help_view_module($module, $popup);
+    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");
+
+  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;
+}
+
+ /**
+  * Load and render a help topics listing.
+  */
+function help_view_module($module, $popup = FALSE) {
+  $output = '';
+
+  $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;
 }
 
-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 = '<div class="clearfix"><div class="help-items"><ul>';
-  $i = 0;
-  foreach ($modules as $module => $name) {
-    $output .= '<li>' . l($name, 'admin/help/' . $module) . '</li>';
-    if (($i + 1) % $break == 0 && ($i + 1) != $count) {
-      $output .= '</ul></div><div class="help-items' . ($i + 1 == $break * 3 ? ' help-items-last' : '') . '"><ul>';
+/**
+ * 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')), array('%24' => '$')), $output);
+     }
+     else {
+      $output = preg_replace('/\[topic:([^"]+)\]/', strtr(url('admin/help/$1'), array('%24' => '$')), $output);
     }
-    $i++;
+
+    global $base_path;
+
+    // Change '[url:X]' to the URL to the site.
+    $output = preg_replace('/\[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 <br /> to the filter.
+      $output = preg_replace('/^<!--[^\n]*-->\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, 'ul', 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]";
+      }
+      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 = '<div class="help-navigation clear-block">';
+
+        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 .= '</div>';
+
+        $output .= $navigation;
+      }
+    }
+
+    if (!empty($info['css'])) {
+      drupal_add_css($info['path'] . '/' . $info['css']);
+    }
+
+    return '<div class="help-topic">' . $output . '</div>';
   }
-  $output .= '</ul></div></div>';
+}
 
-  return $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;
+     }
+   }
+
+  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 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 = '';
+        }
+      }
+
+      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];
+  }
+}
+
+/**
+ * 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);
+      }
+
+      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();
+    }
+    // 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 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.
+ *
+ */
+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_query("SELECT * FROM {system} WHERE name = :name", array(':name' => $module))->fetchObject();
+    $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 (isset($_GET['popup'])) {
+    if (empty($options['query'])) {
+      $options['query'] = 'popup';
+    }
+  }
+
+  return l($text, $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('<link rel="shortcut icon" href="' . check_url(theme_get_setting('favicon')) . '" type="image/x-icon" />');
+  }
+
+  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	20 Feb 2009 23:53:28 -0000
@@ -5,6 +5,93 @@
   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 #444;
+  display: block;
+  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 */
+}
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	20 Feb 2009 23:53:28 -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	20 Feb 2009 23:53:28 -0000
@@ -0,0 +1,12 @@
+// $Id: $
+(function ($) {
+  Drupal.behaviors.help = {
+    attach: function() {
+      $('a.help-link-popup').bind('click', function() {
+        var url = this.href + (this.href.indexOf('?') != -1 ? '&' : '?') + "popup";
+        window.open(url, 'help_window', 'width=600,height=550,scrollbars,resizable').focus();
+        return false;
+      });
+    }
+  };
+})(jQuery);
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	20 Feb 2009 23:53:28 -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 = '<p>' . t('This guide provides context sensitive help on the use and configuration of <a href="@drupal">Drupal</a> and its modules, and is a supplement to the more extensive online <a href="@handbook">Drupal handbook</a>. 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')) . '</p>';
-      return $output;
-    case 'admin/help#help':
-      $output = '<p>' . t('The help module provides context sensitive help on the use and configuration of <a href="@drupal">Drupal</a> and its modules, and is a supplement to the more extensive online <a href="@handbook">Drupal handbook</a>. 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')) . '</p>';
-      $output .= '<p>' . t('For more information, see the online handbook entry for <a href="@help">Help module</a>.', array('@help' => 'http://drupal.org/handbook/modules/help/')) . '</p>';
-      return $output;
+      return '<p>' . t('This guide provides context sensitive help on the use and configuration of <a href="@drupal">Drupal</a> and its modules, and is a supplement to the more extensive online <a href="@handbook">Drupal handbook</a>. 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')) . '</p>';
   }
 }
+
+/**
+ * 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 '<div class="more-help-link">' . $output . '</div>';
+}
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	20 Feb 2009 23:53:28 -0000
@@ -8,77 +8,46 @@ 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'),
     );
   }
 
   /**
-   * 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('<h2>' . t($name) . '</h2>', 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");
-    while ($module = db_fetch_object($result)) {
-      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]*-->\n/', '', $help);
+        $help = _filter_autop($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'));
+    $this->drupalGet('admin/help/block', array('query' => 'popup'));
+    $this->assertRaw('modules/help/help-popup.css', t('Popup displayed'));
+    $this->assertLink('About Block', 0, t('About Block link found'));
   }
 }
Index: modules/system/system.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v
retrieving revision 1.127
diff -u -p -r1.127 system.admin.inc
--- modules/system/system.admin.inc	18 Feb 2009 15:19:56 -0000	1.127
+++ modules/system/system.admin.inc	20 Feb 2009 23:53:29 -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");
       }
 
@@ -598,9 +596,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();
@@ -618,12 +613,10 @@ function system_modules($form_state = ar
         $extra['requires'][$requires] = t('@module (<span class="admin-enabled">enabled</span>)', 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();
@@ -744,7 +737,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'],
