Refactor generation of ToC

This replaces the existing iterative implementation of the ToC
generation with an recursive one.

This also solves the problem of skipped headers which causes wrong
leveling of them.

Signed-off-by: Sheogorath <sheogorath@shivering-isles.com>
This commit is contained in:
Sheogorath 2018-07-04 02:22:48 +02:00
parent 4e38d1836e
commit 4fe0620853
No known key found for this signature in database
GPG key ID: 1F05CC3635CDDFFD

View file

@ -44,59 +44,69 @@
} }
} }
Toc.prototype._createTocContent = function () { Toc.prototype._createTocContent = function recursiveToc(level = 0, titleElements = [], titleNames = [], ulClass = undefined) {
this._elTitleElementsLen = this.elTitleElements.length // Inititalize our elements from the toc object
if (!this._elTitleElementsLen) return // which is only available on level 0
if (level === 0) {
titleElements = this.elTitleElements
titleNames = this._elTitlesNames
ulClass = this.ulClass
}
var titleElementsLen = titleElements.length
// No need to do anything for an empty ToC
if (!titleElementsLen) return
this.tocContent = '' this.tocContent = ''
this._tempLists = [] var content = '<ul'
if (ulClass) {
content += ' class="' + ulClass + '"'
}
content += '>'
var iterTag = titleNames[level]
var recurse = false
for (var i = 0; i < this._elTitleElementsLen; i++) { for (var element; element = titleElements.shift();) {
var j = i + 1 var elementTag = element.tagName.toLowerCase()
this._elTitleElement = this.elTitleElements[i]
this._elTitleElementName = this._elTitleElement.tagName
this._elTitleElementTitle = this._elTitleElement.textContent.replace(/"/g, '&quot;')
this._elTitleElementText = (typeof this.process === 'function' ? this.process(this._elTitleElement) : this._elTitleElement.innerHTML).replace(/<(?:.|\n)*?>/gm, '')
var id = this._elTitleElement.getAttribute('id')
if (!id) {
this._elTitleElement.setAttribute('id', 'tip' + i)
id = '#tip' + i
} else {
id = '#' + id
}
this.tocContent += '<li><a href="' + id + '" title="'+ this._elTitleElementTitle +'">' + this._elTitleElementText + '</a>' // We only care about tags on our level to add them as list item
if (elementTag == iterTag) {
if (j !== this._elTitleElementsLen) { // Let's do some cleaning
this._elNextTitleElementName = this.elTitleElements[j].tagName var elementTitle = element.textContent.replace(/"/g, '&quot;')
if (this._elTitleElementName !== this._elNextTitleElementName) { var elementText = (typeof this.process === 'function' ? this.process(element) : element.innerHTML).replace(/<(?:.|\n)*?>/gm, '')
var checkColse = false var id = element.getAttribute('id')
var y = 1 if (!id) {
for (var t = this._tempLists.length - 1; t >= 0; t--) { element.setAttribute('id', 'tip' + i)
if (this._tempLists[t].tagName === this._elNextTitleElementName) { id = '#tip' + i
checkColse = true
break
}
y++
}
if (checkColse) {
this.tocContent += new Array(y + 1).join('</li></ul>')
this._tempLists.length = this._tempLists.length - y
} else {
this._tempLists.push(this._elTitleElement)
if (this.ulClass) { this.tocContent += '<ul class="' + this.ulClass + '">' } else { this.tocContent += '<ul>' }
}
} else { } else {
this.tocContent += '</li>' id = '#' + id
} }
content += '<li><a href="' + id + '" title="'+ elementTitle +'">' + elementText + '</a>'
// Reset recursion. We need it for the next subsections
recurse = false
// Check if the current element has a lower level than ours, if so, we have to go down the rabbithole!
} else if (!recurse && titleNames.indexOf(elementTag.toLowerCase()) > level) {
recurse = true
// This element is for the lower lever, we have to re-add it before we send the list down there.
titleElements.unshift(element)
// Let's call ourself and get to the next level
content += recursiveToc(level + 1, titleElements, titleNames, ulClass)
} else { } else {
if (this._tempLists.length) { // When we end up here, met a higher level element
this.tocContent += new Array(this._tempLists.length + 1).join('</li></ul>') // This is not our business so back into the list with the element and let's end this loop
} else { titleElements.unshift(element)
this.tocContent += '</li>' break
}
} }
} }
if (this.ulClass) { this.tocContent = '<ul class="' + this.ulClass + '">' + this.tocContent + '</ul>' } else { this.tocContent = '<ul>' + this.tocContent + '</ul>' }
content += '</ul>'
// Set ToC content of the level 0 everything else pass things to the upper level!
if (level === 0) {
this.tocContent = content
} else {
return content
}
} }
Toc.prototype._showToc = function () { Toc.prototype._showToc = function () {