protected function Toc::initialize in TOC API 8
Initializes the table of content index and ensure unique header ids.
1 call to Toc::initialize()
- Toc::__construct in src/
Toc.php - Constructs a new TOC object.
File
- src/
Toc.php, line 194
Class
- Toc
- Defines A class that parses the header tags from an HTML document.
Namespace
Drupal\toc_apiCode
protected function initialize() {
$this->index = [];
// Setup an empty array of keys to track the index's keys.
$default_keys = [];
foreach (array_keys($this->options['headers']) as $tag) {
$default_keys[$tag] = 0;
}
$index_keys = $default_keys;
$dom = Html::load($this->source);
// Loop through all the tags to ensure headers are found in the correct
// order.
$dom_nodes = $dom
->getElementsByTagName('*');
/** @var \DOMElement $dom_node */
foreach ($dom_nodes as $dom_node) {
if (empty($this->options['headers'][$dom_node->tagName])) {
continue;
}
// Set header tag and options.
$header_tag = $dom_node->tagName;
$header_options = $this->options['headers'][$header_tag];
// Set header html and title.
$header_html = '';
foreach ($dom_node->childNodes as $child_node) {
$header_html .= $dom_node->ownerDocument
->saveHTML($child_node);
}
$header_title = strip_tags($header_html);
// Set header key, number, and parent.
$header_number = NULL;
$header_key = NULL;
$header_path = NULL;
$parent_key = NULL;
$header_keys = $default_keys;
$header_level = (int) $dom_node->tagName[1];
for ($level = $this->options['header_min']; $level <= $this->options['header_max']; $level++) {
$tag = "h{$level}";
if ($level == $header_level) {
// When header level is matched, increment the index key and set the
// header number.
$header_number = ++$index_keys[$tag];
}
elseif ($level > $header_level) {
// Reset index keys once a header level is met.
$index_keys[$tag] = 0;
}
$header_keys[$tag] = $index_keys[$tag];
// Now set the parent key for every header level to ensure this header
// has a parent.
if ($level < $header_level) {
$parent_key = implode('.', $header_keys);
if (!isset($this->index[$parent_key])) {
$parent_key = NULL;
}
}
}
$header_key = implode('.', $header_keys);
// Set header parts and path from converted keys.
$header_path = implode($this->options['number_path_separator'], $this
->formatter()
->convertHeaderKeysToValues($header_keys, $this->options));
// Append to this header to it's parent.
if ($parent_key) {
$this->index[$parent_key]['children'][$header_key] = $header_key;
}
// Set header value based on (list) type.
$header_value = $this
->formatter()
->convertNumberToListTypeValue($header_number, $header_options['number_type']);
// Get and reset (unique) header id attribute.
if ($dom_node
->getAttribute('id')) {
$header_id = $dom_node
->getAttribute('id');
}
else {
$id_type = $this->options['header_id'];
$id_prefix = $this->options['header_id_prefix'] ?: 'section';
switch ($id_type) {
case 'title':
$header_id = $this
->formatter()
->convertStringToId($header_title);
break;
case 'number_path':
$header_id = $id_prefix . '-' . $header_path;
break;
case 'key':
default:
$header_id = $id_prefix . '-' . $header_key;
break;
}
}
$header_id = $this
->uniqueId($header_id);
$dom_node
->setAttribute('id', $header_id);
// Track the header's id and map it to the header's key.
// This is used to lookup the parent and children relationships.
$this->ids[$header_id] = $header_key;
// Set header in index.
$this->index[$header_key] = [
'type' => $header_options['number_type'],
'tag' => $header_tag,
'level' => $header_level,
'key' => $header_key,
'keys' => $header_keys,
'indent' => $header_level - $this->options['header_min'],
'path' => $header_path,
'number' => $header_number,
'value' => $header_value,
'parent' => $parent_key,
'children' => [],
'id' => $header_id,
'title' => $header_title,
'html' => [
'#markup' => $header_html,
'#allowed_tags' => $this
->getAllowedTags(),
],
'url' => Url::fromRoute('<none>', NULL, [
'fragment' => $header_id,
]),
];
}
$this->content = Html::serialize($dom);
}