diff --git a/build/release.sh b/build/release.sh index aa33a751..c388bc36 100644 --- a/build/release.sh +++ b/build/release.sh @@ -12,7 +12,7 @@ echo if [[ $REPLY =~ ^[Yy]$ ]]; then echo "Releasing $VERSION ..." - npm run lint + npm run test # build VERSION=$VERSION npm run build @@ -29,8 +29,8 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then # commit git add -A - git commit -m "[build] $VERSION" - npm version $VERSION --message "[release] $VERSION" + git commit -m "[build] $VERSION $RELEASE_TAG" + npm version $VERSION --message "[release] $VERSION $RELEASE_TAG" # publish git push origin refs/tags/v$VERSION diff --git a/lib/docsify.js b/lib/docsify.js index 7cf70183..7a0444d2 100644 --- a/lib/docsify.js +++ b/lib/docsify.js @@ -253,323 +253,108 @@ var dom = Object.freeze({ toggleClass: toggleClass }); -var UA = window.navigator.userAgent.toLowerCase(); +var inBrowser = typeof window !== 'undefined'; -var isIE = UA && /msie|trident/.test(UA); +var isMobile = inBrowser && document.body.clientWidth <= 600; -var isMobile = document.body.clientWidth <= 600; - -var decode = decodeURIComponent; -var encode = encodeURIComponent; - -function parseQuery (query) { - var res = {}; - - query = query.trim().replace(/^(\?|#|&)/, ''); - - if (!query) { - return res - } - - // Simple parse - query.split('&').forEach(function (param) { - var parts = param.replace(/\+/g, ' ').split('='); - - res[parts[0]] = decode(parts[1]); - }); - return res -} - -function stringifyQuery (obj) { - var qs = []; - - for (var key in obj) { - qs.push(((encode(key)) + "=" + (encode(obj[key]))).toLowerCase()); - } - - return qs.length ? ("?" + (qs.join('&'))) : '' -} - -var getBasePath = cached(function (base) { - return /^(\/|https?:)/g.test(base) - ? base - : cleanPath(window.location.pathname + '/' + base) -}); - -function getPath () { - var args = [], len = arguments.length; - while ( len-- ) args[ len ] = arguments[ len ]; - - return cleanPath(args.join('/')) -} - -var isAbsolutePath = cached(function (path) { - return /(:|(\/{2}))/.test(path) -}); - -var getParentPath = cached(function (path) { - return /\/$/g.test(path) - ? path - : (path = path.match(/(\S*\/)[^\/]+$/)) - ? path[1] - : '' -}); - -var cleanPath = cached(function (path) { - return path - .replace(/^\/+/, '/') - .replace(/([^:])\/{2,}/g, '$1/') -}); - -function replaceHash (path) { - var i = window.location.href.indexOf('#'); - window.location.replace( - window.location.href.slice(0, i >= 0 ? i : 0) + '#' + path - ); -} - -var replaceSlug = cached(function (path) { - return path - .replace('#', '?id=') - // .replace(/\?(\w+)=/g, (_, slug) => slug === 'id' ? '?id=' : `&${slug}=`) -}); /** - * Normalize the current url - * - * @example - * domain.com/docs/ => domain.com/docs/#/ - * domain.com/docs/#/#slug => domain.com/docs/#/?id=slug + * @see https://github.com/MoOx/pjax/blob/master/lib/is-supported.js */ -function normalize () { - var path = getHash(); +var supportsPushState = inBrowser && (function () { + // Borrowed wholesale from https://github.com/defunkt/jquery-pjax + return window.history && + window.history.pushState && + window.history.replaceState && + // pushState isn’t reliable on iOS until 5. + !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/) +})(); - path = replaceSlug(path); +/** + * Render github corner + * @param {Object} data + * @return {String} + */ +function corner (data) { + if (!data) { return '' } + if (!/\/\//.test(data)) { data = 'https://github.com/' + data; } + data = data.replace(/^git\+/, ''); - if (path.charAt(0) === '/') { return replaceHash(path) } - replaceHash('/' + path); -} - -function getHash () { - // We can't use window.location.hash here because it's not - // consistent across browsers - Firefox will pre-decode it! - var href = window.location.href; - var index = href.indexOf('#'); - return index === -1 ? '' : href.slice(index + 1) + return ( + "" + + '' + + '') } /** - * Parse the url - * @param {string} [path=window.location.herf] - * @return {object} { path, query } + * Render main content */ -function parse (path) { - if ( path === void 0 ) path = window.location.href; +function main (config) { + var aside = ( + '' + + ''); - var query = ''; - - var queryIndex = path.indexOf('?'); - if (queryIndex >= 0) { - query = path.slice(queryIndex + 1); - path = path.slice(0, queryIndex); - } - - var hashIndex = path.indexOf('#'); - if (hashIndex) { - path = path.slice(hashIndex + 1); - } - - return { path: path, query: parseQuery(query) } + return (isMobile ? (aside + "
") : ("
" + aside)) + + '
' + + '
' + + '
' + + '
' } /** - * to URL - * @param {string} path - * @param {object} qs query params - * @param {string} currentRoute optional current route + * Cover Page */ -function toURL (path, params, currentRoute) { - var local = currentRoute && path[0] === '#'; - var route = parse(replaceSlug(path)); +function cover () { + var SL = ', 100%, 85%'; + var bgc = 'linear-gradient(to left bottom, ' + + "hsl(" + (Math.floor(Math.random() * 255) + SL) + ") 0%," + + "hsl(" + (Math.floor(Math.random() * 255) + SL) + ") 100%)"; - route.query = merge({}, route.query, params); - path = route.path + stringifyQuery(route.query); - path = path.replace(/\.md(\?)|\.md$/, '$1'); - - if (local) { path = currentRoute + path; } - - return cleanPath('#/' + path) + return "
" + + '
' + + '
' + + '
' } - -var route = Object.freeze({ - normalize: normalize, - getHash: getHash, - parse: parse, - toURL: toURL, - parseQuery: parseQuery, - stringifyQuery: stringifyQuery, - getBasePath: getBasePath, - getPath: getPath, - isAbsolutePath: isAbsolutePath, - getParentPath: getParentPath, - cleanPath: cleanPath -}); - -var title = $.title; /** - * Toggle button + * Render tree + * @param {Array} tree + * @param {String} tpl + * @return {String} */ -function btn (el) { - var toggle = function (_) { return body.classList.toggle('close'); }; +function tree (toc, tpl) { + if ( tpl === void 0 ) tpl = ''; - el = getNode(el); - on(el, 'click', function (e) { - e.stopPropagation(); - toggle(); + if (!toc || !toc.length) { return '' } + + toc.forEach(function (node) { + tpl += "
  • " + (node.title) + "
  • "; + if (node.children) { + tpl += "
  • "; + } }); - var sidebar = getNode('.sidebar'); - - isMobile && on(body, 'click', function (_) { return body.classList.contains('close') && toggle(); } - ); - on(sidebar, 'click', function (_) { return setTimeout((function (_) { return getAndActive(sidebar, true, true); }, 0)); } - ); + return tpl } -function sticky () { - var cover = getNode('section.cover'); - if (!cover) { return } - var coverHeight = cover.getBoundingClientRect().height; - - if (window.pageYOffset >= coverHeight || cover.classList.contains('hidden')) { - toggleClass(body, 'add', 'sticky'); - } else { - toggleClass(body, 'remove', 'sticky'); - } +function helper (className, content) { + return ("

    " + (content.slice(5).trim()) + "

    ") } -/** - * Get and active link - * @param {string|element} el - * @param {Boolean} isParent acitve parent - * @param {Boolean} autoTitle auto set title - * @return {element} - */ -function getAndActive (el, isParent, autoTitle) { - el = getNode(el); - - var links = findAll(el, 'a'); - var hash = '#' + getHash(); - var target; - - links - .sort(function (a, b) { return b.href.length - a.href.length; }) - .forEach(function (a) { - var href = a.getAttribute('href'); - var node = isParent ? a.parentNode : a; - - if (hash.indexOf(href) === 0 && !target) { - target = a; - toggleClass(node, 'add', 'active'); - } else { - toggleClass(node, 'remove', 'active'); - } - }); - - if (autoTitle) { - $.title = target ? ((target.innerText) + " - " + title) : title; - } - - return target -} - -var nav = {}; -var hoverOver = false; - -function highlight () { - var sidebar = getNode('.sidebar'); - var anchors = findAll('.anchor'); - var wrap = find(sidebar, '.sidebar-nav'); - var active = find(sidebar, 'li.active'); - var top = body.scrollTop; - var last; - - for (var i = 0, len = anchors.length; i < len; i += 1) { - var node = anchors[i]; - - if (node.offsetTop > top) { - if (!last) { last = node; } - break - } else { - last = node; - } - } - if (!last) { return } - var li = nav[last.getAttribute('data-id')]; - - if (!li || li === active) { return } - - active && active.classList.remove('active'); - li.classList.add('active'); - active = li; - - // scroll into view - // https://github.com/vuejs/vuejs.org/blob/master/themes/vue/source/js/common.js#L282-L297 - if (!hoverOver && body.classList.contains('sticky')) { - var height = sidebar.clientHeight; - var curOffset = 0; - var cur = active.offsetTop + active.clientHeight + 40; - var isInView = ( - active.offsetTop >= wrap.scrollTop && - cur <= wrap.scrollTop + height - ); - var notThan = cur - curOffset < height; - var top$1 = isInView - ? wrap.scrollTop - : notThan - ? curOffset - : cur - height; - - sidebar.scrollTop = top$1; - } -} - -function scrollActiveSidebar () { - if (isMobile) { return } - - var sidebar = getNode('.sidebar'); - var lis = findAll(sidebar, 'li'); - - for (var i = 0, len = lis.length; i < len; i += 1) { - var li = lis[i]; - var a = li.querySelector('a'); - if (!a) { continue } - var href = a.getAttribute('href'); - - if (href !== '/') { - href = parse(href).query.id; - } - - nav[decodeURIComponent(href)] = li; - } - - off('scroll', highlight); - on('scroll', highlight); - on(sidebar, 'mouseover', function () { hoverOver = true; }); - on(sidebar, 'mouseleave', function () { hoverOver = false; }); -} - -function scrollIntoView (id) { - var section = find('#' + id); - section && section.scrollIntoView(); -} - -var scrollEl = $.scrollingElement || $.documentElement; - -function scroll2Top (offset) { - if ( offset === void 0 ) offset = 0; - - scrollEl.scrollTop = offset === true ? 0 : Number(offset); +function theme (color) { + return ("") } var barEl; @@ -707,93 +492,44 @@ var cssVars = function (color) { }); }; -/** - * Render github corner - * @param {Object} data - * @return {String} - */ -function corner (data) { - if (!data) { return '' } - if (!/\/\//.test(data)) { data = 'https://github.com/' + data; } - data = data.replace(/^git\+/, ''); +var RGX = /([^{]*?)\w(?=\})/g; - return ( - "" + - '' + - '') -} +var dict = { + YYYY: 'getFullYear', + YY: 'getYear', + MM: function (d) { + return d.getMonth() + 1; + }, + DD: 'getDate', + HH: 'getHours', + mm: 'getMinutes', + ss: 'getSeconds' +}; -/** - * Render main content - */ -function main (config) { - var aside = ( - '' + - ''); +var tinydate = function (str) { + var parts=[], offset=0; + str.replace(RGX, function (key, _, idx) { + // save preceding string + parts.push(str.substring(offset, idx - 1)); + offset = idx += key.length + 1; + // save function + parts.push(function(d){ + return ('00' + (typeof dict[key]==='string' ? d[dict[key]]() : dict[key](d))).slice(-key.length); + }); + }); - return (isMobile ? (aside + "
    ") : ("
    " + aside)) + - '
    ' + - '
    ' + - '
    ' + - '
    ' -} + if (offset !== str.length) { + parts.push(str.substring(offset)); + } -/** - * Cover Page - */ -function cover () { - var SL = ', 100%, 85%'; - var bgc = 'linear-gradient(to left bottom, ' + - "hsl(" + (Math.floor(Math.random() * 255) + SL) + ") 0%," + - "hsl(" + (Math.floor(Math.random() * 255) + SL) + ") 100%)"; - - return "
    " + - '
    ' + - '
    ' + - '
    ' -} - -/** - * Render tree - * @param {Array} tree - * @param {String} tpl - * @return {String} - */ -function tree (toc, tpl) { - if ( tpl === void 0 ) tpl = ''; - - if (!toc || !toc.length) { return '' } - - toc.forEach(function (node) { - tpl += "
  • " + (node.title) + "
  • "; - if (node.children) { - tpl += "
    • " + (tree(node.children)) + "
    "; - } - }); - - return tpl -} - -function helper (className, content) { - return ("

    " + (content.slice(5).trim()) + "

    ") -} - -function theme (color) { - return ("") -} + return function (arg) { + var out='', i=0, d=arg||new Date(); + for (; i]*?>[\s\S]+?<\/(pre|template|code)>/g, function (m) { return m.replace(/:/g, '__colon__'); }) - .replace(/:(\w+?):/ig, window.emojify || replace) + .replace(/:(\w+?):/ig, (inBrowser && window.emojify) || replace) .replace(/__colon__/g, ':') } -var markdownCompiler = marked; -var contentBase = ''; -var currentPath = ''; -var linkTarget = '_blank'; -var renderer = new marked.Renderer(); -var cacheTree = {}; -var toc = []; +var decode = decodeURIComponent; +var encode = encodeURIComponent; -/** - * Compile markdown content - */ -var markdown = cached(function (text) { - var html = ''; +function parseQuery (query) { + var res = {}; - if (!text) { return text } + query = query.trim().replace(/^(\?|#|&)/, ''); - html = markdownCompiler(text); - html = emojify(html); - slugify.clear(); + if (!query) { + return res + } - return html + // Simple parse + query.split('&').forEach(function (param) { + var parts = param.replace(/\+/g, ' ').split('='); + + res[parts[0]] = decode(parts[1]); + }); + return res +} + +function stringifyQuery (obj) { + var qs = []; + + for (var key in obj) { + qs.push(((encode(key)) + "=" + (encode(obj[key]))).toLowerCase()); + } + + return qs.length ? ("?" + (qs.join('&'))) : '' +} + +var getBasePath = cached(function (base) { + if ( base === void 0 ) base = ''; + + // TODO + var path = inBrowser ? window.location.pathname : ''; + + return /^(\/|https?:)/g.test(base) + ? base + : cleanPath(path + '/' + base) }); -markdown.renderer = renderer; +function getPath () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; -markdown.init = function (config, ref) { - if ( config === void 0 ) config = {}; - var base = ref.base; if ( base === void 0 ) base = window.location.pathname; - var externalLinkTarget = ref.externalLinkTarget; + return cleanPath(args.join('/')) +} - contentBase = getBasePath(base); - linkTarget = externalLinkTarget || linkTarget; +var isAbsolutePath = cached(function (path) { + return /(:|(\/{2}))/.test(path) +}); - if (isFn(config)) { - markdownCompiler = config(marked, renderer); +var getParentPath = cached(function (path) { + return /\/$/g.test(path) + ? path + : (path = path.match(/(\S*\/)[^\/]+$/)) + ? path[1] + : '' +}); + +var cleanPath = cached(function (path) { + return path + .replace(/^\/+/, '/') + .replace(/([^:])\/{2,}/g, '$1/') +}); + +var Compiler = function Compiler (config, router) { + this.config = config; + this.router = router; + this.cacheTree = {}; + this.toc = []; + this.linkTarget = config.externalLinkTarget || '_blank'; + this.contentBase = getBasePath(config.basePath); + + var renderer = this._initRenderer(); + var compile; + var mdConf = config.markdown || {}; + + if (isFn(mdConf)) { + compile = mdConf(marked, renderer); } else { - renderer = merge(renderer, config.renderer); - marked.setOptions(merge(config, { renderer: renderer })); + marked.setOptions(merge(mdConf, { + renderer: merge(renderer, mdConf.renderer) + })); + compile = marked; } + + this.compile = cached(function (text) { + var html = ''; + + if (!text) { return text } + + html = compile(text); + html = config.noEmoji ? html : emojify(html); + slugify.clear(); + + return html + }); }; -markdown.update = function () { - currentPath = parse().path; -}; +Compiler.prototype._initRenderer = function _initRenderer () { + var renderer = new marked.Renderer(); + var ref = this; + var linkTarget = ref.linkTarget; + var router = ref.router; + var toc = ref.toc; + var contentBase = ref.contentBase; + /** + * render anchor tag + * @link https://github.com/chjj/marked#overriding-renderer-methods + */ + renderer.heading = function (text, level) { + var nextToc = { level: level, title: text }; -/** - * render anchor tag - * @link https://github.com/chjj/marked#overriding-renderer-methods - */ -renderer.heading = function (text, level) { - var nextToc = { level: level, title: text }; + if (/{docsify-ignore}/g.test(text)) { + text = text.replace('{docsify-ignore}', ''); + nextToc.title = text; + nextToc.ignoreSubHeading = true; + } - if (/{docsify-ignore}/g.test(text)) { - text = text.replace('{docsify-ignore}', ''); - nextToc.title = text; - nextToc.ignoreSubHeading = true; - } + if (/{docsify-ignore-all}/g.test(text)) { + text = text.replace('{docsify-ignore-all}', ''); + nextToc.title = text; + nextToc.ignoreAllSubs = true; + } - if (/{docsify-ignore-all}/g.test(text)) { - text = text.replace('{docsify-ignore-all}', ''); - nextToc.title = text; - nextToc.ignoreAllSubs = true; - } + var slug = slugify(text); + var url = router.toURL(router.getCurrentPath(), { id: slug }); + nextToc.slug = url; + toc.push(nextToc); - var slug = slugify(text); - var url = toURL(currentPath, { id: slug }); - nextToc.slug = url; - toc.push(nextToc); + return ("" + text + "") + }; + // highlight code + renderer.code = function (code, lang) { + if ( lang === void 0 ) lang = ''; - return ("" + text + "") -}; -// highlight code -renderer.code = function (code, lang) { - if ( lang === void 0 ) lang = ''; + var hl = prism.highlight(code, prism.languages[lang] || prism.languages.markup); - var hl = prism.highlight(code, prism.languages[lang] || prism.languages.markup); + return ("
    " + hl + "
    ") + }; + renderer.link = function (href, title, text) { + var blank = ''; + if (!/:|(\/{2})/.test(href)) { + href = router.toURL(href, null, router.getCurrentPath()); + } else { + blank = " target=\"" + linkTarget + "\""; + } + if (title) { + title = " title=\"" + title + "\""; + } + return ("" + text + "") + }; + renderer.paragraph = function (text) { + if (/^!>/.test(text)) { + return helper('tip', text) + } else if (/^\?>/.test(text)) { + return helper('warn', text) + } + return ("

    " + text + "

    ") + }; + renderer.image = function (href, title, text) { + var url = href; + var titleHTML = title ? (" title=\"" + title + "\"") : ''; - return ("
    " + hl + "
    ") -}; -renderer.link = function (href, title, text) { - var blank = ''; - if (!/:|(\/{2})/.test(href)) { - href = toURL(href, null, currentPath); - } else { - blank = " target=\"" + linkTarget + "\""; - } - if (title) { - title = " title=\"" + title + "\""; - } - return ("" + text + "") -}; -renderer.paragraph = function (text) { - if (/^!>/.test(text)) { - return helper('tip', text) - } else if (/^\?>/.test(text)) { - return helper('warn', text) - } - return ("

    " + text + "

    ") -}; -renderer.image = function (href, title, text) { - var url = href; - var titleHTML = title ? (" title=\"" + title + "\"") : ''; + if (!isAbsolutePath(href)) { + url = getPath(contentBase, href); + } - if (!isAbsolutePath(href)) { - url = getPath(contentBase, href); - } + return ("\""") + }; - return ("\""") + return renderer }; /** * Compile sidebar */ -function sidebar (text, level) { +Compiler.prototype.sidebar = function sidebar (text, level) { + var currentPath = this.router.getCurrentPath(); var html = ''; if (text) { - html = markdown(text); - html = html.match(/]*>([\s\S]+)<\/ul>/g)[0]; + html = this.compile(text); + html = html && html.match(/]*>([\s\S]+)<\/ul>/g)[0]; } else { - var tree$$1 = cacheTree[currentPath] || genTree(toc, level); + var tree$$1 = this.cacheTree[currentPath] || genTree(this.toc, level); html = tree(tree$$1, '