customize sidebar and navbar via markdown file, #6 (#8)

* Refactor: use iife

* Feat: customize sidebar and navbar via markdown file, #6

* Add changelog
This commit is contained in:
cinwell.li
2016-11-29 01:07:47 +08:00
committed by GitHub
parent e09b6f218f
commit 35d3bd1647
16 changed files with 625 additions and 333 deletions

View File

@@ -1,28 +1,80 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.Docsify = factory());
}(this, (function () { 'use strict';
var Docsify = (function () {
'use strict';
var ajax = function (url, options) {
if ( options === void 0 ) options = {};
/**
* Simple ajax
* @param {String} url
* @param {String} [method=get]
* @return {Promise}
*/
function load (url, method) {
if ( method === void 0 ) method = 'get';
var xhr = new XMLHttpRequest();
xhr.open(options.method || 'get', url);
xhr.open(method, url);
xhr.send();
return {
then: function (cb) {
xhr.addEventListener('load', cb);
return this
},
catch: function (cb) {
xhr.addEventListener('error', cb);
return this
then: function (success, error) {
if ( error === void 0 ) error = function () {};
xhr.addEventListener('error', error);
xhr.addEventListener('load', function (ref) {
var target = ref.target;
target.status >= 400 ? error(target) : success(target.response);
});
}
}
};
}
/**
* gen toc tree
* @link https://github.com/killercup/grock/blob/5280ae63e16c5739e9233d9009bc235ed7d79a50/styles/solarized/assets/js/behavior.coffee#L54-L81
* @param {Array} toc
* @param {Number} maxLevel
* @return {Array}
*/
function genTree (toc, maxLevel) {
var headlines = [];
var last = {};
toc.forEach(function (headline) {
var level = headline.level || 1;
var len = level - 1;
if (level > maxLevel) { return }
if (last[len]) {
last[len].children = last[len].children || [];
last[len].children.push(headline);
} else {
headlines.push(headline);
}
last[level] = headline;
});
return headlines
}
/**
* camel to kebab
* @link https://github.com/bokuweb/kebab2camel/blob/master/index.js
* @param {String} str
* @return {String}
*/
function camel2kebab (str) {
return str.replace(/([A-Z])/g, function (m) { return '-' + m.toLowerCase(); })
}
/**
* is nil
* @param {Object} object
* @return {Boolean}
*/
function isNil (o) {
return o === null || o === undefined
}
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
@@ -2119,96 +2171,52 @@ Prism.languages.js = Prism.languages.javascript;
});
/**
* @link from https://github.com/killercup/grock/blob/5280ae63e16c5739e9233d9009bc235ed7d79a50/styles/solarized/assets/js/behavior.coffee#L54-L81
* Render github corner
* @param {Object} data
* @return {String}
*/
var tocToTree = function (toc, maxLevel) {
var headlines = [];
var last = {};
function corner (data) {
if (!data) { return '' }
if (!/\/\//.test(data)) { data = 'https://github.com/' + data; }
toc.forEach(function (headline) {
var level = headline.level || 1;
var len = level - 1;
return ("\n <a href=\"" + data + "\" class=\"github-corner\" aria-label=\"View source on Github\">\n <svg viewBox=\"0 0 250 250\" aria-hidden=\"true\">\n <path d=\"M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z\"></path>\n <path d=\"M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2\" fill=\"currentColor\" style=\"transform-origin: 130px 106px;\" class=\"octo-arm\"></path>\n <path d=\"M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z\" fill=\"currentColor\" class=\"octo-body\"></path>\n </svg>\n </a>")
}
if (level > maxLevel) { return }
if (last[len]) {
last[len].children = last[len].children || [];
last[len].children.push(headline);
} else {
headlines.push(headline);
}
last[level] = headline;
});
/**
* Render main content
* @return {[type]} [description]
*/
function main () {
return "<main>\n <aside class=\"sidebar\"></aside>\n <section class=\"content\">\n <article class=\"markdown-section\"></article>\n </section>\n </main>"
}
return headlines
};
var buildHeadlinesTree = function (tree, tpl) {
/**
* Render tree
* @param {Array} tree
* @param {String} tpl
* @return {String}
*/
function tree (toc, tpl) {
if ( tpl === void 0 ) tpl = '';
if (!tree || !tree.length) { return '' }
if (!toc || !toc.length) { return '' }
tree.forEach(function (node) {
toc.forEach(function (node) {
tpl += "<li><a class=\"section-link\" href=\"" + (node.slug) + "\">" + (node.title) + "</a></li>";
if (node.children) {
tpl += "<li><ul class=\"children\">" + (buildHeadlinesTree(node.children)) + "</li></ul>";
tpl += "<li><ul class=\"children\">" + (tree(node.children)) + "</li></ul>";
}
});
return tpl
};
var genToc = function (toc, opts) {
var tree = Array.isArray(opts.sidebar)
? opts.sidebar
: tocToTree(toc, opts['max-level']);
return buildHeadlinesTree(tree, '<ul>')
};
var cornerTpl = "\n <a href=\"{{repo}}\" class=\"github-corner\" aria-label=\"View source on Github\">\n <svg viewBox=\"0 0 250 250\" aria-hidden=\"true\">\n <path d=\"M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z\"></path>\n <path d=\"M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2\" fill=\"currentColor\" style=\"transform-origin: 130px 106px;\" class=\"octo-arm\"></path>\n <path d=\"M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z\" fill=\"currentColor\" class=\"octo-body\"></path>\n </svg>\n </a>\n";
var toc = [];
var renderer = new marked.Renderer();
}
/**
* render anchor tag
* @link https://github.com/chjj/marked#overriding-renderer-methods
* Active sidebar when scroll
* @link https://buble.surge.sh/
*/
renderer.heading = function (text, level) {
var slug = text.replace(/<(?:.|\n)*?>/gm, '').toLowerCase().replace(/[\s\n\t]+/g, '-');
toc.push({ level: level, slug: '#' + slug, title: text });
return ("<h" + level + " id=\"" + slug + "\"><a href=\"#" + slug + "\" class=\"anchor\"></a>" + text + "</h" + level + ">")
};
// highlight code
renderer.code = function (code, lang) {
if ( lang === void 0 ) lang = '';
var hl = prism.highlight(code, prism.languages[lang] || prism.languages.markup);
return ("<pre data-lang=\"" + lang + "\"><code class=\"lang-" + lang + "\">" + hl + "</code></pre>")
};
marked.setOptions({ renderer: renderer });
var render = function (content, opts) {
if ( opts === void 0 ) opts = {};
var corner = '';
if (opts.repo) {
var repo = /\/\//.test(opts.repo) ? opts.repo : ('https://github.com/' + opts.repo);
corner = cornerTpl.replace(/{{repo}}/g, repo);
}
var section = "<section class=\"content\">\n <article class=\"markdown-section\">" + (marked(content)) + "</article>\n </section>";
var sidebar = "<aside class=\"sidebar\">" + (genToc(toc, opts)) + "</aside>";
return (corner + "<main>" + sidebar + section + "</main>")
};
function scrollActiveSidebar (isCustom) {
if (/mobile/i.test(navigator.userAgent) || isCustom) { return }
function scrollActiveSidebar () {
if (/mobile/i.test(navigator.userAgent)) { return }
var anchors = document.querySelectorAll('.anchor');
var nav = {};
@@ -2257,84 +2265,160 @@ function scrollActiveSidebar (isCustom) {
scrollIntoView();
}
var bindEvent = function (isCustom) {
scrollActiveSidebar(isCustom);
};
/**
* Acitve link
*/
function activeLink (dom, activeParent) {
var host = document.location.origin + document.location.pathname;
var DEFAULT_OPTS = {
el: '#app',
repo: '',
'max-level': 6,
sidebar: ''
};
dom = typeof dom === 'object' ? dom : document.querySelector(dom);
if (!dom) { return
var script = document.currentScript || [].slice.call(document.getElementsByTagName('script')).pop();
if (script) {
for (var prop in DEFAULT_OPTS) {
DEFAULT_OPTS[prop] = script.getAttribute('data-' + prop) || DEFAULT_OPTS[prop];
}
}
var Docsify = function Docsify (opts) {
Docsify.installed = true;
this.opts = Object.assign({}, opts, DEFAULT_OPTS);
this.replace = true;
this.dom = document.querySelector(this.opts.el);
if (!this.dom) {
this.dom = document.body;
this.replace = false;
}
if (this.opts.sidebar) { this.opts.sidebar = window[this.opts.sidebar]; }
this.loc = document.location.pathname;
if (/\/$/.test(this.loc)) { this.loc += 'README'; }
this.load();
var nav = document.querySelector('nav');
if (nav) { this.activeNav(nav); }
};
Docsify.prototype.load = function load () {
var this$1 = this;
ajax(((this.loc) + ".md"))
.then(function (res) {
var target = res.target;
if (target.status >= 400) {
this$1.render('not found');
} else {
this$1.render(res.target.response);
bindEvent(!!this$1.opts.sidebar);
if (this$1.opts.sidebar) {
this$1.activeNav(document.querySelector('aside.sidebar'), true);
}
}
})
.catch(function (_) { return this$1.render('not found'); });
};
Docsify.prototype.render = function render$1 (content) {
this.dom[this.replace ? 'outerHTML' : 'innerHTML'] = render(content, this.opts);
};
Docsify.prototype.activeNav = function activeNav (elm, activeParentNode) {
var host = document.location.origin + document.location.pathname;[].slice.call(elm.querySelectorAll('a')).forEach(function (node) {
; }[].slice.call(dom.querySelectorAll('a')).forEach(function (node) {
if (node.href === host) {
activeParentNode
activeParent
? node.parentNode.setAttribute('class', 'active')
: node.setAttribute('class', 'active');
}
});
}
var renderTo = function (dom, content) {
dom = typeof dom === 'object' ? dom : document.querySelector(dom);
dom.innerHTML = content;
return dom
};
var toc = [];
var renderer = new marked.Renderer();
/**
* render anchor tag
* @link https://github.com/chjj/marked#overriding-renderer-methods
*/
renderer.heading = function (text, level) {
var slug = text.toLowerCase().replace(/<(?:.|\n)*?>/gm, '').replace(/[\s\n\t]+/g, '-');
toc.push({ level: level, slug: '#' + slug, title: text });
return ("<h" + level + " id=\"" + slug + "\"><a href=\"#" + slug + "\" class=\"anchor\"></a>" + text + "</h" + level + ">")
};
// highlight code
renderer.code = function (code, lang) {
if ( lang === void 0 ) lang = '';
var hl = prism.highlight(code, prism.languages[lang] || prism.languages.markup);
return ("<pre data-lang=\"" + lang + "\"><code class=\"lang-" + lang + "\">" + hl + "</code></pre>")
};
marked.setOptions({ renderer: renderer });
/**
* App
*/
function renderApp (dom, replace, opts) {
var nav = document.querySelector('nav') || document.createElement('nav');
dom[replace ? 'outerHTML' : 'innerHTML'] = corner(opts.repo) + main();
document.body.insertBefore(nav, document.body.children[0]);
}
/**
* article
*/
function renderArticle (content) {
if ( content === void 0 ) content = 'not found';
renderTo('article', marked(content));
if (!renderSidebar.rendered) { renderSidebar(null); }
if (!renderNavbar.rendered) { renderNavbar(null); }
}
/**
* navbar
*/
function renderNavbar (content, OPTIONS) {
if ( OPTIONS === void 0 ) OPTIONS = {};
renderNavbar.rendered = true;
if (content) { renderTo('nav', marked(content)); }
activeLink('nav');
}
/**
* sidebar
*/
function renderSidebar (content, OPTIONS) {
if ( OPTIONS === void 0 ) OPTIONS = {};
renderSidebar.rendered = true;
var isToc = false;
if (content) {
content = marked(content);
} else if (OPTIONS.sidebar) {
content = tree(OPTIONS.sidebar, '<ul>');
} else {
content = tree(genTree(toc, OPTIONS.maxLevel), '<ul>');
isToc = true;
}
renderTo('aside.sidebar', content);
isToc ? scrollActiveSidebar() : activeLink('aside.sidebar', true);
}
var OPTIONS = {
el: '#app',
repo: '',
maxLevel: 6,
sidebar: '',
loadSidebar: null,
loadNavbar: null
};
var script = document.currentScript || [].slice.call(document.getElementsByTagName('script')).pop();
// load configuration for script attribute
if (script) {
for (var prop in OPTIONS) {
var val = script.getAttribute('data-' + camel2kebab(prop));
OPTIONS[prop] = isNil(val) ? OPTIONS[prop] : true;
}
if (OPTIONS.loadSidebar === true) { OPTIONS.loadSidebar = '_sidebar.md'; }
if (OPTIONS.loadNavbar === true) { OPTIONS.loadNavbar = '_navbar.md'; }
if (OPTIONS.sidebar) { OPTIONS.sidebar = window[OPTIONS.sidebar]; }
}
var Docsify = function () {
var dom = document.querySelector(OPTIONS.el) || document.body;
var replace = dom !== document.body;
var loc = document.location.pathname;
if (/\/$/.test(loc)) { loc += 'README'; }
// Render app
renderApp(dom, replace, OPTIONS);
// Render markdown file
load((loc + ".md"))
.then(renderArticle, function (_) { return renderArticle(); });
// Render sidebar
if (OPTIONS.loadSidebar) {
load(OPTIONS.loadSidebar)
.then(function (content) { return renderSidebar(content, OPTIONS); });
}
// Render navbar
if (OPTIONS.loadNavbar) {
load(OPTIONS.loadNavbar)
.then(function (content) { return renderNavbar(content, OPTIONS); });
}
};
window.addEventListener('load', function () {
if (Docsify.installed) { return }
new Docsify();
});
var index = Docsify();
return Docsify;
return index;
})));
}());