Skip to content

Commit 9e81a59

Browse files
committed
feat(hook): support custom plugin
1 parent 6f87529 commit 9e81a59

File tree

5 files changed

+116
-48
lines changed

5 files changed

+116
-48
lines changed

src/hook.js

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
export default class Hook {
2+
constructor () {
3+
this.beforeHooks = []
4+
this.afterHooks = []
5+
this.initHooks = []
6+
this.readyHooks = []
7+
}
8+
9+
beforeEach (fn) {
10+
this.beforeHooks.push(fn)
11+
}
12+
13+
afterEach (fn) {
14+
this.afterHooks.push(fn)
15+
}
16+
17+
init (fn) {
18+
this.initHooks.push(fn)
19+
}
20+
21+
ready (fn) {
22+
this.readyHooks.push(fn)
23+
}
24+
25+
emit (name, data, next) {
26+
let newData = data
27+
const queue = this[name + 'Hooks']
28+
const step = function (index) {
29+
const hook = queue[index]
30+
if (index >= queue.length) {
31+
next && next(newData)
32+
} else {
33+
if (typeof hook === 'function') {
34+
if (hook.length === 2) {
35+
hook(data, result => {
36+
newData = result
37+
step(index + 1)
38+
})
39+
} else {
40+
const result = hook(data)
41+
newData = result !== undefined ? result : newData
42+
step(index + 1)
43+
}
44+
} else {
45+
step(index + 1)
46+
}
47+
}
48+
}
49+
50+
step(0)
51+
}
52+
}

src/index.js

+24-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as utils from './util'
22
import { scrollIntoView, activeLink } from './event'
33
import * as render from './render'
4+
import Hook from './hook'
45

