import marked from 'marked' import Prism from 'prismjs' import * as tpl from './tpl' import { activeLink, scrollActiveSidebar, bindToggle, scroll2Top, sticky } from './event' import { genTree, getRoute, isMobile } from './util' let OPTIONS = {} const CACHE = {} const renderTo = function (dom, content) { dom = typeof dom === 'object' ? dom : document.querySelector(dom) dom.innerHTML = content return dom } let toc = [] const renderer = new marked.Renderer() /** * render anchor tag * @link https://github.com/chjj/marked#overriding-renderer-methods */ renderer.heading = function (text, level) { const slug = text.toLowerCase() .replace(/<(?:.|\n)*?>/gm, '') .replace(/[^\w|\u4e00-\u9fa5]+/g, '-') let route = '' if (OPTIONS.router) { route = `#/${getRoute()}` } toc.push({ level, slug: `${route}#${encodeURIComponent(slug)}`, title: text }) return `${text}` } // highlight code renderer.code = function (code, lang = '') { const hl = Prism.highlight(code, Prism.languages[lang] || Prism.languages.markup) return `
${hl}
` } renderer.link = function (href, title, text) { if (OPTIONS.router && !/^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/.test(href)) { href = !/^\/#/.test(href) ? `#${href}` : href } return `${text}` } marked.setOptions({ renderer }) /** * App */ export function renderApp (dom, replace) { const nav = document.querySelector('nav') || document.createElement('nav') if (!OPTIONS.repo) nav.classList.add('no-badge') dom[replace ? 'outerHTML' : 'innerHTML'] = tpl.corner(OPTIONS.repo) + (OPTIONS.coverpage ? tpl.cover() : '') + tpl.main(OPTIONS.sidebarToggle ? tpl.toggle() : '') document.body.insertBefore(nav, document.body.children[0]) // bind toggle bindToggle('button.sidebar-toggle') // bind sticky effect if (OPTIONS.coverpage) { !isMobile() && window.addEventListener('scroll', sticky) } else { document.body.classList.add('sticky') } } /** * article */ export function renderArticle (content) { renderTo('article', content ? marked(content) : 'not found') if (!renderSidebar.rendered) renderSidebar(null, OPTIONS) if (!renderNavbar.rendered) renderNavbar(null, OPTIONS) renderSidebar.rendered = false renderNavbar.rendered = false if (OPTIONS.auto2top) scroll2Top() } /** * navbar */ export function renderNavbar (content) { if (CACHE.navbar && CACHE.navbar === content) return CACHE.navbar = content renderNavbar.rendered = true if (content) renderTo('nav', marked(content)) activeLink('nav') } /** * sidebar */ export function renderSidebar (content) { let isToc = false if (content) { content = marked(content) } else if (OPTIONS.sidebar) { content = tpl.tree(OPTIONS.sidebar, '