From 13fe8cbe424ecbd5327c89da82a0291dd129600c Mon Sep 17 00:00:00 2001 From: theWituch Date: Sat, 18 Dec 2021 13:18:57 +0100 Subject: [PATCH 1/9] Allow to use only Twigs {{ toc }} in template without [toc] in page .md --- TableOfContents.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TableOfContents.php b/TableOfContents.php index a9cc9d5..1fc5f2c 100644 --- a/TableOfContents.php +++ b/TableOfContents.php @@ -162,11 +162,12 @@ public function onContentParsed(&$content) foreach ($nodes as $node) { if (trim($node->nodeValue) === "[toc]") { $node->parentNode->replaceChild($div_element, $node); - $content = preg_replace(array("/<(!DOCTYPE|\?xml).+?>/", "/<\/?(html|body)>/"), array("", ""), $document->saveHTML()); break; } } + $content = preg_replace(array("/<(!DOCTYPE|\?xml).+?>/", "/<\/?(html|body)>/"), array("", ""), $document->saveHTML()); + // Save the TOC element as string $this->toc_element_xml = $div_element->ownerDocument->saveXML($div_element); } From 758ad98c8dff5779ad0a08349f2755d1ce468403 Mon Sep 17 00:00:00 2001 From: theWituch Date: Sat, 18 Dec 2021 22:27:59 +0100 Subject: [PATCH 2/9] Don't store special string of generated TOC --- TableOfContents.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/TableOfContents.php b/TableOfContents.php index 1fc5f2c..fd388cb 100644 --- a/TableOfContents.php +++ b/TableOfContents.php @@ -25,7 +25,7 @@ class TableOfContents extends AbstractPicoPlugin 'heading' => null, ); - protected $min_headers, $min_level, $max_level, $tag, $style, $heading, $toc_element_xml; + protected $min_headers, $min_level, $max_level, $tag, $style, $heading; protected $available_tags = ['ol', 'ul']; protected $available_styles = ['numbers', 'bullets', 'none', 'default']; @@ -167,9 +167,6 @@ public function onContentParsed(&$content) } $content = preg_replace(array("/<(!DOCTYPE|\?xml).+?>/", "/<\/?(html|body)>/"), array("", ""), $document->saveHTML()); - - // Save the TOC element as string - $this->toc_element_xml = $div_element->ownerDocument->saveXML($div_element); } /** @@ -182,7 +179,7 @@ public function onContentParsed(&$content) */ public function onPageRendering(&$templateName, array &$twigVariables) { - $twigVariables['toc'] = new Twig_Markup($this->toc_element_xml, 'UTF-8'); + $twigVariables['toc'] = new Twig_Markup("

[toc]

", 'UTF-8'); } /* ********************************************************************************* */ From 4e2ad0635f7fed19d3fb0fc9a9cdf9e19c5e1e6c Mon Sep 17 00:00:00 2001 From: theWituch Date: Sat, 18 Dec 2021 22:34:42 +0100 Subject: [PATCH 3/9] Process TOC after final page were rendered instead content parsed step It allow to generate TOC of dynamic generated pages eg. when page template includes template --- TableOfContents.php | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/TableOfContents.php b/TableOfContents.php index fd388cb..5589a23 100644 --- a/TableOfContents.php +++ b/TableOfContents.php @@ -111,6 +111,31 @@ public function onMetaParsed(array &$meta) * @param string &$content parsed contents (HTML) of the requested page */ public function onContentParsed(&$content) + { + return; + } + + /** + * Triggered before Pico renders the page + * + * @see DummyPlugin::onPageRendered() + * + * @param string &$templateName file name of the template + * @param array &$twigVariables template variables + */ + public function onPageRendering(&$templateName, array &$twigVariables) + { + $twigVariables['toc'] = new Twig_Markup("

[toc]