56
const OPTIONS = utils.merge({
67
el: '#app',
@@ -33,11 +34,14 @@ if (script) {
3334
if (OPTIONS.name === true) OPTIONS.name = ''
3435
}
3536

37+
const hook = new Hook()
38+
3639
// utils
3740
window.$docsify = OPTIONS
3841
window.Docsify = {
3942
installed: true,
40-
utils: utils.merge({}, utils)
43+
utils: utils.merge({}, utils),
44+
hook
4145
}
4246

4347
// load options
@@ -107,21 +111,26 @@ const mainRender = function (cb) {
107111
}
108112

109113
const Docsify = function () {
110-
const dom = document.querySelector(OPTIONS.el) || document.body
111-
const replace = dom !== document.body
112-
const main = function () {
113-
mainRender(_ => {
114-
scrollIntoView()
115-
activeLink('nav')
116-
;[].concat(window.$docsify.plugins).forEach(fn => fn && fn())
117-
})
118-
}
114+
setTimeout(_ => {
115+
;[].concat(OPTIONS.plugins).forEach(fn => typeof fn === 'function' && fn(hook))
116+
window.Docsify.hook.emit('init')
117+
118+
const dom = document.querySelector(OPTIONS.el) || document.body
119+
const replace = dom !== document.body
120+
const main = function () {
121+
mainRender(_ => {
122+
scrollIntoView()
123+
activeLink('nav')
124+
})
125+
}
119126

120-
// Render app
121-
render.renderApp(dom, replace)
122-
main()
123-
if (!/^#\//.test(window.location.hash)) window.location.hash = '#/'
124-
window.addEventListener('hashchange', main)
127+
// Render app
128+
render.renderApp(dom, replace)
129+
main()
130+
if (!/^#\//.test(window.location.hash)) window.location.hash = '#/'
131+
window.addEventListener('hashchange', main)
132+
window.Docsify.hook.emit('ready')
133+
}, 0)
125134
}
126135

127136
export default Docsify()

src/plugins/ga.js

+4-7
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,15 @@ const install = function () {
2828
if (install.installed) return
2929
install.installed = true
3030

31-
if (!window.Docsify || !window.Docsify.installed) {
32-
console.error('[Docsify] Please load docsify.js first.')
33-
return
34-
}
35-
3631
if (!window.$docsify.ga) {
3732
console.error('[Docsify] ga is required.')
3833
return
3934
}
4035

41-
collect()
42-
window.$docsify.plugins = [].concat(window.$docsify.plugins, collect)
36+
window.$docsify.plugins = [].concat(function (hook) {
37+
hook.init(collect)
38+
hook.beforeEach(collect)
39+
}, window.$docsify.plugins)
4340
}
4441

4542
export default install()

src/plugins/search.js

+9-8
Original file line numberDiff line numberDiff line change
@@ -324,13 +324,6 @@ const install = function () {
324324
if (install.installed) return
325325
install.installed = true
326326

327-
if (!window.Docsify || !window.Docsify.installed) {
328-
console.error('[Docsify] Please load docsify.js first.')
329-
return
330-
}
331-
332-
window.$docsify.plugins = [].concat(window.$docsify.plugins, searchPlugin)
333-
334327
const userConfig = window.$docsify.search
335328
const isNil = window.Docsify.utils.isNil
336329

@@ -342,7 +335,15 @@ const install = function () {
342335
CONFIG.placeholder = userConfig.placeholder || CONFIG.placeholder
343336
}
344337

345-
new SearchComponent()
338+
window.$docsify.plugins = [].concat(hook => {
339+
const isAuto = CONFIG.paths === 'auto'
340+
341+
hook.ready(() => {
342+
new SearchComponent()
343+
!isAuto && searchPlugin()
344+
})
345+
isAuto && hook.beforeEach(searchPlugin)
346+
}, window.$docsify.plugins)
346347
}
347348

348349
export default install()

src/render.js

+27-18
Original file line numberDiff line numberDiff line change
@@ -123,25 +123,34 @@ export function renderApp (dom, replace) {
123123
* article
124124
*/
125125
export function renderArticle (content) {
126-
renderTo('article', content ? markdown(content) : 'not found')
127-
if (!$docsify.loadSidebar) renderSidebar()
128-
129-
if (content && typeof Vue !== 'undefined') {
130-
CACHE.vm && CACHE.vm.$destroy()
131-
132-
const script = [].slice.call(
133-
document.body.querySelectorAll('article>script'))
134-
.filter(script => !/template/.test(script.type)
135-
)[0]
136-
const code = script ? script.innerText.trim() : null
137-
138-
script && script.remove()
139-
CACHE.vm = code
140-
? new Function(`return ${code}`)()
141-
: new Vue({ el: 'main' }) // eslint-disable-line
142-
CACHE.vm && CACHE.vm.$nextTick(_ => event.scrollActiveSidebar())
126+
const hook = window.Docsify.hook
127+
const renderFn = function (data) {
128+
renderTo('article', data)
129+
if (!$docsify.loadSidebar) renderSidebar()
130+
131+
if (data && typeof Vue !== 'undefined') {
132+
CACHE.vm && CACHE.vm.$destroy()
133+
134+
const script = [].slice.call(
135+
document.body.querySelectorAll('article>script'))
136+
.filter(script => !/template/.test(script.type)
137+
)[0]
138+
const code = script ? script.innerText.trim() : null
139+
140+
script && script.remove()
141+
CACHE.vm = code
142+
? new Function(`return ${code}`)()
143+
: new Vue({ el: 'main' }) // eslint-disable-line
144+
CACHE.vm && CACHE.vm.$nextTick(_ => event.scrollActiveSidebar())
145+
}
146+
if ($docsify.auto2top) setTimeout(() => event.scroll2Top($docsify.auto2top), 0)
143147
}
144-
if ($docsify.auto2top) setTimeout(() => event.scroll2Top($docsify.auto2top), 0)
148+
149+
hook.emit('before', content, result => {
150+
const html = result ? markdown(result) : ''
151+
152+
hook.emit('after', html, result => renderFn(result || 'not found'))
153+
})
145154
}
146155

147156
/**

0 commit comments

Comments
 (0)