Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 48 additions & 8 deletions TableOfContents.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,17 @@ class TableOfContents extends AbstractPicoPlugin
'style' => 'none',
// Heading text, if a heading for the table of contents is desired.
'heading' => null,
// Show/hide the table of contents by default.
'toggle' => true,
// Hide toc initially
'initially_hide' => true,
// Hide text
'hide_text' => '▲',
// Show text
'show_text' => '▼',
);

protected $min_headers, $min_level, $max_level, $tag, $style, $heading, $toc_element_xml;
protected $min_headers, $min_level, $max_level, $tag, $style, $toggle, $initially_hide, $hide_text, $show_text, $heading, $toc_element_xml;

protected $available_tags = ['ol', 'ul'];
protected $available_styles = ['numbers', 'bullets', 'none', 'default'];
Expand Down Expand Up @@ -90,6 +98,10 @@ public function onMetaParsed(array &$meta)
$this->tag = $this->getVal('tag', $meta);
$this->style = $this->getVal('style', $meta);
$this->heading = $this->getVal('heading', $meta);
$this->initially_hide = $this->getVal('initially_hide', $meta);
$this->toggle = $this->getVal('toggle', $meta);
$this->hide_text = $this->getVal('hide_text', $meta);
$this->show_text = $this->getVal('show_text', $meta);

// Check if the tag is valid
if (!in_array($this->tag, $this->available_tags)) {
Expand Down Expand Up @@ -147,9 +159,21 @@ public function onContentParsed(&$content)
$div_element->setAttribute('id', 'toc');

// Add heading element, if enabled
if (isset($this->heading)) {
$heading_element = $document->createElement('div', $this->heading);
if (isset($this->heading) || $this->toggle) {
$heading_element = $document->createElement('div', isset($this->heading) ? $this->heading : ' ');
$heading_element->setAttribute('class', 'toc-heading');

// Create the toogle button element if enabled
if($this->toggle)
{
$button_element = $document->createElement('button', $this->initially_hide ? $this->show_text : $this->hide_text);
$button_element->setAttribute('id', 'toc-toggle');
$button_element->setAttribute('data-show-text', $this->show_text);
$button_element->setAttribute('data-hide-text', $this->hide_text);

$heading_element->appendChild($button_element);
}

$div_element->appendChild($heading_element);
}

Expand Down Expand Up @@ -208,21 +232,33 @@ private function getVal($key, $meta)
* @param integer $index
* @return DOMElement
*/
private function getList($document, $headers, &$index = 0)
private function getList($document, $headers, &$index = 0, $isTopLevel = true)
{
// Initialize ordered list element
$list_element = $document->createElement($this->tag);
if ($this->style !== "default") {
$list_element->setAttribute('class', "toc-$this->style");
}

if ($this->toggle && $isTopLevel)
{
if ($this->initially_hide === true) {
$list_element->setAttribute('class', 'toc-hide');
} else {
$list_element->setAttribute('class', 'toc-show');
}
}

for ($index; $index < $headers->length; $index++) {
$curr_header = $headers[$index];
if (isset($curr_header->tagName) && $curr_header->tagName !== '') {
$header_classes = explode(' ', $curr_header->getAttribute('class'));
$is_unlisted = in_array('unlisted', $header_classes);

// Add missing id's to the h tags
$id = $curr_header->getAttribute('id');
if ($id === "") {
$id = $this->slugify($curr_header->nodeValue);
$id = $this->slugify($curr_header->nodeValue) . '-' . $index;
$curr_header->setAttribute('id', $id);
}

Expand All @@ -237,11 +273,15 @@ private function getList($document, $headers, &$index = 0)
if ($next_header && strtolower($curr_header->tagName) < strtolower($next_header->tagName)) {
// The next header is at a lower level -> add nested headers
$index++;
$nested_list_element = $this->getList($document, $headers, $index);
$li_element->appendChild($nested_list_element);
$nested_list_element = $this->getList($document, $headers, $index, false);
if ($nested_list_element->hasChildNodes()) {
$li_element->appendChild($nested_list_element);
};
}

$list_element->appendChild($li_element);
if (!$is_unlisted) {
$list_element->appendChild($li_element);
}

// Refresh next_header with the updated index
$next_header = ($index + 1 < $headers->length) ? $headers[$index + 1] : null;
Expand Down
21 changes: 21 additions & 0 deletions js/toc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
var toggleTocElement = document.getElementById("toc-toggle");

if (toggleTocElement) {
toggleTocElement.addEventListener("click", function() {
var tocElement = document.getElementById("toc");
if (tocElement) {
var xElement = tocElement.querySelector(".toc-hide, .toc-show");
if (xElement) {
if (xElement.classList.contains("toc-hide")) {
xElement.classList.remove("toc-hide");
xElement.classList.add("toc-show");
this.innerText = this.getAttribute('data-show-text');
} else if (xElement.classList.contains("toc-show")) {
xElement.classList.remove("toc-show");
xElement.classList.add("toc-hide");
this.innerText = this.getAttribute('data-hide-text');
}
}
}
});
}
21 changes: 19 additions & 2 deletions style.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#toc {
border : 1px solid #cdd;
background-color: #f5f5ff;
margin : 0;
margin : 20px 0 20px 0;
padding : 1em;
font-size : 80%;
}
Expand Down Expand Up @@ -29,7 +29,7 @@

.toc-numbers {
counter-reset : item;
list-style-type: none;
list-style-type: none;
}
.toc-numbers li:before {
content : counters(item, ". ") ". ";
Expand All @@ -39,4 +39,21 @@
.toc-heading {
font-size : larger;
font-weight: bold;
position: relative;
}

#toc-toggle {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
/* Weitere Stiloptionen nach Wunsch */
}

.toc-hide {
display: none;
}

.toc-show {
display: inherit;
}