83 lines
2.5 KiB
PHP
83 lines
2.5 KiB
PHP
<?php
|
|
|
|
/**
|
|
* PageTOC
|
|
*
|
|
* This plugin allows creation of Table of Contents + Link Anchors
|
|
*
|
|
* Based on the original version https://github.com/caseyamcl/toc
|
|
* by Casey McLaughlin <caseyamcl@gmail.com>
|
|
*
|
|
* Licensed under MIT, see LICENSE.
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Grav\Plugin\PageToc;
|
|
|
|
use DOMElement;
|
|
use RuntimeException;
|
|
use Cocur\Slugify\SlugifyInterface;
|
|
|
|
/**
|
|
* TOC Markup Fixer adds `id` attributes to all H1...H6 tags where they do not
|
|
* already exist
|
|
*
|
|
* @author Casey McLaughlin <caseyamcl@gmail.com>
|
|
*/
|
|
class MarkupFixer
|
|
{
|
|
use HtmlHelper;
|
|
|
|
/**
|
|
* Fix markup
|
|
*
|
|
* @param string $markup
|
|
* @param int $start
|
|
* @param int $depth
|
|
* @param array $options
|
|
* @return string Markup with added IDs
|
|
* @throws RuntimeException
|
|
*/
|
|
public function fix(string $markup, array $options = []): ?string
|
|
{
|
|
$start = (int) $options['start'] ?? 1;
|
|
$depth = (int) $options['depth'] ?? 6;
|
|
$domDocument = $this->getHTMLParser($markup);
|
|
$slugger = new UniqueSlugify();
|
|
|
|
/** @var DOMElement $node */
|
|
foreach ($this->traverseHeaderTags($domDocument, $start, $depth) as $node) {
|
|
if ($node->getAttribute('id')) {
|
|
$slug = $node->getAttribute('id');
|
|
} else {
|
|
$slug = $slugger->slugify($node->getAttribute('title') ?: $node->textContent, $options);
|
|
}
|
|
|
|
$node->setAttribute('id', $slug);
|
|
|
|
if ($options['hclass']) {
|
|
$class = $node->getAttribute('class');
|
|
$node->setAttribute('class', trim("$class {$options['hclass']}"));
|
|
}
|
|
|
|
if ($options['link']) {
|
|
$link = $domDocument->createElement("a");
|
|
$class = isset($options['class']) ? " {$options['class']}" : "";
|
|
$link->setAttribute('href', "#$slug");
|
|
$link->setAttribute('class', "toc-anchor {$options['position']}$class");
|
|
$link->setAttribute('data-anchor-icon', $options['icon']);
|
|
$link->setAttribute('aria-label', $options['aria']);
|
|
if ($options['position'] == 'after') {
|
|
$node->appendChild($link);
|
|
} else {
|
|
$node->insertBefore($link, $node->firstChild);
|
|
}
|
|
}
|
|
}
|
|
|
|
$markup = $domDocument->saveHTML($domDocument->getElementsByTagName('page-toc')->item(0));
|
|
return str_replace(['<page-toc>', '</page-toc>'], '', $markup);
|
|
}
|
|
}
|