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 21 Feb 2009 23:22:35 -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 21 Feb 2009 23:22:36 -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 21 Feb 2009 23:22:36 -0000 @@ -1590,13 +1590,6 @@ function theme_list($elements) { } /** - * Returns code that emits the 'more help'-link. - */ -function theme_more_help_link($url) { - return ''; -} - -/** * Return code that emits an XML icon. * * For most use cases, this function has been superseded by theme_feed_icon(). Index: modules/block/help/about.html =================================================================== RCS file: modules/block/help/about.html diff -N modules/block/help/about.html --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/block/help/about.html 21 Feb 2009 23:22:36 -0000 @@ -0,0 +1,15 @@ + +

Blocks are boxes of content rendered into an area, or region, of a web page. The default theme Garland, for example, implements the regions "left sidebar", "right sidebar", "content", "header", and "footer", and a block may appear in any one of these areas. The blocks administration page provides a drag-and-drop interface for assigning a block to a region, and for controlling the order of blocks within regions.

+

Although blocks are usually generated automatically by modules (like the User login block, for example), administrators can also define custom blocks. Custom blocks have a title, description, and body. The body of the block can be as long as necessary, and can contain content supported by any available input format.

+

When working with blocks, remember that:

+ +

For more information, see the online handbook entry for Block module.

Index: modules/block/help/block.help =================================================================== RCS file: modules/block/help/block.help diff -N modules/block/help/block.help --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/block/help/block.help 21 Feb 2009 23:22:36 -0000 @@ -0,0 +1,5 @@ +; $Id$ +[about] +title = About Block +file = about +weight = -10 \ No newline at end of file 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 21 Feb 2009 23:22:36 -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 21 Feb 2009 23:22:36 -0000 @@ -118,13 +118,6 @@ class DBLogTestCase extends DrupalWebTes 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); 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 21 Feb 2009 23:22:36 -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/about.html =================================================================== RCS file: modules/help/help/about.html diff -N modules/help/help/about.html --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/help/help/about.html 21 Feb 2009 23:22:36 -0000 @@ -0,0 +1,45 @@ + +The help system was designed to replace the original Drupal help system, which has several flaws that make it hard to create new help, hard to maintain existing help, and particularly hard to access help. + +The primary goal, then, is to increase the accessibility of help, meaning the ability of both the user and the help text author to access the needed tools to use, create, maintain and translate the help. + +This system is completely separate from Drupal's hook_help(). In Drupal 6, it actually co-exists with it; in the future, it is hoped that it will completely replace it allowing hook_help() to be deprecated and removed. + +Messages added to the top of a page are not really "help". Often these messages are an introduction to a form or a short blurb telling a user what to do with a particular page. The problem is, these messages are always there, they are easily ignored, and they come before the actual page. In general, when users are learning, they want to see the page first, then ask questions. The reverse order is much less conducive to actually teaching a user how to use something. By allowing help to be available on request, the system conforms more naturally to how most people work. + +

Help is organized by topic

+With the hook_help() method, help text is organized by URL path. This is fine if you have help text describing how to use a particular page or what a particular page does, but ultimately is limiting because manuals and documentation are usually grouped by topic, and those topics are determined by the material itself. + +Help allows the documentation author to organize topics as he or she sees fit; the only restriction, really, is that each individual chunk of text needs to stand on its own as a discrete topic. + +What's more, modules can insert their topics into another module's hierarchy. This would allow the Drupal core to create a task based help navigation system which allows modules insert topics into that navigation fluidly. This allows modules to continue to keep their systems separate, yet integrate into the main system. + +

Help topics are processed HTML in their own files

+This separation makes it easy to find and modify. Currently, everything is lumped together in hook_help() in PHP strings that are run through t(), and there is a fair amount of PHP code necessary in this system that actually gets in the way of writing good, explanatory text. + +In fact, requiring a documentation author to understand PHP at all is a detriment. The idea that documentation writers need to have PHP development as a skill seriously reduces the number of available contributors. HTML, on the other hand, is a much more common skill, is relatively easy to learn, and the amount of HTML needed to write documentation is only a little bit more than the HTML used in forum posts. + +Another benefit to not using PHP is that the files themselves are safe. They are unlikely to include malicious PHP code that could take over the server or do worse things. This means that these files can be used relatively easily on the drupal.org hardware so that a module's help files can be made immediately available without needing to download the module. It also means that descriptions of the module can be made on drupal.org that are version aware, can be corrected easily in CVS with patches, but can also be made available with the module so that drupal.org is not required. + +This also means that we could, if we wanted, package the drupal.org handbooks, or a subset of them, directly into a drupal distribution, or a drupal add-on, so that Drupal administrators can have Drupal help without needing to visit drupal.org. This can be valuable in locked down corporate environments and on planes. But more importantly, the handbooks can be made version aware much more easily than the current method on drupal.org. + +The downside to this method is that these books can't easily be made dynamic. Though the use of alter hooks could allow a module to make modifications to the help as needed, doing this could make the help files less useful when you take them out of context. + +

Help files are translated as a file

+It is actually not easy to translate documents as strings, particularly when the language being used is very much unlike English. In fact, when translating a document, the organization of the sentences may change drastically. It is also a burden on the CPU to do this, as you are indexing on very long strings. + +Translators have a much better time translating a document as a unit, because of the presence of the entire context. + +

Help has its own navigation system

+By making use of a navigation system specified in a .ini file (which is not PHP code and therefore safe to use on *.drupal.org sites), the help can be structured like a book, which is typical of online manuals. This is familiar to users, can be organized (and re-organized) and allows a module to include significantly richer text without burdening the PHP code with having its help loaded unnecessarily. + +This book can be navigated hierarchically as well, making it easy to keep related topics together. +

Help is indexed by the search engine

+An important goal of this system was to add searchability to the help. By being able to enter keywords into the search box and find relevant topics, we come up with a system that resembles the kind of help that comes with many operating systems. This is very valuable when searching through manuals trying to find out how to do a particular thing. + +This search is specific to the help, meaning that the help will not be mixed in with the global node search. This can be considered both an advantage and a disadvantage. For the most part, this help system is meant to provide help to site administrators, and content searches should not find it. The disadvantage, of course, is when you want to use it for end user help, you will not be able to. + +

Inline help can be brought in via popups

+In addition to the manual-like hierarchical navigation, help can also provide context-sensitive additional help through a popup. While popups are controversial, the argument for using them is that when getting help while on a form, a popup will not throw away a user's data. Browsers are not very friendly to input forms if they are not submitted, and navigating away from the form can be dangerous. There are various other solutions to this problem, but each one has a drawback. The drawbacks to popups are well known, but mostly it is the irritation of having new windows. When getting help, though, a popup is usually invited. Help should not interfere with what the operation the user is trying to complete. It differs greatly from the uninvited popup, which are usually ads or popups meant to prevent users from navigating away from a site. + +These popups can be added to a page with text links or icon links. Index: modules/help/help/creating-help.html =================================================================== RCS file: modules/help/help/creating-help.html diff -N modules/help/help/creating-help.html --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/help/help/creating-help.html 21 Feb 2009 23:22:36 -0000 @@ -0,0 +1,43 @@ + +

The Help system is a pluggable system that provides help facilities for Drupal and its modules. Although the help does not provide general help by itself, it provides a powerful and easy framework that modules may use to provide their own help. +

+ +

+Modules utilizing Help should create a 'help' subdirectory inside their +module's directory. Place the file MODULENAME.help in this subdirectory, formatted +similar to the following example: +

+
+[buses]
+title = "How buses are tied into the system"
+file = buses
+
+[TOPIC_ID]
+title = "Title of topic".
+file = filename of topic, without the .html extension.
+weight = How important the topic is on the index page.
+parent = The optional topic parent to use in the breadcrumb, 
+         either topic or module%topic.
+
+ +

+All topics are addressed by the module providing the topic, and by the topic +id. To embed links, use the following format: +

+ +$output .= theme('help_topic', $module, $topic); + + +

Inside your help file, link to other topics using the format <a href="[topic:module/topic]">. This +format will ensure the popup status remains consistent when switching between links.

+ +

Use <img src="[path]example.jpg" /> to reference items +within the help directory, such as images you wish to embed within the help text.

+ +

Use <a href="[base_url]admin/settings/site-configuration" target="_blank"> to reference any normal path in the site.

+ +

If the search module is enabled, the contents of help system will be indexed on cron. If you enable new modules and wish to immediately index its help text, visit the "Administration -> Reports -> Status report" and click the "Run cron manually" link.

+ +

Example: Don't click this!

+ +

See: Help file format

Index: modules/help/help/help-file.html =================================================================== RCS file: modules/help/help/help-file.html diff -N modules/help/help/help-file.html --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/help/help/help-file.html 21 Feb 2009 23:22:36 -0000 @@ -0,0 +1,54 @@ + +The help configuration file is in simple .ini file format, divided into sections for each help file, plus an optional section for global settings that might be inherited for each help file. + +The first line of an help ini file should be ;$Id $ which will be a comment providing the CVS identifier for the file. The ; indicates a comment character. Anything after the ; will be ignored. + +Global settings may be put into a section named [help settings] -- this means that this name is reserved and it cannot be a help file in any module. The following settings may be set in this section: +
+
line break
+
If set to any value, the line break filter will be applied to all help files defined by this module, unless that help file specifically is set otherwise. By default, the line break filter is not applied; however, help files can be much easier to write with the line break filter on.
+
navigation
+
If set to true, the navigation will be displayed at the end of the help topic: previous topic, next topic, and child topics.
+
css
+
Specify a css file that will be used for all help files (unless overridden), including the .css extension. This .css file must reside in the help directory along with the .html files, and will not be affected by translation.
+
name
+
May be set to override the module name as displayed in both the module index as well as the navigation and breadcrumb trail. In general this does not need to be set, but a few modules may want to use a more friendly name than appears in the .info file.
+
index name
+
This may be set to change the name of the module in the module index. It overrides the 'name' setting above, as well as the module name in its .info file.
+
hide
+
This may be used to hide a module in the module index. This is particularly useful for modules who insert their help files into the hierarchy of another module, as might be done by modules that extend Views or CCK. By setting "hide = TRUE" the module will not appear as its own entry.
+
+ +Each section after that will correspond to a single help file, and each one may have the following settings: +
+
title
+
The title of the topic, presented to the user and used in links. If you have special characters in your title, be sure to enclose it in quotes.
+
file
+
The filename, without the .html extension, used for the topic. This is optional; if not specified, the topic name wil be the file name.
+
weight
+
The weight, used for sorting topics on the administration page. Defaults to 0 if unspecified. Items with the same weight are listed in the same order as they listed in the .help file.
+
parent
+
The topic ID to use in a hierarchy; children will be listed beneath parents in the topic list, and will have the parent in their breadcrumb trail. You may parent this topic to another module's topic by using module%topic as the identifier. For example, 'views%display' will make this a child of the 'display' topic in the 'views' module.
+
line break
+
If set to true, linebreaks will be converted into br and p tags automatically. If unspecified, will default to off. Set to 0 to disable the filter if this has been turned on in the global settings.
+
css
+
Specify a css file that will be used for this file. This .css file must reside in the help directory along with the .html files. This will override any .css file added by the global system.
+
popup width
+
The width in pixels of the popup window. Defaults to 500 if unspecified.
+
popup height
+
The height in pixels of the popup window. Defaults to 500 if unspecified.
+
+ +For example, here is a version of the help.help file: +
+[using-help]
+title = "Using help"
+weight = -10
+
+[translation]
+title = Translating help
+
+[help-file]
+title = Help file format
+line break = TRUE
+
\ No newline at end of file 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 21 Feb 2009 23:22:36 -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 21 Feb 2009 23:22:36 -0000 @@ -0,0 +1,34 @@ + + + + + + <?php print $title; ?> + + + + + + +
+ + + +
+

+
+ + +
+ +
+
+ + 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 21 Feb 2009 23:22:36 -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 21 Feb 2009 23:22:36 -0000 @@ -3,74 +3,579 @@ /** * @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 = '

' . t('Help topics') . '

' . t('Help is available on the following items:') . '

' . 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 = '
    '; - $i = 0; - foreach ($modules as $module => $name) { - $output .= '
  • ' . l($name, 'admin/help/' . $module) . '
  • '; - if (($i + 1) % $break == 0 && ($i + 1) != $count) { - $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']; + $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
    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, '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 = '
    '; + + 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 . '
    '; } - $output .= '
'; +} - 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(''); + } + + 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 21 Feb 2009 23:22:37 -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/help.help =================================================================== RCS file: modules/help/help/help.help diff -N modules/help/help/help.help --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/help/help/help.help 21 Feb 2009 23:22:37 -0000 @@ -0,0 +1,15 @@ +; $Id$ + +[about] +title = About Help +line break = TRUE + +[creating-help] +title = Creating help + +[translation] +title = Translating help + +[help-file] +title = Help file format +line break = TRUE \ No newline at end of file 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 21 Feb 2009 23:22:37 -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 21 Feb 2009 23:22:37 -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 21 Feb 2009 23:22:37 -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 ''; +} 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 21 Feb 2009 23:22:37 -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('

' . 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"); - 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/', '', $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/help/help/translation.html =================================================================== RCS file: modules/help/help/translation.html diff -N modules/help/help/translation.html --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/help/help/translation.html 21 Feb 2009 23:22:37 -0000 @@ -0,0 +1,10 @@ + +

To translate help, first create a translations/help/$language directory +in the module directory. Then, copy the .ini file and all .html files from +the help directory.

+ +

The .ini file only needs to keep the titles, and if there is a 'name' or 'index name' setting in the 'help settings' portion, that should be retained. Any retained settings should be translated. The rest of the data in the .ini file may be discarded or ignored.

+ +

Each file should then be translated in place.

+ +

When translating a .html file, you will find that the path keyword will lead to the original directory. If you must translate items that are linked, such as images, use trans_path instead, which will lead to the translated directory. This will allow you to pick and choose which linked items, if any, will be translated.

\ No newline at end of file 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 21 Feb 2009 23:22:37 -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 (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(); @@ -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'],