diff --git a/code/DocumentationParser.php b/code/DocumentationParser.php index fe5374c..61bbe54 100755 --- a/code/DocumentationParser.php +++ b/code/DocumentationParser.php @@ -44,7 +44,7 @@ class DocumentationParser { public static function parse(DocumentationPage $page, $baselink = null) { if(!$page || (!$page instanceof DocumentationPage)) return false; - $md = $page->getMarkdown(); + $md = $page->getMarkdown(true); // Pre-processing $md = self::rewrite_image_links($md, $page); diff --git a/code/DocumentationService.php b/code/DocumentationService.php index 453fba1..4b3747f 100755 --- a/code/DocumentationService.php +++ b/code/DocumentationService.php @@ -76,6 +76,20 @@ class DocumentationService { * @var bool */ private static $automatic_registration = true; + + /** + * by default pagenumbers start high at 10.000 + * + * @var integer + */ + private static $pagenumber_start_at = 10000; + + /** + * allow the use of key/value pairs in comments + * + * @var boolean + */ + private static $meta_comments_enabled = false; /** * Return the allowed extensions @@ -138,6 +152,43 @@ class DocumentationService { public static function automatic_registration_enabled() { return self::$automatic_registration; } + + /** + * set the number to start default pagenumbering, allowing room for + * custom pagenumbers below. + * + * @param int $number + */ + public static function start_pagenumbers_at($number = 10000) { + if (is_int($number)) self::$pagenumber_start_at = $number; + } + + /** + * return the startlevel for default pagenumbering + * + * @return int + */ + public static function get_pagenumber_start_at() { + return self::$pagenumber_start_at; + } + + /** + * Allow the use of key/value pairs in comments? + * + * @param bool $allow + */ + public static function enable_meta_comments($allow = true) { + self::$meta_comments_enabled = (bool) $allow; + } + + /** + * can we use key/value pairs + * + * @return bool + */ + public static function meta_comments_enabled() { + return self::$meta_comments_enabled; + } /** * Return the entities which are listed for documentation. Optionally only @@ -459,6 +510,7 @@ class DocumentationService { */ public static function get_pages_from_folder($entity, $relativePath = false, $recursive = true, $version = 'trunk', $lang = 'en') { $output = new ArrayList(); + $metaCommentsEnabled = self::meta_comments_enabled(); $pages = array(); if(!$entity instanceof DocumentationEntity) @@ -475,6 +527,7 @@ class DocumentationService { } if(count($pages) > 0) { + $pagenumber = self::get_pagenumber_start_at(); natsort($pages); foreach($pages as $key => $pagePath) { @@ -497,12 +550,17 @@ class DocumentationService { // does this page act as a folder? $path = $page->getPath(); if (is_dir($path)) { $page->setIsFolder(true); } - + + $page->setPagenumber($pagenumber++); + + // we need the markdown to get the comments + if ($metaCommentsEnabled) $page->getMarkdown(); + $output->push($page); } } - return $output; + return ($metaCommentsEnabled)? $output->sort('pagenumber') : $output; } /** diff --git a/code/models/DocumentationPage.php b/code/models/DocumentationPage.php index b5a20d2..2345a63 100755 --- a/code/models/DocumentationPage.php +++ b/code/models/DocumentationPage.php @@ -42,6 +42,12 @@ class DocumentationPage extends ViewableData { */ protected $isFolder = false; + /** + * + * @var integer + */ + protected $pagenumber = 0; + /** * @param Boolean */ @@ -56,6 +62,14 @@ class DocumentationPage extends ViewableData { return $this->isFolder; } + /** + * + * @param int $number + */ + public function setPagenumber($number = 0) { + if (is_int($number )) $this->pagenumber = $number; + } + /** * @return DocumentationEntity */ @@ -247,16 +261,19 @@ class DocumentationPage extends ViewableData { * * @return string */ - function getMarkdown() { + function getMarkdown($removeMetaData = false) { try { $path = $this->getPath(true); if($path) { $ext = $this->getExtension(); - - if(DocumentationService::is_valid_extension($ext)) { - return file_get_contents($path); - } + + if(empty($ext) || DocumentationService::is_valid_extension($ext)) { + if ($md = file_get_contents($path)) { + if ($this->title != 'Index') $this->getMetadataFromComments($md, $removeMetaData); + } + return $md; + } } } catch(InvalidArgumentException $e) {} @@ -274,4 +291,42 @@ class DocumentationPage extends ViewableData { function getHTML($version, $lang = 'en') { return DocumentationParser::parse($this, $this->entity->getRelativeLink($version, $lang)); } + + /** + * get metadata from the first html block in the page, then remove the + * block on request + * + * @param DocumentationPage $md + * @param bool $remove + */ + public function getMetadataFromComments(&$md, $removeMetaData = false) { + if($md && DocumentationService::meta_comments_enabled()) { + + // get the text up to the first whiteline + $extPattern = "/^(.+)\n(\r)*\n/Uis"; + $matches = preg_match($extPattern, $md, $block); + if($matches && $block[1]) { + $metaDataFound = false; + + // find the key/value pairs + $intPattern = '/(?[A-Za-z][A-Za-z0-9_-]+)[\t]*:[\t]*(?[^:\n\r\/]+)/x'; + $matches = preg_match_all($intPattern, $block[1], $meta); + + foreach($meta['key'] as $index => $key) { + if(isset($meta['value'][$index])) { + + // check if a property exists for this key + if (property_exists(get_class(), $key)) { + $this->setMetaData($key, $meta['value'][$index]); + $metaDataFound = true; + } + } + } + // optionally remove the metadata block (only on the page that is displayed) + if ($metaDataFound && $removeMetaData) { + $md = preg_replace($extPattern, '', $md); + } + } + } + } } \ No newline at end of file diff --git a/docs/en/Configuration-Options.md b/docs/en/Configuration-Options.md index 89aaf64..0c62420 100755 --- a/docs/en/Configuration-Options.md +++ b/docs/en/Configuration-Options.md @@ -54,5 +54,51 @@ to new structures. )); +## Custom metadata and pagesorting +Custom metadata can be added to the head of the MarkDown file like this: + + pagenumber: 1 + title: A custom title + + +Make sure to add an empty line to separate the metadata from the content of +the file. + +You now need to explicitly enable the use of metadata by adding the following to +your _config.php: + + ```php + DocumentationService::enable_meta_comments(); + ``` + +**Note:** SilverStripe needs to read the contents of each page to retrieve the +metadata. This is expensive, so if you do not plan to use custom sorting, +do not enable this feature: + +### Custom page sorting + +By default pages in the lefthand menu are sorted alphabetically. Adding a +pagenumber to the metadata, like in the example above, allows for custom +pagenumbering. + +**Note:** although folders appear in the menu as 'pages', you obviously can't +number them, so you need to number their index.php page instead. + +Pages that have no custom pagenumber, keep their original +order, but for them not to interfere with custom sort, they also receive a +pagenumber, starting at 10.000. + +You can change this starting point for default pagenumbers: + + ```php + DocumentationService:: start_pagenumbers_at(80); + ``` + +### Other key-value pairs + +Basically all DocumentationPage properties can be added to the metadata comment +block. Beware that the outcome isn't always predictable. Adding a title +property to the block will change the menu title, but the breadcrumbs +are at this time not yet supported. \ No newline at end of file