* * Licensed under MIT, see LICENSE. */ declare(strict_types=1); namespace Grav\Plugin\PageToc; use ArrayIterator; use DOMDocument; use DomElement; use DOMXPath; /** * Trait that helps with HTML-related operations * * @package TOC */ trait HtmlHelper { protected function getHTMLParser($markup) { libxml_use_internal_errors(true); $domDocument = new \DOMDocument(); $html = "$markup"; $domDocument->loadHTML(mb_encode_numericentity($html, [0x80, 0x10FFFF, 0, ~0], 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); $domDocument->preserveWhiteSpace = true; return $domDocument; } /** * Convert a topLevel and depth to H1..H6 tags array * * @param int $topLevel * @param int $depth * @return array|string[] Array of header tags; ex: ['h1', 'h2', 'h3'] */ protected function determineHeaderTags(int $topLevel, int $depth): array { $desired = range((int) $topLevel, (int) $topLevel + ((int) $depth - 1)); $allowed = [1, 2, 3, 4, 5, 6]; return array_map(function ($val) { return 'h' . $val; }, array_intersect($desired, $allowed)); } /** * Traverse Header Tags in DOM Document * * @param DOMDocument $domDocument * @param int $topLevel * @param int $depth * @return ArrayIterator */ protected function traverseHeaderTags(DOMDocument $domDocument, int $topLevel, int $depth): ArrayIterator { $xQueryResults = new DOMXPath($domDocument); $xpathQuery = sprintf( "//*[%s]", implode(' or ', array_map(function ($v) { return sprintf('local-name() = "%s"', $v); }, $this->determineHeaderTags($topLevel, $depth))) ); $nodes = []; $xQueryResults = $xQueryResults->query($xpathQuery); if ($xQueryResults) { foreach ($xQueryResults as $node) { $nodes[] = $node; } return new ArrayIterator($nodes); } else { return new ArrayIterator([]); } } }