| 1 |
<?php
|
| 2 |
// $Id: advanced_help.module,v 1.40 2008/10/27 22:43:28 merlinofchaos Exp $
|
| 3 |
/**
|
| 4 |
* @file advanced_help.module
|
| 5 |
*
|
| 6 |
* Pluggable system to provide advanced help facilities for Drupal and modules.
|
| 7 |
*
|
| 8 |
* Modules utilizing this help system should create a 'help' directory in their
|
| 9 |
* module. Inside that directory place MODULENAME.help.ini which will be formatted
|
| 10 |
* like this:
|
| 11 |
*
|
| 12 |
* @code
|
| 13 |
* [buses]
|
| 14 |
* title = "How buses are tied into the system"
|
| 15 |
* file = buses
|
| 16 |
*
|
| 17 |
* [TOPIC_ID]
|
| 18 |
* title = "Title of topic"
|
| 19 |
* file = filename of topic, without the .html extension
|
| 20 |
* weight = the importance of the topic on the index page
|
| 21 |
* parent = the optional topic parent to use in the breadcrumb. Can be either topic or module%topic
|
| 22 |
* @endcode
|
| 23 |
*
|
| 24 |
* All topics are addressed by the module that provides the topic, and the topic
|
| 25 |
* id. Links may be embedded as in the following example:
|
| 26 |
*
|
| 27 |
* @code
|
| 28 |
* $output .= theme('advanced_help_topic', $module, $topic);
|
| 29 |
* @endcode
|
| 30 |
*
|
| 31 |
* Link to other topics using <a href="topic:module/topic">. (Using
|
| 32 |
* this format ensures the popup status remains consistent for all
|
| 33 |
* links.)
|
| 34 |
*/
|
| 35 |
|
| 36 |
/**
|
| 37 |
* Implementation of hook_menu().
|
| 38 |
*/
|
| 39 |
function advanced_help_menu() {
|
| 40 |
// View help topic index.
|
| 41 |
|
| 42 |
// This is structured a little oddly so POTX can properly handle the translation.
|
| 43 |
if (module_exists('help')) {
|
| 44 |
$items['admin/advanced_help'] = array(
|
| 45 |
'title' => 'Advanced help',
|
| 46 |
'page callback' => 'advanced_help_index_page',
|
| 47 |
'access arguments' => array('view advanced help index'),
|
| 48 |
'weight' => 9,
|
| 49 |
);
|
| 50 |
}
|
| 51 |
else {
|
| 52 |
$items['admin/advanced_help'] = array(
|
| 53 |
'title' => 'Help',
|
| 54 |
'page callback' => 'advanced_help_index_page',
|
| 55 |
'access arguments' => array('view advanced help index'),
|
| 56 |
'weight' => 9,
|
| 57 |
);
|
| 58 |
}
|
| 59 |
$items['advanced_help/search/%menu_tail'] = array(
|
| 60 |
'title' => 'Search help',
|
| 61 |
'page callback' => 'advanced_help_search_view',
|
| 62 |
'page arguments' => array('advanced_help'),
|
| 63 |
'access arguments' => array('view advanced help index'),
|
| 64 |
);
|
| 65 |
|
| 66 |
// View help topic.
|
| 67 |
$items['help/%/%'] = array(
|
| 68 |
'page callback' => 'advanced_help_topic_page',
|
| 69 |
'page arguments' => array(1, 2),
|
| 70 |
'access arguments' => array('view advanced help topic'),
|
| 71 |
'type' => MENU_CALLBACK,
|
| 72 |
);
|
| 73 |
|
| 74 |
return $items;
|
| 75 |
}
|
| 76 |
|
| 77 |
/**
|
| 78 |
* Inplementation of hook_menu_alter().
|
| 79 |
**/
|
| 80 |
function advanced_help_menu_alter(&$callbacks) {
|
| 81 |
// We need to fix the menu item provided by search module to restrict access.
|
| 82 |
$callbacks['search/advanced_help/%menu_tail']['access callback'] = 'user_access';
|
| 83 |
$callbacks['search/advanced_help/%menu_tail']['access arguments'] = array('view advanced help index');
|
| 84 |
}
|
| 85 |
|
| 86 |
/**
|
| 87 |
* Implementation of hook_theme().
|
| 88 |
*/
|
| 89 |
function advanced_help_theme() {
|
| 90 |
$hooks['advanced_help_topic'] = array(
|
| 91 |
'arguments' => array('module' => NULL, 'topic' => NULL),
|
| 92 |
);
|
| 93 |
|
| 94 |
$hooks['advanced_help_popup'] = array(
|
| 95 |
'arguments' => array('content' => NULL),
|
| 96 |
'template' => 'advanced-help-popup',
|
| 97 |
);
|
| 98 |
|
| 99 |
return $hooks;
|
| 100 |
}
|
| 101 |
|
| 102 |
function advanced_help_uasort($id_a, $id_b) {
|
| 103 |
$topics = advanced_help_get_topics();
|
| 104 |
list($module_a, $topic_a) = $id_a;
|
| 105 |
$a = $topics[$module_a][$topic_a];
|
| 106 |
list($module_b, $topic_b) = $id_b;
|
| 107 |
$b = $topics[$module_b][$topic_b];
|
| 108 |
|
| 109 |
$a_weight = isset($a['weight']) ? $a['weight'] : 0;
|
| 110 |
$b_weight = isset($b['weight']) ? $b['weight'] : 0;
|
| 111 |
if ($a_weight != $b_weight) {
|
| 112 |
return ($a_weight < $b_weight) ? -1 : 1;
|
| 113 |
}
|
| 114 |
|
| 115 |
if ($a['title'] != $b['title']) {
|
| 116 |
return ($a['title'] < $b['title']) ? -1 : 1;
|
| 117 |
}
|
| 118 |
return 0;
|
| 119 |
}
|
| 120 |
|
| 121 |
/**
|
| 122 |
* Page callback for advanced help search.
|
| 123 |
*/
|
| 124 |
function advanced_help_search_view() {
|
| 125 |
if (!module_exists('search')) {
|
| 126 |
return MENU_NOT_FOUND;
|
| 127 |
}
|
| 128 |
|
| 129 |
$breadcrumb[] = advanced_help_l(t('Help'), 'admin/advanced_help');
|
| 130 |
|
| 131 |
if (!isset($_POST['form_id'])) {
|
| 132 |
$keys = search_get_keys();
|
| 133 |
// Only perform search if there is non-whitespace search term:
|
| 134 |
$results = '';
|
| 135 |
if (trim($keys)) {
|
| 136 |
|
| 137 |
// Collect the search results:
|
| 138 |
$results = search_data($keys, 'advanced_help');
|
| 139 |
|
| 140 |
if ($results) {
|
| 141 |
$results = theme('box', t('Search results'), $results);
|
| 142 |
}
|
| 143 |
else {
|
| 144 |
$results = theme('box', t('Your search yielded no results'), search_help('search#noresults', drupal_help_arg()));
|
| 145 |
}
|
| 146 |
}
|
| 147 |
|
| 148 |
// Construct the search form.
|
| 149 |
$output = drupal_get_form('advanced_help_search_form', $keys);
|
| 150 |
$output .= $results;
|
| 151 |
|
| 152 |
}
|
| 153 |
else {
|
| 154 |
$output = drupal_get_form('advanced_help_search_form', empty($keys) ? '' : $keys);
|
| 155 |
}
|
| 156 |
|
| 157 |
$popup = !empty($_GET['popup']) && user_access('view advanced help popup');
|
| 158 |
if ($popup) {
|
| 159 |
$GLOBALS['devel_shutdown'] = FALSE; // Prevent devel module from spewing.
|
| 160 |
module_invoke('admin_menu', 'suppress'); // Suppress admin_menu.
|
| 161 |
drupal_set_breadcrumb(array_reverse($breadcrumb));
|
| 162 |
print theme('advanced_help_popup', $output);
|
| 163 |
return;
|
| 164 |
}
|
| 165 |
|
| 166 |
$breadcrumb = array_merge(drupal_get_breadcrumb(), array_reverse($breadcrumb));
|
| 167 |
drupal_set_breadcrumb($breadcrumb);
|
| 168 |
return $output;
|
| 169 |
}
|
| 170 |
|
| 171 |
/**
|
| 172 |
* Page callback to view the advanced help topic index.
|
| 173 |
*/
|
| 174 |
function advanced_help_index_page($module = '') {
|
| 175 |
$topics = advanced_help_get_topics();
|
| 176 |
$settings = advanced_help_get_settings();
|
| 177 |
|
| 178 |
// Print a search widget.
|
| 179 |
$output = '';
|
| 180 |
if (module_exists('search')) {
|
| 181 |
$output .= drupal_get_form('advanced_help_search_form');
|
| 182 |
}
|
| 183 |
else {
|
| 184 |
$output .= t('Enable the search module to search help.');
|
| 185 |
}
|
| 186 |
|
| 187 |
$breadcrumb = array();
|
| 188 |
if ($module) {
|
| 189 |
if (empty($topics[$module])) {
|
| 190 |
return drupal_not_found();
|
| 191 |
}
|
| 192 |
|
| 193 |
advanced_help_get_topic_hierarchy($topics);
|
| 194 |
$items = advanced_help_get_tree($topics, $topics[$module]['']['children']);
|
| 195 |
|
| 196 |
$breadcrumb[] = advanced_help_l(t('Help'), 'admin/advanced_help');
|
| 197 |
|
| 198 |
drupal_set_title(t('@module help index', array('@module' => advanced_help_get_module_name($module))));
|
| 199 |
$output .= theme('item_list', $items);
|
| 200 |
}
|
| 201 |
else {
|
| 202 |
// Print a module index.
|
| 203 |
$modules = array();
|
| 204 |
$result = db_query("SELECT * FROM {system}");
|
| 205 |
while ($info = db_fetch_object($result)) {
|
| 206 |
$module_info = unserialize($info->info);
|
| 207 |
$modules[$info->name] = $module_info['name'];
|
| 208 |
}
|
| 209 |
|
| 210 |
asort($modules);
|
| 211 |
|
| 212 |
$items = array();
|
| 213 |
foreach ($modules as $module => $module_name) {
|
| 214 |
if (!empty($topics[$module]) && empty($settings[$module]['hide'])) {
|
| 215 |
if (isset($settings[$module]['index name'])) {
|
| 216 |
$name = $settings[$module]['index name'];
|
| 217 |
}
|
| 218 |
elseif (isset($settings[$module]['name'])) {
|
| 219 |
$name = $settings[$module]['name'];
|
| 220 |
}
|
| 221 |
else {
|
| 222 |
$name = t($module_name);
|
| 223 |
}
|
| 224 |
$items[] = advanced_help_l($name, "admin/advanced_help/$module");
|
| 225 |
}
|
| 226 |
}
|
| 227 |
|
| 228 |
drupal_set_title(t('Module help index'));
|
| 229 |
$output .= theme('item_list', $items);
|
| 230 |
}
|
| 231 |
|
| 232 |
$popup = !empty($_GET['popup']) && user_access('view advanced help popup');
|
| 233 |
if ($popup) {
|
| 234 |
$GLOBALS['devel_shutdown'] = FALSE; // Prevent devel module from spewing.
|
| 235 |
module_invoke('admin_menu', 'suppress'); // Suppress admin_menu.
|
| 236 |
drupal_set_breadcrumb(array_reverse($breadcrumb));
|
| 237 |
print theme('advanced_help_popup', $output);
|
| 238 |
return;
|
| 239 |
}
|
| 240 |
|
| 241 |
$breadcrumb = array_merge(drupal_get_breadcrumb(), array_reverse($breadcrumb));
|
| 242 |
drupal_set_breadcrumb($breadcrumb);
|
| 243 |
|
| 244 |
return $output;
|
| 245 |
}
|
| 246 |
|
| 247 |
/**
|
| 248 |
* Build a tree of advanced help topics.
|
| 249 |
*/
|
| 250 |
function advanced_help_get_tree($topics, $topic_ids, $max_depth = -1, $depth = 0) {
|
| 251 |
uasort($topic_ids, 'advanced_help_uasort');
|
| 252 |
$items = array();
|
| 253 |
foreach ($topic_ids as $info) {
|
| 254 |
list($module, $topic) = $info;
|
| 255 |
$item = advanced_help_l($topics[$module][$topic]['title'], "help/$module/$topic");
|
| 256 |
if (!empty($topics[$module][$topic]['children']) && ($max_depth == -1 || $depth < $max_depth)) {
|
| 257 |
$item .= theme('item_list', advanced_help_get_tree($topics, $topics[$module][$topic]['children'], $max_depth, $depth + 1));
|
| 258 |
}
|
| 259 |
|
| 260 |
$items[] = $item;
|
| 261 |
}
|
| 262 |
|
| 263 |
return $items;
|
| 264 |
}
|
| 265 |
|
| 266 |
/**
|
| 267 |
* Build a hierarchy for a single module's topics.
|
| 268 |
*/
|
| 269 |
function advanced_help_get_topic_hierarchy(&$topics) {
|
| 270 |
foreach ($topics as $module => $module_topics) {
|
| 271 |
foreach ($module_topics as $topic => $info) {
|
| 272 |
$parent_module = $module;
|
| 273 |
// We have a blank topic that we don't want parented to
|
| 274 |
// itself.
|
| 275 |
if (!$topic) {
|
| 276 |
continue;
|
| 277 |
}
|
| 278 |
|
| 279 |
if (empty($info['parent'])) {
|
| 280 |
$parent = '';
|
| 281 |
}
|
| 282 |
else if (strpos($info['parent'], '%')) {
|
| 283 |
list($parent_module, $parent) = explode('%', $info['parent']);
|
| 284 |
if (empty($topics[$parent_module][$parent])) {
|
| 285 |
// If it doesn't exist, top level.
|
| 286 |
$parent = '';
|
| 287 |
}
|
| 288 |
}
|
| 289 |
else {
|
| 290 |
$parent = $info['parent'];
|
| 291 |
if (empty($module_topics[$parent])) {
|
| 292 |
// If it doesn't exist, top level.
|
| 293 |
$parent = '';
|
| 294 |
}
|
| 295 |
}
|
| 296 |
|
| 297 |
if (!isset($topics[$parent_module][$parent]['children'])) {
|
| 298 |
$topics[$parent_module][$parent]['children'] = array();
|
| 299 |
}
|
| 300 |
$topics[$parent_module][$parent]['children'][] = array($module, $topic);
|
| 301 |
$topics[$module][$topic]['_parent'] = array($parent_module, $parent);
|
| 302 |
}
|
| 303 |
}
|
| 304 |
}
|
| 305 |
|
| 306 |
/**
|
| 307 |
* Form builder callback to build the search form.
|
| 308 |
*/
|
| 309 |
function advanced_help_search_form(&$form_state, $keys = '') {
|
| 310 |
$form = search_form($form_state, advanced_help_url('admin/advanced_help'), $keys, 'advanced_help', t('Search help'));
|
| 311 |
require_once './' . drupal_get_path('module', 'search') . '/search.pages.inc';
|
| 312 |
|
| 313 |
$form['basic']['inline']['submit']['#validate'] = array('search_form_validate');
|
| 314 |
$form['basic']['inline']['submit']['#submit'] = array('advanced_help_search_form_submit');
|
| 315 |
|
| 316 |
return $form;
|
| 317 |
}
|
| 318 |
|
| 319 |
/**
|
| 320 |
* Process a search form submission.
|
| 321 |
*/
|
| 322 |
function advanced_help_search_form_submit($form, &$form_state) {
|
| 323 |
$keys = $form_state['values']['processed_keys'];
|
| 324 |
if ($keys == '') {
|
| 325 |
form_set_error('keys', t('Please enter some keywords.'));
|
| 326 |
return;
|
| 327 |
}
|
| 328 |
|
| 329 |
$popup = !empty($_GET['popup']) && user_access('view advanced help popup');
|
| 330 |
|
| 331 |
if ($popup) {
|
| 332 |
$form_state['redirect'] = array('advanced_help/search/' . $keys, 'popup=true');
|
| 333 |
}
|
| 334 |
else {
|
| 335 |
$form_state['redirect'] = 'advanced_help/search/' . $keys;
|
| 336 |
}
|
| 337 |
}
|
| 338 |
|
| 339 |
|
| 340 |
/**
|
| 341 |
* Small helper function to get a module's proper name.
|
| 342 |
*/
|
| 343 |
function advanced_help_get_module_name($module) {
|
| 344 |
$settings = advanced_help_get_settings();
|
| 345 |
if (isset($settings[$module]['name'])) {
|
| 346 |
$name = $settings[$module]['name'];
|
| 347 |
}
|
| 348 |
else {
|
| 349 |
$info = db_fetch_object(db_query("SELECT * FROM {system} WHERE name = '%s'", $module));
|
| 350 |
$info = unserialize($info->info);
|
| 351 |
$name = t($info['name']);
|
| 352 |
}
|
| 353 |
return $name;
|
| 354 |
}
|
| 355 |
|
| 356 |
/**
|
| 357 |
* Page callback to view a help topic.
|
| 358 |
*/
|
| 359 |
function advanced_help_topic_page($module, $topic) {
|
| 360 |
$info = advanced_help_get_topic($module, $topic);
|
| 361 |
if (!$info) {
|
| 362 |
return drupal_not_found();
|
| 363 |
}
|
| 364 |
|
| 365 |
$popup = !empty($_GET['popup']) && user_access('view advanced help popup');
|
| 366 |
|
| 367 |
drupal_set_title($info['title']);
|
| 368 |
|
| 369 |
// Set up breadcrumb.
|
| 370 |
$breadcrumb = array();
|
| 371 |
|
| 372 |
$parent = $info;
|
| 373 |
$pmodule = $module;
|
| 374 |
|
| 375 |
// Loop checker.
|
| 376 |
$checked = array();
|
| 377 |
while (!empty($parent['parent'])) {
|
| 378 |
if (strpos($parent['parent'], '%')) {
|
| 379 |
list($pmodule, $ptopic) = explode('%', $parent['parent']);
|
| 380 |
}
|
| 381 |
else {
|
| 382 |
$ptopic = $parent['parent'];
|
| 383 |
}
|
| 384 |
|
| 385 |
if (!empty($checked[$pmodule][$ptopic])) {
|
| 386 |
break;
|
| 387 |
}
|
| 388 |
$checked[$pmodule][$ptopic] = TRUE;
|
| 389 |
|
| 390 |
$parent = advanced_help_get_topic($pmodule, $ptopic);
|
| 391 |
if (!$parent) {
|
| 392 |
break;
|
| 393 |
}
|
| 394 |
|
| 395 |
$breadcrumb[] = advanced_help_l($parent['title'], "help/$pmodule/$ptopic");
|
| 396 |
}
|
| 397 |
|
| 398 |
$breadcrumb[] = advanced_help_l(advanced_help_get_module_name($pmodule), "admin/advanced_help/$pmodule");
|
| 399 |
$breadcrumb[] = advanced_help_l(t('Help'), "admin/advanced_help");
|
| 400 |
|
| 401 |
$output = advanced_help_view_topic($module, $topic, $popup);
|
| 402 |
if (empty($output)) {
|
| 403 |
$output = t('Missing help topic.');
|
| 404 |
}
|
| 405 |
|
| 406 |
if ($popup) {
|
| 407 |
$GLOBALS['devel_shutdown'] = FALSE; // Prevent devel module from spewing.
|
| 408 |
module_invoke('admin_menu', 'suppress'); // Suppress admin_menu.
|
| 409 |
drupal_set_breadcrumb(array_reverse($breadcrumb));
|
| 410 |
print theme('advanced_help_popup', $output);
|
| 411 |
return;
|
| 412 |
}
|
| 413 |
|
| 414 |
drupal_add_css(drupal_get_path('module', 'advanced_help') . '/help.css');
|
| 415 |
$breadcrumb[] = l(t('Home'), '');
|
| 416 |
drupal_set_breadcrumb(array_reverse($breadcrumb));
|
| 417 |
return $output;
|
| 418 |
}
|
| 419 |
|
| 420 |
/**
|
| 421 |
* Implementation of hook_perm().
|
| 422 |
*/
|
| 423 |
function advanced_help_perm() {
|
| 424 |
return array('view advanced help topic', 'view advanced help popup', 'view advanced help index');
|
| 425 |
}
|
| 426 |
|
| 427 |
/**
|
| 428 |
* Display a help icon with a link to view the topic in a popup.
|
| 429 |
*
|
| 430 |
* @param $module
|
| 431 |
* The module that owns this help topic.
|
| 432 |
* @param $topic
|
| 433 |
* The identifier for the topic
|
| 434 |
* @param $type
|
| 435 |
* - 'icon' to display the question mark icon
|
| 436 |
* - 'title' to display the topic's title
|
| 437 |
* - any other text to display the text. Be sure to t() it!
|
| 438 |
*/
|
| 439 |
function theme_advanced_help_topic($module, $topic, $type = 'icon') {
|
| 440 |
$info = advanced_help_get_topic($module, $topic);
|
| 441 |
if (!$info) {
|
| 442 |
return;
|
| 443 |
}
|
| 444 |
|
| 445 |
switch ($type) {
|
| 446 |
case 'icon':
|
| 447 |
$text = '<span>' . t('Help') . '</span>';
|
| 448 |
$class = 'advanced-help-link';
|
| 449 |
break;
|
| 450 |
case 'title':
|
| 451 |
$text = $info['title'];
|
| 452 |
$class = 'advanced-help-title';
|
| 453 |
break;
|
| 454 |
default:
|
| 455 |
$class = 'advanced-help-title';
|
| 456 |
$text = $type;
|
| 457 |
break;
|
| 458 |
}
|
| 459 |
|
| 460 |
if (user_access('view advanced help popup')) {
|
| 461 |
drupal_add_css(drupal_get_path('module', 'advanced_help') . '/help-icon.css');
|
| 462 |
return l($text, "help/$module/$topic", array(
|
| 463 |
'attributes' => array(
|
| 464 |
'class' => $class,
|
| 465 |
'onclick' => "var w=window.open(this.href, 'advanced_help_window', 'width=". $info['popup width'] .",height=". $info['popup height'] .",scrollbars,resizable'); w.focus(); return false;",
|
| 466 |
'title' => $info['title']
|
| 467 |
),
|
| 468 |
'query' => array('popup' => TRUE),
|
| 469 |
'html' => TRUE)
|
| 470 |
);
|
| 471 |
}
|
| 472 |
else {
|
| 473 |
return l($text, "help/$module/$topic", array(
|
| 474 |
'attributes' => array(
|
| 475 |
'class' => $class,
|
| 476 |
'title' => $info['title']
|
| 477 |
),
|
| 478 |
'html' => TRUE)
|
| 479 |
);
|
| 480 |
}
|
| 481 |
}
|
| 482 |
|
| 483 |
/**
|
| 484 |
* Load and render a help topic.
|
| 485 |
*/
|
| 486 |
function advanced_help_get_topic_filename($module, $topic) {
|
| 487 |
$info = advanced_help_get_topic_file_info($module, $topic);
|
| 488 |
if ($info) {
|
| 489 |
return "./$info[path]/$info[file]";
|
| 490 |
}
|
| 491 |
}
|
| 492 |
/**
|
| 493 |
* Load and render a help topic.
|
| 494 |
*/
|
| 495 |
function advanced_help_get_topic_file_info($module, $topic) {
|
| 496 |
init_theme();
|
| 497 |
global $language;
|
| 498 |
|
| 499 |
$info = advanced_help_get_topic($module, $topic);
|
| 500 |
if (empty($info)) {
|
| 501 |
return;
|
| 502 |
}
|
| 503 |
|
| 504 |
// Search paths:
|
| 505 |
$paths = array(
|
| 506 |
path_to_theme() . '/help', // Allow theme override.
|
| 507 |
drupal_get_path('module', $module) . "/translations/help/$language->language", // Translations.
|
| 508 |
$info['path'], // In same directory as .inc file.
|
| 509 |
);
|
| 510 |
|
| 511 |
foreach ($paths as $path) {
|
| 512 |
if (file_exists("./$path/$info[file]")) {
|
| 513 |
return array('path' => $path, 'file' => $info['file']);
|
| 514 |
}
|
| 515 |
}
|
| 516 |
}
|
| 517 |
|
| 518 |
/**
|
| 519 |
* Load and render a help topic.
|
| 520 |
*/
|
| 521 |
function advanced_help_view_topic($module, $topic, $popup = FALSE) {
|
| 522 |
$file_info = advanced_help_get_topic_file_info($module, $topic);
|
| 523 |
if ($file_info) {
|
| 524 |
$info = advanced_help_get_topic($module, $topic);
|
| 525 |
$file = "./$file_info[path]/$file_info[file]";
|
| 526 |
|
| 527 |
// @todo is this trusted output?
|
| 528 |
$output = file_get_contents($file);
|
| 529 |
// Make some exchanges. The strtr is because url() translates $ into %24
|
| 530 |
// but we need to change it back for the regex replacement.
|
| 531 |
|
| 532 |
// Change 'topic:' to the URL for another help topic.
|
| 533 |
if ($popup) {
|
| 534 |
$output = preg_replace('/href="topic:([^"]+)"/', 'href="' . strtr(url('help/$1', array('query' => 'popup=true')), array('%24' => '$')) . '"', $output);
|
| 535 |
$output = preg_replace('/src="topic:([^"]+)"/', 'src="' . strtr(url('help/$1', array('query' => 'popup=true')), array('%24' => '$')) . '"', $output);
|
| 536 |
$output = preg_replace('/&topic:([^"]+)&/', strtr(url('help/$1', array('query' => 'popup=true')), array('%24' => '$')), $output);
|
| 537 |
}
|
| 538 |
else {
|
| 539 |
$output = preg_replace('/href="topic:([^"]+)"/', 'href="' . strtr(url('help/$1'), array('%24' => '$')) . '"', $output);
|
| 540 |
$output = preg_replace('/src="topic:([^"]+)"/', 'src="' . strtr(url('help/$1'), array('%24' => '$')) . '"', $output);
|
| 541 |
$output = preg_replace('/&topic:([^"]+)&/', strtr(url('help/$1'), array('%24' => '$')), $output);
|
| 542 |
}
|
| 543 |
|
| 544 |
global $base_path;
|
| 545 |
|
| 546 |
// Change 'path:' to the URL to the base help directory.
|
| 547 |
$output = preg_replace('/href="path:([^"]+)"/', 'href="' . $base_path . $info['path'] . '/$1"', $output);
|
| 548 |
$output = preg_replace('/src="path:([^"]+)"/', 'src="' . $base_path . $info['path'] . '/$1"', $output);
|
| 549 |
$output = str_replace('&path&', $base_path . $info['path'] .'/', $output);
|
| 550 |
|
| 551 |
// Change 'trans_path:' to the URL to the actual help directory.
|
| 552 |
$output = preg_replace('/href="trans_path:([^"]+)"/', 'href="' . $base_path . $file_info['path'] . '/$1"', $output);
|
| 553 |
$output = preg_replace('/src="trans_path:([^"]+)"/', 'src="' . $base_path . $file_info['path'] . '/$1"', $output);
|
| 554 |
$output = str_replace('&trans_path&', $base_path . $file_info['path'] .'/', $output);
|
| 555 |
|
| 556 |
// Change 'base_url:' to the URL to the site.
|
| 557 |
$output = preg_replace('/href="base_url:([^"]+)"/', 'href="' . strtr(url('$1'), array('%24' => '$')) . '"', $output);
|
| 558 |
$output = preg_replace('/src="base_url:([^"]+)"/', 'src="' . strtr(url('$1'), array('%24' => '$')) . '"', $output);
|
| 559 |
$output = str_replace('&base_url&', $base_path, $output);
|
| 560 |
|
| 561 |
// Run the line break filter if requested
|
| 562 |
if (!empty($info['line break'])) {
|
| 563 |
// Remove the header since it adds an extra <br /> to the filter.
|
| 564 |
$output = preg_replace('/^<!--[^\n]*-->\n/', '', $output);
|
| 565 |
|
| 566 |
$output = _filter_autop($output);
|
| 567 |
}
|
| 568 |
|
| 569 |
if (!empty($info['navigation'])) {
|
| 570 |
$topics = advanced_help_get_topics();
|
| 571 |
advanced_help_get_topic_hierarchy($topics);
|
| 572 |
if (!empty($topics[$module][$topic]['children'])) {
|
| 573 |
$items = advanced_help_get_tree($topics, $topics[$module][$topic]['children']);
|
| 574 |
$output .= theme('item_list', $items);
|
| 575 |
}
|
| 576 |
|
| 577 |
list($parent_module, $parent_topic) = $topics[$module][$topic]['_parent'];
|
| 578 |
if ($parent_topic) {
|
| 579 |
$parent = $topics[$module][$topic]['_parent'];
|
| 580 |
$up = "help/$parent[0]/$parent[1]";
|
| 581 |
}
|
| 582 |
else {
|
| 583 |
$up = "admin/advanced_help/$module";
|
| 584 |
}
|
| 585 |
|
| 586 |
$siblings = $topics[$parent_module][$parent_topic]['children'];
|
| 587 |
uasort($siblings, 'advanced_help_uasort');
|
| 588 |
$prev = $next = NULL;
|
| 589 |
$found = FALSE;
|
| 590 |
foreach ($siblings as $sibling) {
|
| 591 |
list($sibling_module, $sibling_topic) = $sibling;
|
| 592 |
if ($found) {
|
| 593 |
$next = $sibling;
|
| 594 |
break;
|
| 595 |
}
|
| 596 |
if ($sibling_module == $module && $sibling_topic == $topic) {
|
| 597 |
$found = TRUE;
|
| 598 |
continue;
|
| 599 |
}
|
| 600 |
$prev = $sibling;
|
| 601 |
}
|
| 602 |
|
| 603 |
if ($prev || $up || $next) {
|
| 604 |
$navigation = '<div class="help-navigation clear-block">';
|
| 605 |
|
| 606 |
if ($prev) {
|
| 607 |
$navigation .= advanced_help_l('<< ' . $topics[$prev[0]][$prev[1]]['title'], "help/$prev[0]/$prev[1]", array('attributes' => array('class' => 'help-left')));
|
| 608 |
}
|
| 609 |
if ($up) {
|
| 610 |
$navigation .= advanced_help_l(t('Up'), $up, array('attributes' => array('class' => $prev ? 'help-up' : 'help-up-noleft')));
|
| 611 |
}
|
| 612 |
if ($next) {
|
| 613 |
$navigation .= advanced_help_l($topics[$next[0]][$next[1]]['title'] . ' >>', "help/$next[0]/$next[1]", array('attributes' => array('class' => 'help-right')));
|
| 614 |
}
|
| 615 |
|
| 616 |
$navigation .= '</div>';
|
| 617 |
|
| 618 |
$output .= $navigation;
|
| 619 |
}
|
| 620 |
}
|
| 621 |
|
| 622 |
if (!empty($info['css'])) {
|
| 623 |
drupal_add_css($info['path'] . '/' . $info['css']);
|
| 624 |
}
|
| 625 |
|
| 626 |
$output = '<div class="advanced-help-topic">' . $output . '</div>';
|
| 627 |
drupal_alter('advanced_help_topic', $output, $popup);
|
| 628 |
return $output;
|
| 629 |
}
|
| 630 |
}
|
| 631 |
|
| 632 |
/**
|
| 633 |
* Get the information for a single help topic.
|
| 634 |
*/
|
| 635 |
function advanced_help_get_topic($module, $topic) {
|
| 636 |
$topics = advanced_help_get_topics();
|
| 637 |
if (!empty($topics[$module][$topic])) {
|
| 638 |
return $topics[$module][$topic];
|
| 639 |
}
|
| 640 |
}
|
| 641 |
|
| 642 |
/**
|
| 643 |
* Search the system for all available help topics.
|
| 644 |
*/
|
| 645 |
function advanced_help_get_topics() {
|
| 646 |
$cache = _advanced_help_parse_ini();
|
| 647 |
return $cache['topics'];
|
| 648 |
}
|
| 649 |
|
| 650 |
function advanced_help_get_settings() {
|
| 651 |
$cache = _advanced_help_parse_ini();
|
| 652 |
return $cache['settings'];
|
| 653 |
}
|
| 654 |
|
| 655 |
function _advanced_help_parse_ini() {
|
| 656 |
static $cache = NULL;
|
| 657 |
|
| 658 |
if (!isset($cache)) {
|
| 659 |
$cache = array('topics' => array(), 'settings' => array());
|
| 660 |
|
| 661 |
$help_path = drupal_get_path('module', 'advanced_help') . '/modules';
|
| 662 |
foreach (module_list() as $module) {
|
| 663 |
$module_path = drupal_get_path('module', $module);
|
| 664 |
$info = array();
|
| 665 |
if (file_exists("$module_path/help/$module.help.ini")) {
|
| 666 |
$path = "$module_path/help";
|
| 667 |
$info = parse_ini_file("./$module_path/help/$module.help.ini", TRUE);
|
| 668 |
}
|
| 669 |
elseif (file_exists("$help_path/$module/$module.help.ini")) {
|
| 670 |
$path = "$help_path/$module";
|
| 671 |
$info = parse_ini_file("./$help_path/$module/$module.help.ini", TRUE);
|
| 672 |
}
|
| 673 |
elseif (!file_exists("$module_path/help")) {
|
| 674 |
// Look for one or more README files.
|
| 675 |
$files = file_scan_directory("./$module_path", '^(README|readme).*\.(txt|TXT)$', array('.', '..', 'CVS'), 0, FALSE);
|
| 676 |
$path = "./$module_path";
|
| 677 |
foreach ($files as $name => $fileinfo) {
|
| 678 |
$info[$fileinfo->basename] = array('line break' => TRUE, 'readme file' => TRUE, 'file' => $fileinfo->basename, 'title' => $fileinfo->name);
|
| 679 |
}
|
| 680 |
}
|
| 681 |
|
| 682 |
if (!empty($info)) {
|
| 683 |
// Get translated titles:
|
| 684 |
global $language;
|
| 685 |
$translation = array();
|
| 686 |
if (file_exists("$module_path/translations/help/$language->language/$module.help.ini")) {
|
| 687 |
$translation = parse_ini_file("$module_path/translations/help/$language->language/$module.help.ini", TRUE);
|
| 688 |
}
|
| 689 |
|
| 690 |
$cache['settings'][$module] = array();
|
| 691 |
if (!empty($info['advanced help settings'])) {
|
| 692 |
$cache['settings'][$module] = $info['advanced help settings'];
|
| 693 |
unset($info['advanced help settings']);
|
| 694 |
|
| 695 |
// Check translated strings for translatable global settings.
|
| 696 |
if (isset($translation['advanced help settings']['name'])) {
|
| 697 |
$cache['settings']['name'] = $translation['advanced help settings']['name'];
|
| 698 |
}
|
| 699 |
if (isset($translation['advanced help settings']['index name'])) {
|
| 700 |
$cache['settings']['index name'] = $translation['advanced help settings']['index name'];
|
| 701 |
}
|
| 702 |
|
| 703 |
}
|
| 704 |
|
| 705 |
foreach ($info as $name => $topic) {
|
| 706 |
// Each topic should have a name, a title, a file and of course the path.
|
| 707 |
$file = !empty($topic['file']) ? $topic['file'] : $name;
|
| 708 |
$cache['topics'][$module][$name] = array(
|
| 709 |
'name' => $name,
|
| 710 |
'title' => !empty($translation[$name]['title']) ? $translation[$name]['title'] : $topic['title'],
|
| 711 |
'weight' => isset($topic['weight']) ? $topic['weight'] : 0,
|
| 712 |
'parent' => isset($topic['parent']) ? $topic['parent'] : 0,
|
| 713 |
'popup width' => isset($topic['popup width']) ? $topic['popup width'] : 500,
|
| 714 |
'popup height' => isset($topic['popup height']) ? $topic['popup height'] : 500,
|
| 715 |
'file' => isset($topic['readme file']) ? $file : $file . '.html', // require extension
|
| 716 |
'path' => $path, // not in .ini file
|
| 717 |
'line break' => isset($topic['line break']) ? $topic['line break'] : (isset($cache['settings'][$module]['line break']) ? $cache['settings'][$module]['line break'] : FALSE),
|
| 718 |
'navigation' => isset($topic['navigation']) ? $topic['navigation'] : (isset($cache['settings'][$module]['navigation']) ? $cache['settings'][$module]['navigation'] : TRUE),
|
| 719 |
'css' => isset($topic['css']) ? $topic['css'] : (isset($cache['settings'][$module]['css']) ? $cache['settings'][$module]['css'] : NULL),
|
| 720 |
);
|
| 721 |
}
|
| 722 |
}
|
| 723 |
}
|
| 724 |
drupal_alter('advanced_help_topic_info', $cache);
|
| 725 |
}
|
| 726 |
return $cache;
|
| 727 |
}
|
| 728 |
|
| 729 |
/**
|
| 730 |
* Implementation of hook_search()
|
| 731 |
*/
|
| 732 |
function advanced_help_search($op = 'search', $keys = null) {
|
| 733 |
switch ($op) {
|
| 734 |
case 'name':
|
| 735 |
return t('Help');
|
| 736 |
case 'reset':
|
| 737 |
variable_del('advanced_help_last_cron');
|
| 738 |
return;
|
| 739 |
case 'search':
|
| 740 |
$topics = advanced_help_get_topics();
|
| 741 |
$find = do_search($keys, 'help');
|
| 742 |
if (!$find) {
|
| 743 |
return;
|
| 744 |
}
|
| 745 |
|
| 746 |
$results = array();
|
| 747 |
|
| 748 |
$placeholders = implode(', ', array_fill(0, count($find), '%d'));
|
| 749 |
foreach ($find as $item) {
|
| 750 |
$sids[] = $item->sid;
|
| 751 |
}
|
| 752 |
|
| 753 |
$result = db_query("SELECT * FROM {advanced_help_index} WHERE sid IN ($placeholders)", $sids);
|
| 754 |
while ($sid = db_fetch_object($result)) {
|
| 755 |
// Guard against removed help topics that are still indexed.
|
| 756 |
if (empty($topics[$sid->module][$sid->topic])) {
|
| 757 |
continue;
|
| 758 |
}
|
| 759 |
$info = $topics[$sid->module][$sid->topic];
|
| 760 |
$text = advanced_help_view_topic($sid->module, $sid->topic);
|
| 761 |
$results[] = array('link' => advanced_help_url("help/$sid->module/$sid->topic"),
|
| 762 |
'title' => $info['title'],
|
| 763 |
'snippet' => search_excerpt($keys, $text));
|
| 764 |
}
|
| 765 |
return $results;
|
| 766 |
}
|
| 767 |
}
|
| 768 |
|
| 769 |
/**
|
| 770 |
* Get or create an sid (search id) that correllates to each topic for
|
| 771 |
* the search system.
|
| 772 |
*/
|
| 773 |
function advanced_help_get_sids(&$topics) {
|
| 774 |
global $language;
|
| 775 |
$result = db_query("SELECT * FROM {advanced_help_index} WHERE language = '%s'", $language->language);
|
| 776 |
while ($sid = db_fetch_object($result)) {
|
| 777 |
if (empty($topics[$sid->module][$sid->topic])) {
|
| 778 |
db_query("DELETE FROM {advanced_help_index} WHERE sid = %d", $sid->sid);
|
| 779 |
}
|
| 780 |
else {
|
| 781 |
$topics[$sid->module][$sid->topic]['sid'] = $sid->sid;
|
| 782 |
}
|
| 783 |
}
|
| 784 |
}
|
| 785 |
|
| 786 |
/**
|
| 787 |
* Implementation of hook_update_index().
|
| 788 |
*/
|
| 789 |
function advanced_help_update_index() {
|
| 790 |
global $language;
|
| 791 |
|
| 792 |
// If we got interrupted by limit, this will contain the last module
|
| 793 |
// and topic we looked at.
|
| 794 |
$last = variable_get('advanced_help_last_cron', array('time' => 0));
|
| 795 |
$limit = intval(variable_get('search_cron_limit', 100));
|
| 796 |
$topics = advanced_help_get_topics();
|
| 797 |
advanced_help_get_sids($topics);
|
| 798 |
|
| 799 |
$count = 0;
|
| 800 |
|
| 801 |
foreach ($topics as $module => $module_topics) {
|
| 802 |
// Fast forward if necessary.
|
| 803 |
if (!empty($last['module']) && $last['module'] != $module) {
|
| 804 |
continue;
|
| 805 |
}
|
| 806 |
|
| 807 |
foreach ($module_topics as $topic => $info) {
|
| 808 |
// Fast forward if necessary.
|
| 809 |
if (!empty($last['topic']) && $last['topic'] != $topic) {
|
| 810 |
continue;
|
| 811 |
}
|
| 812 |
|
| 813 |
// If we've been looking to catch up, and we have, reset so we
|
| 814 |
// stop fast forwarding.
|
| 815 |
if (!empty($last['module'])) {
|
| 816 |
unset($last['topic']);
|
| 817 |
unset($last['module']);
|
| 818 |
}
|
| 819 |
|
| 820 |
$file = advanced_help_get_topic_filename($module, $topic);
|
| 821 |
if ($file && (empty($info['sid']) || filemtime($file) > $last['time'])) {
|
| 822 |
if (empty($info['sid'])) {
|
| 823 |
db_query("INSERT INTO {advanced_help_index} (module, topic, language) VALUES ('%s', '%s', '%s')", $module, $topic, $language->language);
|
| 824 |
$info['sid'] = db_last_insert_id('advanced_help_index', 'sid');
|
| 825 |
}
|
| 826 |
|
| 827 |
search_index($info['sid'], 'help', '<h1>' . $info['title'] . '</h1>' . file_get_contents($file));
|
| 828 |
$count++;
|
| 829 |
if ($count >= $limit) {
|
| 830 |
$last['topic'] = $topic;
|
| 831 |
$last['module'] = $module;
|
| 832 |
// Don't change time if we stop.
|
| 833 |
variable_set('advanced_help_last_cron', $last);
|
| 834 |
return;
|
| 835 |
}
|
| 836 |
}
|
| 837 |
}
|
| 838 |
}
|
| 839 |
variable_set('advanced_help_last_cron', array('time' => time()));
|
| 840 |
}
|
| 841 |
|
| 842 |
/**
|
| 843 |
* Fill in a bunch of page variables for our specialized popup page.
|
| 844 |
*/
|
| 845 |
function template_preprocess_advanced_help_popup(&$variables) {
|
| 846 |
// Add favicon.
|
| 847 |
if (theme_get_setting('toggle_favicon')) {
|
| 848 |
drupal_set_html_head('<link rel="shortcut icon" href="'. check_url(theme_get_setting('favicon')) .'" type="image/x-icon" />');
|
| 849 |
}
|
| 850 |
|
| 851 |
global $theme;
|
| 852 |
// Construct page title.
|
| 853 |
if (drupal_get_title()) {
|
| 854 |
$head_title = array(strip_tags(drupal_get_title()), variable_get('site_name', 'Drupal'));
|
| 855 |
}
|
| 856 |
else {
|
| 857 |
$head_title = array(variable_get('site_name', 'Drupal'));
|
| 858 |
if (variable_get('site_slogan', '')) {
|
| 859 |
$head_title[] = variable_get('site_slogan', '');
|
| 860 |
}
|
| 861 |
}
|
| 862 |
|
| 863 |
drupal_add_css(drupal_get_path('module', 'advanced_help') . '/help-popup.css');
|
| 864 |
drupal_add_css(drupal_get_path('module', 'advanced_help') . '/help.css');
|
| 865 |
|
| 866 |
$variables['head_title'] = implode(' | ', $head_title);
|
| 867 |
$variables['base_path'] = base_path();
|
| 868 |
$variables['front_page'] = url();
|
| 869 |
$variables['breadcrumb'] = theme('breadcrumb', drupal_get_breadcrumb());
|
| 870 |
$variables['feed_icons'] = drupal_get_feeds();
|
| 871 |
$variables['head'] = drupal_get_html_head();
|
| 872 |
$variables['language'] = $GLOBALS['language'];
|
| 873 |
$variables['language']->dir = $GLOBALS['language']->direction ? 'rtl' : 'ltr';
|
| 874 |
$variables['logo'] = theme_get_setting('logo');
|
| 875 |
$variables['messages'] = theme('status_messages');
|
| 876 |
$variables['site_name'] = (theme_get_setting('toggle_name') ? variable_get('site_name', 'Drupal') : '');
|
| 877 |
$variables['css'] = drupal_add_css();
|
| 878 |
$css = drupal_add_css();
|
| 879 |
|
| 880 |
// Remove theme css.
|
| 881 |
foreach ($css as $media => $types) {
|
| 882 |
if (isset($css[$media]['theme'])) {
|
| 883 |
$css[$media]['theme'] = array();
|
| 884 |
}
|
| 885 |
}
|
| 886 |
|
| 887 |
$variables['styles'] = drupal_get_css($css);
|
| 888 |
$variables['scripts'] = drupal_get_js();
|
| 889 |
$variables['title'] = drupal_get_title();
|
| 890 |
// Closure should be filled last.
|
| 891 |
$variables['closure'] = theme('closure');
|
| 892 |
}
|
| 893 |
|
| 894 |
/**
|
| 895 |
* Format a link but preserve popup identity.
|
| 896 |
*/
|
| 897 |
function advanced_help_l($text, $dest, $options = array()) {
|
| 898 |
$popup = !empty($_GET['popup']) && user_access('view advanced help popup');
|
| 899 |
if ($popup) {
|
| 900 |
if (empty($options['query'])) {
|
| 901 |
$options['query'] = array();
|
| 902 |
}
|
| 903 |
|
| 904 |
if (is_array($options['query'])) {
|
| 905 |
$options['query'] += array('popup' => TRUE);
|
| 906 |
}
|
| 907 |
else {
|
| 908 |
$options['query'] += '&popup=TRUE';
|
| 909 |
}
|
| 910 |
}
|
| 911 |
|
| 912 |
return l($text, $dest, $options);
|
| 913 |
}
|
| 914 |
|
| 915 |
/**
|
| 916 |
* Format a URL but preserve popup identity.
|
| 917 |
*/
|
| 918 |
function advanced_help_url($dest, $options = array()) {
|
| 919 |
$popup = !empty($_GET['popup']) && user_access('view advanced help popup');
|
| 920 |
if ($popup) {
|
| 921 |
if (empty($options['query'])) {
|
| 922 |
$options['query'] = array();
|
| 923 |
}
|
| 924 |
|
| 925 |
$options['query'] += array('popup' => TRUE);
|
| 926 |
}
|
| 927 |
|
| 928 |
return url($dest, $options);
|
| 929 |
}
|