GitHub: https://bitfragment.github.io/mindoc
Begin module.
var mindoc = (function() {
function capitalize(str) {
str = str.toLowerCase();
return str.charAt(0).toUpperCase() + str.substr(1);
}
Replace hyphens with spaces.
function deHyphenateWords(str) {
var re = new RegExp(/^\b[a-z]\S+\b-\b\S+\b/);
if (re.test(str)) str = str.replace(/-+/g, ' ');
return str;
}
Replace hyphens with spaces and capitalize the first (or only) word.
function resolvePandocId(id) {
id = deHyphenateWords(id);
return capitalize(id);
}
Adapted from http://jaketrent.com/post/addremove-classes-raw-javascript/
Pandoc interprets $
in a template as the start of a template
variable, so we have to avoid the regexp metacharacter $
here.
Instead, we match space or nothing: (\s|)
function hasClass(element, cls) {
return !!element.className.match(new RegExp('(\\s|^)' + cls + '(\\s|)'));
}
function addClass(element, cls) {
if (!hasClass(element, cls)) element.className += ' ' + cls;
}
function removeClass(element, cls) {
if (hasClass(element, cls)) {
var re = new RegExp('(\\s|^)' + cls + '(\\s|)');
element.className = element.className.replace(re, ' ');
}
}
function addPureClasses() {
var elts, eltslen,
pureClasses = {
'table': 'pure-table pure-table-bordered'
};
Object.keys(pureClasses).forEach(function(key) {
elts = document.getElementsByTagName(key);
eltslen = elts.length;
if (eltslen > 1) {
for (var i = 0; i < eltslen; i++) {
addClass(elts[i], pureClasses[key]);
}
}
});
}
function addRefLinkEventListeners(citeElts, refsElt) {
for (var i = 0, l = citeElts.length; i < l; i++) {
var citeLinks = citeElts[i].getElementsByTagName('a');
for (var j = 0, ll = citeLinks.length; j < ll; j++) {
citeLinks[j].addEventListener('click', function() {
removeClass(refsElt, 'hidden');
});
}
}
}
function addFnLinkEventListeners(fnElts, notesElt) {
for (var i = 0, l = fnElts.length; i < l; i++) {
fnElts[i].addEventListener('click', function() {
removeClass(notesElt, 'hidden');
});
}
}
When Pandoc is invoked with its --section-divs
option, HTML
output includes the class ‘level’ + n (where n is an integer) added
to <div>
elements enclosing document sections, plus ‘id’
attributes generated from header text:
<div id="foo" class="section level2">
<h2>Foo</h2>
...
</div>
If html5
is specified as Pandoc’s output format, Pandoc creates
<section>
elements instead:
<section id="foo" class="level2">
<h2>Foo</h2>
...
</div>
function createMenuListItemElt() {
var elt = document.createElement('li');
addClass(elt, 'pure-menu-item');
return elt;
}
function createMenuAElt(sectionId) {
var elt = document.createElement('a');
elt.id = 'menu-' + sectionId;
elt.href = '#';
elt.innerHTML = resolvePandocId(sectionId);
addClass(elt, 'pure-menu-link');
return elt;
}
function createNavigation(sectionElts) {
var docFrag = document.createDocumentFragment(),
navNav = document.createElement('nav'),
navDiv = document.createElement('div'),
navList = document.createElement('ul');
docFrag.appendChild(navNav);
navNav.appendChild(navDiv);
navDiv.appendChild(navList);
addClass(navDiv, 'pure-menu');
addClass(navList, 'pure-menu-list');
Add ‘All sections’ as first menu item.
var allSectionsId = 'All sections',
allSections = createMenuListItemElt();
addClass(allSections, 'pure-menu-selected')
navList.appendChild(allSections);
allSections.appendChild(createMenuAElt(allSectionsId));
Add menu list items and links, using ‘id’ attributes of section elements.
var sectionId, menuListElement;
for (var i = 0, l = sectionElts.length; i < l; i++) {
sectionId = sectionElts[i].getAttribute('id');
menuListElement = createMenuListItemElt();
navList.appendChild(menuListElement);
menuListElement.appendChild(createMenuAElt(sectionId));
}
var pageContent = document.getElementById('page-content');
document.querySelector('body').insertBefore(docFrag, pageContent);
}
Toggle by removing a class from the currently selected element and adding it to the element passed to this function.
function toggleSelectedMenuElt(elt) {
var selectedElement;
if (!elt.hasAttribute('pure-menu-selected')) {
selectedElement = document.querySelector('.pure-menu-selected');
removeClass(selectedElement, 'pure-menu-selected');
addClass(elt, 'pure-menu-selected');
}
}
Toggle the selected menu item, then hide the document section currently shown and show the section with the relevant id attribute.
function showHideSectionElts(sectionElts, link) {
var elt,
clickedId = link.getAttribute('id'),
resolvedClickedId = clickedId.replace(/menu-/, ''),
clickedParent = document.getElementById(clickedId).parentNode;
toggleSelectedMenuElt(clickedParent);
for (var section in sectionElts) {
elt = sectionElts[section];
if (!hasClass(elt, 'hidden')) addClass(elt, 'hidden');
if (elt.getAttribute('id') === resolvedClickedId &&
hasClass(elt, 'hidden')) removeClass(elt, 'hidden');
}
}
function showAllSectionElts(sectionElts) {
var elt;
for (var section in sectionElts) {
elt = sectionElts[section];
if (hasClass(elt, 'hidden')) removeClass(elt, 'hidden');
}
}
function addMenuEventListeners(sectionElts) {
var menuLinks = document.querySelectorAll('.pure-menu-link');
for (var i = 0, l = menuLinks.length; i < l; i++) {
if (i === 0) { // 'All sections' link
menuLinks[i].addEventListener('click', function() {
showAllSectionElts(sectionElts);
});
} else { // Other section links
menuLinks[i].addEventListener('click', function() {
showHideSectionElts(sectionElts, this);
});
}
}
}
return {
main: function() {
addPureClasses();
Test to see if Pandoc was invoked with --section-divs
.
if (document.getElementsByClassName('level2').length > 0) {
var elts, sectionElts = [];
['abstract', 'level2', 'footnotes'].forEach(function(cls) {
elts = document.getElementsByClassName(cls);
for (var i = 0, l = elts.length; i < l; i++) {
sectionElts.push(elts[i]);
}
});
} else {
If Pandoc wasn’t invoked with --section-divs
, we’re done here.
return;
}
var elt;
Pandoc 1.17.1 gives all sections the class ‘level2’ except for the footnotes section. We want the footnotes section to appear in the navigation menu, so we add it here. Pandoc 1.17.1 does not give the footnotes section an ‘id’ attribute, so we add that here too.
for (var section in sectionElts) {
elt = sectionElts[section];
Add class ‘level2’ to any element that does not have it, so that it appears in the navigation menu.
if (!hasClass(elt, 'level2')) addClass(elt, 'level2');
Add an ‘id’ attribute to the footnotes section.
if (hasClass(elt, 'footnotes')) elt.setAttribute('id', 'footnotes');
}
Now create the navigation menu.
createNavigation(sectionElts);
Add click handlers to menu items.
addMenuEventListeners(sectionElts);
Add click handlers to reference links.
var citeElts = document.getElementsByClassName('citation'),
refsElt = document.getElementById('references');
addRefLinkEventListeners(citeElts, refsElt);
Add click handlers to footnote links.
var fnElts = document.getElementsByClassName('footnoteRef'),
notesElt = document.getElementById('footnotes');
addFnLinkEventListeners(fnElts, notesElt);
}
}
End module.
}());
window.addEventListener('load', function() {
mindoc.main();
});