diff --git a/src/hook.js b/src/hook.js new file mode 100644 index 000000000..311103d9e --- /dev/null +++ b/src/hook.js @@ -0,0 +1,52 @@ +export default class Hook { + constructor () { + this.beforeHooks = [] + this.afterHooks = [] + this.initHooks = [] + this.readyHooks = [] + } + + beforeEach (fn) { + this.beforeHooks.push(fn) + } + + afterEach (fn) { + this.afterHooks.push(fn) + } + + init (fn) { + this.initHooks.push(fn) + } + + ready (fn) { + this.readyHooks.push(fn) + } + + emit (name, data, next) { + let newData = data + const queue = this[name + 'Hooks'] + const step = function (index) { + const hook = queue[index] + if (index >= queue.length) { + next && next(newData) + } else { + if (typeof hook === 'function') { + if (hook.length === 2) { + hook(data, result => { + newData = result + step(index + 1) + }) + } else { + const result = hook(data) + newData = result !== undefined ? result : newData + step(index + 1) + } + } else { + step(index + 1) + } + } + } + + step(0) + } +} diff --git a/src/index.js b/src/index.js index f07ef5d86..3065d1802 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ import * as utils from './util' import { scrollIntoView, activeLink } from './event' import * as render from './render' +import Hook from './hook' const OPTIONS = utils.merge({ el: '#app', @@ -33,11 +34,14 @@ if (script) { if (OPTIONS.name === true) OPTIONS.name = '' } +const hook = new Hook() + // utils window.$docsify = OPTIONS window.Docsify = { installed: true, - utils: utils.merge({}, utils) + utils: utils.merge({}, utils), + hook } // load options @@ -107,21 +111,26 @@ const mainRender = function (cb) { } const Docsify = function () { - const dom = document.querySelector(OPTIONS.el) || document.body - const replace = dom !== document.body - const main = function () { - mainRender(_ => { - scrollIntoView() - activeLink('nav') - ;[].concat(window.$docsify.plugins).forEach(fn => fn && fn()) - }) - } + setTimeout(_ => { + ;[].concat(OPTIONS.plugins).forEach(fn => typeof fn === 'function' && fn(hook)) + window.Docsify.hook.emit('init') + + const dom = document.querySelector(OPTIONS.el) || document.body + const replace = dom !== document.body + const main = function () { + mainRender(_ => { + scrollIntoView() + activeLink('nav') + }) + } - // Render app - render.renderApp(dom, replace) - main() - if (!/^#\//.test(window.location.hash)) window.location.hash = '#/' - window.addEventListener('hashchange', main) + // Render app + render.renderApp(dom, replace) + main() + if (!/^#\//.test(window.location.hash)) window.location.hash = '#/' + window.addEventListener('hashchange', main) + window.Docsify.hook.emit('ready') + }, 0) } export default Docsify() diff --git a/src/plugins/ga.js b/src/plugins/ga.js index d45fac22f..40c455f21 100644 --- a/src/plugins/ga.js +++ b/src/plugins/ga.js @@ -28,18 +28,15 @@ const install = function () { if (install.installed) return install.installed = true - if (!window.Docsify || !window.Docsify.installed) { - console.error('[Docsify] Please load docsify.js first.') - return - } - if (!window.$docsify.ga) { console.error('[Docsify] ga is required.') return } - collect() - window.$docsify.plugins = [].concat(window.$docsify.plugins, collect) + window.$docsify.plugins = [].concat(function (hook) { + hook.init(collect) + hook.beforeEach(collect) + }, window.$docsify.plugins) } export default install() diff --git a/src/plugins/search.js b/src/plugins/search.js index a34307db8..b76e1d02b 100644 --- a/src/plugins/search.js +++ b/src/plugins/search.js @@ -324,13 +324,6 @@ const install = function () { if (install.installed) return install.installed = true - if (!window.Docsify || !window.Docsify.installed) { - console.error('[Docsify] Please load docsify.js first.') - return - } - - window.$docsify.plugins = [].concat(window.$docsify.plugins, searchPlugin) - const userConfig = window.$docsify.search const isNil = window.Docsify.utils.isNil @@ -342,7 +335,15 @@ const install = function () { CONFIG.placeholder = userConfig.placeholder || CONFIG.placeholder } - new SearchComponent() + window.$docsify.plugins = [].concat(hook => { + const isAuto = CONFIG.paths === 'auto' + + hook.ready(() => { + new SearchComponent() + !isAuto && searchPlugin() + }) + isAuto && hook.beforeEach(searchPlugin) + }, window.$docsify.plugins) } export default install() diff --git a/src/render.js b/src/render.js index 83d7e30cf..bc08ec960 100644 --- a/src/render.js +++ b/src/render.js @@ -123,25 +123,34 @@ export function renderApp (dom, replace) { * article */ export function renderArticle (content) { - renderTo('article', content ? markdown(content) : 'not found') - if (!$docsify.loadSidebar) renderSidebar() - - if (content && typeof Vue !== 'undefined') { - CACHE.vm && CACHE.vm.$destroy() - - const script = [].slice.call( - document.body.querySelectorAll('article>script')) - .filter(script => !/template/.test(script.type) - )[0] - const code = script ? script.innerText.trim() : null - - script && script.remove() - CACHE.vm = code - ? new Function(`return ${code}`)() - : new Vue({ el: 'main' }) // eslint-disable-line - CACHE.vm && CACHE.vm.$nextTick(_ => event.scrollActiveSidebar()) + const hook = window.Docsify.hook + const renderFn = function (data) { + renderTo('article', data) + if (!$docsify.loadSidebar) renderSidebar() + + if (data && typeof Vue !== 'undefined') { + CACHE.vm && CACHE.vm.$destroy() + + const script = [].slice.call( + document.body.querySelectorAll('article>script')) + .filter(script => !/template/.test(script.type) + )[0] + const code = script ? script.innerText.trim() : null + + script && script.remove() + CACHE.vm = code + ? new Function(`return ${code}`)() + : new Vue({ el: 'main' }) // eslint-disable-line + CACHE.vm && CACHE.vm.$nextTick(_ => event.scrollActiveSidebar()) + } + if ($docsify.auto2top) setTimeout(() => event.scroll2Top($docsify.auto2top), 0) } - if ($docsify.auto2top) setTimeout(() => event.scroll2Top($docsify.auto2top), 0) + + hook.emit('before', content, result => { + const html = result ? markdown(result) : '' + + hook.emit('after', html, result => renderFn(result || 'not found')) + }) } /**