", 'UTF-8'); + } + + /** + * Triggered after Pico has rendered the page + * + * @see DummyPlugin::onPageRendering() + * + * @param string &$content output contents (HTML) of the final page + */ + public function onPageRendered(&$content) { if (trim($content) === "") { return; @@ -169,19 +194,6 @@ public function onContentParsed(&$content) $content = preg_replace(array("/<(!DOCTYPE|\?xml).+?>/", "/<\/?(html|body)>/"), array("", ""), $document->saveHTML()); } - /** - * Triggered before Pico renders the page - * - * @see DummyPlugin::onPageRendered() - * - * @param string &$templateName file name of the template - * @param array &$twigVariables template variables - */ - public function onPageRendering(&$templateName, array &$twigVariables) - { - $twigVariables['toc'] = new Twig_Markup("

[toc]

", 'UTF-8'); - } - /* ********************************************************************************* */ /** From 093c8ac162b483b23f5b7ca70e795e8acedc4b87 Mon Sep 17 00:00:00 2001 From: theWituch Date: Sat, 18 Dec 2021 22:37:59 +0100 Subject: [PATCH 4/9] Add 'container' option to specify parent element as content source --- TableOfContents.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/TableOfContents.php b/TableOfContents.php index 5589a23..01e22d3 100644 --- a/TableOfContents.php +++ b/TableOfContents.php @@ -23,9 +23,11 @@ class TableOfContents extends AbstractPicoPlugin 'style' => 'none', // Heading text, if a heading for the table of contents is desired. 'heading' => null, + // ID of parent container which content will be scanned for TOC + 'container' => null, ); - protected $min_headers, $min_level, $max_level, $tag, $style, $heading; + protected $min_headers, $min_level, $max_level, $tag, $style, $heading, $container; protected $available_tags = ['ol', 'ul']; protected $available_styles = ['numbers', 'bullets', 'none', 'default']; @@ -90,6 +92,7 @@ public function onMetaParsed(array &$meta) $this->tag = $this->getVal('tag', $meta); $this->style = $this->getVal('style', $meta); $this->heading = $this->getVal('heading', $meta); + $this->container = $this->getVal('container', $meta); // Check if the tag is valid if (!in_array($this->tag, $this->available_tags)) { @@ -157,7 +160,10 @@ public function onPageRendered(&$content) // Get the list of headers $xPathExpression = []; for ($i = $this->min_level; $i <= $this->max_level; $i++) { - $xPathExpression[] = "//h$i"; + if (isset($this->container)) { + $xPathExpression[] = "//* [@id='$this->container']//h$i"; + } else + $xPathExpression[] = "//h$i"; } $xPathExpression = join("|", $xPathExpression); From cd40af0ec167028ac27fa902537b51a615fb32d4 Mon Sep 17 00:00:00 2001 From: theWituch Date: Sat, 18 Dec 2021 22:38:59 +0100 Subject: [PATCH 5/9] Add header filtering capability by marking with class 'not-in-toc' --- TableOfContents.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TableOfContents.php b/TableOfContents.php index 01e22d3..b7c6e61 100644 --- a/TableOfContents.php +++ b/TableOfContents.php @@ -161,9 +161,9 @@ public function onPageRendered(&$content) $xPathExpression = []; for ($i = $this->min_level; $i <= $this->max_level; $i++) { if (isset($this->container)) { - $xPathExpression[] = "//* [@id='$this->container']//h$i"; + $xPathExpression[] = "//* [@id='$this->container']//h$i [not(contains(@class,'not-in-toc'))]"; } else - $xPathExpression[] = "//h$i"; + $xPathExpression[] = "//h$i [not(contains(@class,'not-in-toc'))]"; } $xPathExpression = join("|", $xPathExpression); From 602deeb498fc07bb5784fda7fbb9acbe40993d98 Mon Sep 17 00:00:00 2001 From: theWituch Date: Sat, 18 Dec 2021 22:39:35 +0100 Subject: [PATCH 6/9] Allow to override {{ toc }} from template by [toc] in page .md file --- TableOfContents.php | 1 - 1 file changed, 1 deletion(-) diff --git a/TableOfContents.php b/TableOfContents.php index b7c6e61..47a8488 100644 --- a/TableOfContents.php +++ b/TableOfContents.php @@ -193,7 +193,6 @@ public function onPageRendered(&$content) foreach ($nodes as $node) { if (trim($node->nodeValue) === "[toc]") { $node->parentNode->replaceChild($div_element, $node); - break; } } From 7750ef3eeeb5b051c50f7778386e8402235ba95f Mon Sep 17 00:00:00 2001 From: theWituch Date: Sat, 18 Dec 2021 22:47:12 +0100 Subject: [PATCH 7/9] Update README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c45d1a1..27bc3ed 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ You can change the default configuration by adding values to your `config` file. * **none** (no item marker is shown) * **default** (the default css style applied to lists) * `heading` - Heading text, if a heading for the ToC is desired. - *Default value: (unset)* +* `container` - ID of parent DOM element which content will be scanned for headers. - *Default value: (unset)* For reference, these values are set in `config/config.yml` using the following format: @@ -102,6 +103,7 @@ TOC: tag: ol style: none heading: Contents + container: main ``` This configuration will be applied to the entire site, but it's also possible to override it for a specific page by adding the Meta headers with the same format (see the [example](#example)). From df92ffe98e4829f98fa2699f6ec93f09818ee0d5 Mon Sep 17 00:00:00 2001 From: theWituch Date: Sat, 18 Dec 2021 23:31:41 +0100 Subject: [PATCH 8/9] Remove [toc] placeholder from page content if not enough headers --- TableOfContents.php | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/TableOfContents.php b/TableOfContents.php index 47a8488..025fb8b 100644 --- a/TableOfContents.php +++ b/TableOfContents.php @@ -169,30 +169,32 @@ public function onPageRendered(&$content) $domXPath = new DOMXPath($document); $headers = $domXPath->query($xPathExpression); - if (!$headers || $headers->length < $this->min_headers) { - return; // Not enough header to display - } + if ($headers && $headers->length >= $this->min_headers) { // Enough header to display + // Initialize TOC element + $div_element = $document->createElement('div'); + $div_element->setAttribute('id', 'toc'); - // Initialize TOC element - $div_element = $document->createElement('div'); - $div_element->setAttribute('id', 'toc'); + // Add heading element, if enabled + if (isset($this->heading)) { + $heading_element = $document->createElement('div', $this->heading); + $heading_element->setAttribute('class', 'toc-heading'); + $div_element->appendChild($heading_element); + } - // Add heading element, if enabled - if (isset($this->heading)) { - $heading_element = $document->createElement('div', $this->heading); - $heading_element->setAttribute('class', 'toc-heading'); - $div_element->appendChild($heading_element); + // Add the list element + $list_element = $this->getList($document, $headers); + $div_element->appendChild($list_element); } - // Add the list element - $list_element = $this->getList($document, $headers); - $div_element->appendChild($list_element); - // Replace [toc] in document $nodes = $domXPath->query('//p'); foreach ($nodes as $node) { if (trim($node->nodeValue) === "[toc]") { - $node->parentNode->replaceChild($div_element, $node); + if (isset($div_element)) { + $node->parentNode->replaceChild($div_element, $node); + } else { + $node->parentNode->removeChild($node); + } } } From 77453eb0c008ef9a450d96213e56b01152487d95 Mon Sep 17 00:00:00 2001 From: theWituch Date: Mon, 20 Dec 2021 02:10:06 +0100 Subject: [PATCH 9/9] Improve [toc] placeholder query --- TableOfContents.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TableOfContents.php b/TableOfContents.php index 025fb8b..f56fd0e 100644 --- a/TableOfContents.php +++ b/TableOfContents.php @@ -187,7 +187,7 @@ public function onPageRendered(&$content) } // Replace [toc] in document - $nodes = $domXPath->query('//p'); + $nodes = $domXPath->query("//p[. = '[toc]']"); foreach ($nodes as $node) { if (trim($node->nodeValue) === "[toc]") { if (isset($div_element)) {