diff options
Diffstat (limited to 'Zotlabs')
-rw-r--r-- | Zotlabs/Lib/Traits/HelpHelper.php | 68 | ||||
-rw-r--r-- | Zotlabs/Module/Help.php | 191 | ||||
-rw-r--r-- | Zotlabs/Widget/Helpindex.php | 63 |
3 files changed, 262 insertions, 60 deletions
diff --git a/Zotlabs/Lib/Traits/HelpHelper.php b/Zotlabs/Lib/Traits/HelpHelper.php new file mode 100644 index 000000000..f0dca35d0 --- /dev/null +++ b/Zotlabs/Lib/Traits/HelpHelper.php @@ -0,0 +1,68 @@ +<?php + +namespace Zotlabs\Lib\Traits; + +use CommerceGuys\Intl\Language\LanguageRepository; + +trait HelpHelper { + + // PHP versions before 8.2 does not support trait constants, + // Leave this commented out until we drop support for PHP 8.1. + // + // const VALID_FILE_EXT = ['md', 'bb', 'html']; + + private string $file_name = ''; + private string $file_type = ''; + + /** + * Determines help language. + * + * If the language was specified in the URL, override the language preference + * of the browser. Default to English if both of these are absent. + * + * Updates the `$lang` property of the module. + */ + private function determine_help_language() { + + $language_repository = new LanguageRepository; + $languages = $language_repository->getList(); + + if(array_key_exists(argv(1), $languages)) { + $lang = argv(1); + $from_url = true; + } else { + $lang = \App::$language; + if(! isset($lang)) + $lang = 'en'; + + $from_url = false; + } + + $this->lang = array('language' => $lang, 'from_url' => $from_url); + } + + /** + * Find the full path name of the file, given it's base path and + * the language of the request. + * + * @param string $base_path The path of the file to find, relative to the + * doc root path, and without the extension. + */ + private function find_help_file(string $base_path, string $lang): void { + + // Use local variable until we can use trait constants. + $valid_file_ext = ['md', 'bb', 'html']; + + $base_path = "doc/{$lang}/${base_path}"; + + foreach ($valid_file_ext as $ext) { + $path = "{$base_path}.{$ext}"; + if (file_exists($path)) { + $this->file_name = $path; + $this->file_type = $ext; + + break; + } + } + } +} diff --git a/Zotlabs/Module/Help.php b/Zotlabs/Module/Help.php index 55ac80842..00946368f 100644 --- a/Zotlabs/Module/Help.php +++ b/Zotlabs/Module/Help.php @@ -1,7 +1,7 @@ <?php namespace Zotlabs\Module; -require_once('include/help.php'); +use Michelf\MarkdownExtra; /** * You can create local site resources in doc/Site.md and either link to doc/Home.md for the standard resources @@ -14,7 +14,50 @@ require_once('include/help.php'); */ class Help extends \Zotlabs\Web\Controller { - function get() { + use \Zotlabs\Lib\Traits\HelpHelper; + + private string $heading_slug = ''; + + /** + * Associative array containing the detected language. + */ + public array $lang = [ + 'language' => 'en', //! Detected language, 2-letter ISO 639-1 code ("en") + 'from_url' => false, //! true if language from URL overrides browser default + ]; + + /** + * Pre-check before processing request. + * + * Determine language requested, and ensure that a topic was requested. + * If no topic was requested, redirect to the about page, and abort + * processing. + */ + public function init() { + $this->determine_help_language(); + + if (argc() === 1) { + goaway("/help/{$this->lang['language']}/about/about"); + killme(); + } + } + + /** + * Process get request for the help module. + * + * Loads the correct help file from the `doc/` directory, and passes it to + * the help template in `view/tpl/help.tpl`. + * + * If the requested help topic does not exist for the currently selected + * language, a 404 status is returned instead. + * + * This function currently also handles search and serving static assets + * that may be used by the help files. + * + * @return string The rendered help page or a 404 page if help topic was + * not found. + */ + public function get() { nav_set_selected('Help'); $o = ''; @@ -81,6 +124,119 @@ class Help extends \Zotlabs\Web\Controller { killme(); } + // + // The args to the module will be along this pattern: + // + // help/<lang>/<subdir..>/<topic> + // + // Where `<lang>` is the language which we want to fetch the topic. This + // element is optional, but will be used to override the browser language + // preference if it exists. + // + // There may be zero or more `<subdir...>` elements. If there are any + // present, the first subdir will be used as the slug to find the + // heading of the help page. + // + // The `<topic>` should be the name of a file within the given language + // and subdirectory tree under the `doc/` directory of the site file + // system. The topic is given _without_ the file extension, which will be + // determined by the module. + // + // The valid file extensions for help topic are: + // + // - `.md` for markdown formatted source files. + // - `.bb` for bbcode formatted source files. + // - `.html` for help topics in html format. + // + + // Strip away the module name from the args + $args = array_slice(\App::$argv, 1); + + // Remove language if necessary + // + // The language was determined during pre-request processing in the + // `init` function. + if ($this->lang['from_url']) { + array_shift($args); + } + + // Keep the first remaining arg as the heading slug + $this->heading_slug = $args[0]; + + // Locate the file for the topic in the doc directory + $this->find_help_file(implode('/', $args), $this->lang['language']); + + $this->set_page_title(); + + if (empty($this->file_name)) { + header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . t('Not Found')); + $tpl = get_markup_template("404.tpl"); + return replace_macros($tpl, array( + '$message' => t('Page not found.') + )); + + } else { + $tpl = get_markup_template('help.tpl'); + return replace_macros($tpl, [ '$module' => $this ]); + } + } + + public function render_content(): string { + return $this->render_help_file($this->file_name, $this->file_type); + } + + public function render_help_file(string $file_name, string $file_type): string { + $raw_text = file_get_contents($file_name); + + switch ($file_type) { + case 'md': + // We need to escape the `#include` statements in the original file, + // to be sure it's not rendered as a heading by markdown. + $raw_text = preg_replace('/#include/ism', '%%include', $raw_text); + $content = MarkdownExtra::defaultTransform($raw_text); + $content = preg_replace('/%%include/ism', '#include', $content); + break; + + case 'bb': + $content = zidify_links(bbcode($raw_text)); + break; + + case 'html': + $content = parseIdentityAwareHTML($raw_text); + break; + } + + // Replace includes with the contents of the included file + $content = preg_replace_callback( + "/#include (.*?)\;/ism", + function ($matches) { + $sub_file_type = array_pop(explode('.', $matches[1])); + $included_content = $this->render_help_file($matches[1], $sub_file_type); + return str_replace($matches[0], $included_content, $matches[0]); + }, + $content + ); + + return translate_projectname($content); + } + + public function get_page_title(): string { + $title = t('$Projectname Documentation'); + $heading = $this->get_heading(); + + if (! empty($heading)) { + $title .= ': ' . $heading; + } + + return $title; + } + + public function get_toc_heading(): string { + return t('Contents'); + } + + + private function get_heading(): string { $headings = [ 'about' => t('About'), 'member' => t('Members'), @@ -89,21 +245,22 @@ class Help extends \Zotlabs\Web\Controller { 'tutorials' => t('Tutorials') ]; - $heading = ''; - if(array_key_exists(argv(1), $headings)) - $heading = $headings[argv(1)]; - - $content = get_help_content(); - - $language = determine_help_language()['language']; - - return replace_macros(get_markup_template('help.tpl'), array( - '$title' => t('$Projectname Documentation'), - '$tocHeading' => t('Contents'), - '$content' => $content, - '$heading' => $heading, - '$language' => $language - )); + if(array_key_exists($this->heading_slug, $headings)) { + return $headings[$this->heading_slug]; + } else { + return ''; + } } + /** + * Set the page title to an unslugified version of the file name. + * + * @Note This modifies the global `App::$page['title']` property. + */ + private function set_page_title(): void { + $title = basename($this->file_name, ".{$this->file_type}"); + \App::$page['title'] = + t('Help:') . ' ' + . ucwords(str_replace(['-', '_'],' ',notags($title))); + } } diff --git a/Zotlabs/Widget/Helpindex.php b/Zotlabs/Widget/Helpindex.php index 63e686d3a..a7120b47f 100644 --- a/Zotlabs/Widget/Helpindex.php +++ b/Zotlabs/Widget/Helpindex.php @@ -1,6 +1,9 @@ <?php - /** + * Widget to show the help index. + * + * By default used by the left sidebar by the help module. + * * * Name: Help index * * Description: Help pages index */ @@ -9,54 +12,28 @@ namespace Zotlabs\Widget; class Helpindex { - function widget($arr) { - - require_once('include/help.php'); - - $o = '<div class="widget">'; - - $level_0 = get_help_content('sitetoc'); - if(! $level_0) { - $path = 'toc'; - $x = determine_help_language(); - $lang = $x['language']; - if($lang !== 'en') { - $path = $lang . '/toc'; - } - $level_0 = get_help_content($path); - } + use \Zotlabs\Lib\Traits\HelpHelper; - $level_0 = preg_replace('/\<ul(.*?)\>/','<ul class="nav nav-pills flex-column">',$level_0); + private string $contents = ''; - $levels = array(); + function widget() { + $this->determine_help_language(); + $this->find_help_file('toc', $this->lang['language']); - // TODO: Implement support for translations in hierarchical table of content files - /* - if(argc() > 2) { - $path = ''; - for($x = 1; $x < argc(); $x ++) { - $path .= argv($x) . '/'; - $y = get_help_content($path . 'sitetoc'); - if(! $y) - $y = get_help_content($path . 'toc'); - if($y) - $levels[] = preg_replace('/\<ul(.*?)\>/','<ul class="nav nav-pills flex-column">',$y); - } - } - */ - - if($level_0) - $o .= $level_0; - if($levels) { - foreach($levels as $l) { - $o .= '<br /><br />'; - $o .= $l; - } + if (! empty($this->file_name)) { + $this->contents = file_get_contents($this->file_name); } - $o .= '</div>'; + $tpl = get_markup_template('widget.tpl'); + return replace_macros($tpl, [ '$widget' => $this ]); + } + + public function title(): string { + return t('Help Contents'); + } - return $o; + public function contents(): string { + return $this->contents; } } |