static/js/com/toc.js (139 lines of code) (raw):
import $ from 'jquery';
function Toc(options) {
var that = this,
option;
if (typeof options == 'object') {
for (option in options) {
if (option in that) {
that[option] = options[option];
}
}
}
that.scope = document.body;
that.init(options);
}
Toc.prototype = {
selector: 'h1,h2,h3,h4,h5,h6',
scope: null,
from: 1,
to: 6,
map: null,
createLinks: true,
cssClasses: {
tocList: 'toc',
tocListItem: 'toc-item_level_#'
},
init: function (options) {
var that = this;
that.map = that.get();
},
__getMap: function (selector, scope) {
var that = this;
var sections = [], sectionNode, section;
var i, len;
var selector = (typeof selector != 'undefined') ? selector : that.selector;
var scope = (typeof scope != 'undefined') ? scope : that.scope;
var sectionsNodes = ('querySelectorAll' in scope)
? scope.querySelectorAll(selector)
: $(selector, scope);
for (i = 0, len = sectionsNodes.length; i < len; i++) {
sectionNode = sectionsNodes[i];
section = {
id: sectionNode.id,
level: parseInt(sectionNode.tagName.substr(1, 1)),
title: $(sectionNode).text(),
node: sectionNode,
content: []
};
sections.push(section);
}
return sections;
},
get: function (options) {
var that = this;
var selector = (options && typeof options.selector != 'undefined') ? options.selector : that.selector;
var scope = (options && typeof options.scope != 'undefined') ? options.scope : that.scope;
var sectMap, tocList;
sectMap = that.__getMap(selector, scope);
if (sectMap.length == 0) {
return [];
}
tocList = that.__getBranch(sectMap, sectMap[0].level, 0);
return tocList;
},
render: function (opts) {
var that = this;
var from = (opts && typeof opts.from != 'undefined') ? opts.from : that.from;
var to = (opts && typeof opts.to != 'undefined') ? opts.to : that.to;
var target = (opts && typeof opts.target != 'undefined') ? opts.target : null;
var toc;
toc = that.__create(that.map, from, to);
if (target != null) {
target.appendChild(toc);
}
return toc;
},
__create: function (list, from, to) {
var that = this;
var createLinks = that.createLinks;
var ul, li, a, title;
var section, sectionContent;
var css = that.cssClasses;
var i, len;
if (list.length == 0) {
return null;
}
ul = document.createElement('ul');
ul.className = css.tocList;
for (i = 0, len = list.length; i < len; i++) {
section = list[i];
li = document.createElement('li');
li.className = css.tocListItem.replace('#', section.level);
if (createLinks) {
title = document.createElement('a');
title.href = "#" + section.id;
title.appendChild(document.createTextNode(section.title));
}
else {
title = document.createTextNode(section.title);
}
li.appendChild(title);
if (section.content.length > 0 &&
section.content[0].level >= from &&
section.content[0].level <= to) {
sectionContent = that.__create(section.content, from, to);
li.appendChild(sectionContent);
}
ul.appendChild(li);
}
return ul;
},
__getBranch: function (sections, level, start, firstRun) {
var that = this;
var firstRun = (typeof firstRun !== 'undefined') ? firstRun : true;
var end = sections.length;
var tree = [];
var section, prevSect;
for (var i = start; i < end; i++) {
section = sections[i];
prevSect = (typeof sections[i - 1] !== 'undefined')
? sections[i - 1]
: null;
if (section.level == level) {
// siblings
tree.push(section);
}
else if (section.level > level) {
// inner branch
if (prevSect && prevSect.level < section.level) {
prevSect.content = this.__getBranch(sections, section.level, i, false);
}
}
else if (section.level < level) {
// out of branch
if (!firstRun) {
break;
}
}
}
return tree;
}
};
export default Toc;