feat(hook): support custom plugin

This commit is contained in:
qingwei.li 2017-02-12 15:36:37 +08:00
commit 9e81a5975f
5 changed files with 113 additions and 45 deletions

52
src/hook.js Normal file
View file

@ -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)
}
}

View file

@ -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')
// Render app
render.renderApp(dom, replace)
main()
if (!/^#\//.test(window.location.hash)) window.location.hash = '#/'
window.addEventListener('hashchange', main)
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)
window.Docsify.hook.emit('ready')
}, 0)
}
export default Docsify()

View file

@ -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()

View file

@ -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()

View file

@ -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()
const hook = window.Docsify.hook
const renderFn = function (data) {
renderTo('article', data)
if (!$docsify.loadSidebar) renderSidebar()
if (content && typeof Vue !== 'undefined') {
CACHE.vm && CACHE.vm.$destroy()
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
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())
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'))
})
}
/**