mirror of
https://github.com/docsifyjs/docsify.git
synced 2025-12-08 19:55:52 +00:00
refactor(embed): async fetch embed files, fixed #387
This commit is contained in:
parent
471e407c73
commit
62ce447fc3
@ -47,12 +47,10 @@ export function fetchMixin (proto) {
|
||||
// Load main content
|
||||
last.then(
|
||||
(text, opt) => {
|
||||
this._renderMain(text, opt)
|
||||
loadSideAndNav()
|
||||
this._renderMain(text, opt, loadSideAndNav)
|
||||
},
|
||||
_ => {
|
||||
this._renderMain(null)
|
||||
loadSideAndNav()
|
||||
this._renderMain(null, {}, loadSideAndNav)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@ -5,13 +5,12 @@ import { genTree } from './gen-tree'
|
||||
import { slugify } from './slugify'
|
||||
import { emojify } from './emojify'
|
||||
import { isAbsolutePath, getPath } from '../router/util'
|
||||
import { isFn, merge, cached } from '../util/core'
|
||||
import { isFn, merge, cached, isPrimitive } from '../util/core'
|
||||
import { get } from '../fetch/ajax'
|
||||
|
||||
const cachedLinks = {}
|
||||
let uid = 0
|
||||
|
||||
function getAndRemoveConfig (str = '') {
|
||||
export function getAndRemoveConfig (str = '') {
|
||||
const config = {}
|
||||
|
||||
if (str) {
|
||||
@ -25,62 +24,37 @@ function getAndRemoveConfig (str = '') {
|
||||
|
||||
return { str, config }
|
||||
}
|
||||
|
||||
const compileMedia = {
|
||||
markdown (url) {
|
||||
const id = `docsify-get-${uid++}`
|
||||
|
||||
if (!process.env.SSR) {
|
||||
get(url, false).then(text => {
|
||||
document.getElementById(id).innerHTML = this.compile(text)
|
||||
})
|
||||
|
||||
return `<div data-origin="${url}" id=${id}></div>`
|
||||
} else {
|
||||
return `<div data-origin="${url}" id=${uid}></div>
|
||||
<script>
|
||||
var compile = window.__current_docsify_compiler__
|
||||
Docsify.get('${url}', false).then(function(text) {
|
||||
document.getElementById('${uid}').innerHTML = compile(text)
|
||||
})
|
||||
</script>`
|
||||
return {
|
||||
url
|
||||
}
|
||||
},
|
||||
iframe (url, title) {
|
||||
return `<iframe src="${url}" ${title || 'width=100% height=400'}></iframe>`
|
||||
return {
|
||||
code: `<iframe src="${url}" ${title || 'width=100% height=400'}></iframe>`
|
||||
}
|
||||
},
|
||||
video (url, title) {
|
||||
return `<video src="${url}" ${title || 'controls'}>Not Support</video>`
|
||||
return {
|
||||
code: `<video src="${url}" ${title || 'controls'}>Not Support</video>`
|
||||
}
|
||||
},
|
||||
audio (url, title) {
|
||||
return `<audio src="${url}" ${title || 'controls'}>Not Support</audio>`
|
||||
return {
|
||||
code: `<audio src="${url}" ${title || 'controls'}>Not Support</audio>`
|
||||
}
|
||||
},
|
||||
code (url, title) {
|
||||
const id = `docsify-get-${uid++}`
|
||||
let ext = url.match(/\.(\w+)$/)
|
||||
let lang = url.match(/\.(\w+)$/)
|
||||
|
||||
ext = title || (ext && ext[1])
|
||||
if (ext === 'md') ext = 'markdown'
|
||||
lang = title || (lang && lang[1])
|
||||
if (lang === 'md') lang = 'markdown'
|
||||
|
||||
if (!process.env.SSR) {
|
||||
get(url, false).then(text => {
|
||||
document.getElementById(id).innerHTML = this.compile(
|
||||
'```' + ext + '\n' + text.replace(/`/g, '@qm@') + '\n```\n'
|
||||
).replace(/@qm@/g, '`')
|
||||
})
|
||||
|
||||
return `<div data-origin="${url}" id=${id}></div>`
|
||||
} else {
|
||||
return `<div data-origin="${url}" id=${id}></div>
|
||||
<script>
|
||||
setTimeout(() => {
|
||||
var compiler = window.__current_docsify_compiler__
|
||||
Docsify.get('${url}', false).then(function(text) {
|
||||
document.getElementById('${id}').innerHTML = compiler
|
||||
.compile('\`\`\`${ext}\\n' + text.replace(/\`/g, '@qm@') + '\\n\`\`\`\\n')
|
||||
.replace(/@qm@/g, '\`')
|
||||
})
|
||||
})
|
||||
</script>`
|
||||
return {
|
||||
url,
|
||||
lang
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -109,12 +83,18 @@ export class Compiler {
|
||||
compile = marked
|
||||
}
|
||||
|
||||
this._marked = compile
|
||||
this.compile = cached(text => {
|
||||
let html = ''
|
||||
|
||||
if (!text) return text
|
||||
|
||||
html = compile(text)
|
||||
if (isPrimitive(text)) {
|
||||
html = compile(text)
|
||||
} else {
|
||||
html = compile.parser(text)
|
||||
}
|
||||
|
||||
html = config.noEmoji ? html : emojify(html)
|
||||
slugify.clear()
|
||||
|
||||
@ -122,7 +102,40 @@ export class Compiler {
|
||||
})
|
||||
}
|
||||
|
||||
matchNotCompileLink (link) {
|
||||
compileEmbed (href, title) {
|
||||
const { str, config } = getAndRemoveConfig(title)
|
||||
let embed
|
||||
title = str
|
||||
|
||||
if (config.include) {
|
||||
if (!isAbsolutePath(href)) {
|
||||
href = getPath(this.contentBase, href)
|
||||
}
|
||||
|
||||
let media
|
||||
if (config.type && (media = compileMedia[config.type])) {
|
||||
embed = media.call(this, href, title)
|
||||
embed.type = config.type
|
||||
} else {
|
||||
let type = 'code'
|
||||
if (/\.(md|markdown)/.test(href)) {
|
||||
type = 'markdown'
|
||||
} else if (/\.html?/.test(href)) {
|
||||
type = 'iframe'
|
||||
} else if (/\.(mp4|ogg)/.test(href)) {
|
||||
type = 'video'
|
||||
} else if (/\.mp3/.test(href)) {
|
||||
type = 'audio'
|
||||
}
|
||||
embed = compileMedia[type].call(this, href, title)
|
||||
embed.type = type
|
||||
}
|
||||
|
||||
return embed
|
||||
}
|
||||
}
|
||||
|
||||
_matchNotCompileLink (link) {
|
||||
const links = this.config.noCompileLinks || []
|
||||
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
@ -182,33 +195,9 @@ export class Compiler {
|
||||
const { str, config } = getAndRemoveConfig(title)
|
||||
title = str
|
||||
|
||||
if (config.include) {
|
||||
if (!isAbsolutePath(href)) {
|
||||
href = getPath(contentBase, href)
|
||||
}
|
||||
|
||||
let media
|
||||
if (config.type && (media = compileMedia[config.type])) {
|
||||
return media.call(_self, href, title)
|
||||
}
|
||||
|
||||
let type = 'code'
|
||||
if (/\.(md|markdown)/.test(href)) {
|
||||
type = 'markdown'
|
||||
} else if (/\.html?/.test(href)) {
|
||||
type = 'iframe'
|
||||
} else if (/\.(mp4|ogg)/.test(href)) {
|
||||
type = 'video'
|
||||
} else if (/\.mp3/.test(href)) {
|
||||
type = 'audio'
|
||||
}
|
||||
|
||||
return compileMedia[type].call(_self, href, title)
|
||||
}
|
||||
|
||||
if (
|
||||
!/:|(\/{2})/.test(href) &&
|
||||
!_self.matchNotCompileLink(href) &&
|
||||
!_self._matchNotCompileLink(href) &&
|
||||
!config.ignore
|
||||
) {
|
||||
if (href === _self.config.homepage) href = 'README'
|
||||
|
||||
84
src/core/render/embed.js
Normal file
84
src/core/render/embed.js
Normal file
@ -0,0 +1,84 @@
|
||||
import { get } from '../fetch/ajax'
|
||||
import { merge } from '../util/core'
|
||||
|
||||
const cached = {}
|
||||
|
||||
function walkFetchEmbed ({ step = 0, embedTokens, compile }, cb) {
|
||||
const token = embedTokens[step]
|
||||
|
||||
if (!token) {
|
||||
return cb({})
|
||||
}
|
||||
|
||||
get(token.embed.url).then(text => {
|
||||
let embedToken
|
||||
|
||||
if (token.embed.type === 'markdown') {
|
||||
embedToken = compile.lexer(text)
|
||||
} else if (token.embed.type === 'code') {
|
||||
embedToken = compile.lexer(
|
||||
'```' +
|
||||
token.embed.lang +
|
||||
'\n' +
|
||||
text.replace(/`/g, '@DOCSIFY_QM@') +
|
||||
'\n```\n'
|
||||
)
|
||||
}
|
||||
cb({ token, embedToken })
|
||||
walkFetchEmbed({ step: ++step, compile, embedTokens }, cb)
|
||||
})
|
||||
}
|
||||
|
||||
export function prerenderEmbed ({ compiler, raw }, done) {
|
||||
let hit
|
||||
if ((hit = cached[raw])) {
|
||||
return done(hit)
|
||||
}
|
||||
|
||||
const compile = compiler._marked
|
||||
let tokens = compile.lexer(raw)
|
||||
const embedTokens = []
|
||||
const linkRE = compile.InlineLexer.rules.link
|
||||
const links = tokens.links
|
||||
|
||||
tokens.forEach((token, index) => {
|
||||
if (token.type === 'paragraph') {
|
||||
token.text = token.text.replace(
|
||||
new RegExp(linkRE, 'g'),
|
||||
(src, filename, href, title) => {
|
||||
const embed = compiler.compileEmbed(href, title)
|
||||
|
||||
if (embed) {
|
||||
if (embed.type === 'markdown' || embed.type === 'code') {
|
||||
embedTokens.push({
|
||||
index,
|
||||
embed
|
||||
})
|
||||
}
|
||||
return embed.code
|
||||
}
|
||||
|
||||
return src
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
let moveIndex = 0
|
||||
walkFetchEmbed({ compile, embedTokens }, ({ embedToken, token }) => {
|
||||
if (token) {
|
||||
const index = token.index + moveIndex
|
||||
|
||||
merge(links, embedToken.links)
|
||||
|
||||
tokens = tokens
|
||||
.slice(0, index)
|
||||
.concat(embedToken, tokens.slice(index + 1))
|
||||
moveIndex += embedToken.length - 1
|
||||
} else {
|
||||
cached[raw] = tokens.concat()
|
||||
tokens.links = cached[raw].links = links
|
||||
done(tokens)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -9,6 +9,7 @@ import { getPath, isAbsolutePath } from '../router/util'
|
||||
import { isMobile, inBrowser } from '../util/env'
|
||||
import { isPrimitive } from '../util/core'
|
||||
import { scrollActiveSidebar, scroll2Top } from '../event/scroll'
|
||||
import { prerenderEmbed } from './embed'
|
||||
|
||||
function executeScript () {
|
||||
const script = dom
|
||||
@ -119,18 +120,37 @@ export function renderMixin (proto) {
|
||||
getAndActive(this.router, 'nav')
|
||||
}
|
||||
|
||||
proto._renderMain = function (text, opt = {}) {
|
||||
proto._renderMain = function (text, opt = {}, next) {
|
||||
if (!text) {
|
||||
return renderMain.call(this, text)
|
||||
}
|
||||
|
||||
callHook(this, 'beforeEach', text, result => {
|
||||
let html = this.isHTML ? result : this.compiler.compile(result)
|
||||
if (opt.updatedAt) {
|
||||
html = formatUpdated(html, opt.updatedAt, this.config.formatUpdated)
|
||||
}
|
||||
let html
|
||||
const callback = () => {
|
||||
if (opt.updatedAt) {
|
||||
html = formatUpdated(html, opt.updatedAt, this.config.formatUpdated)
|
||||
}
|
||||
|
||||
callHook(this, 'afterEach', html, text => renderMain.call(this, text))
|
||||
callHook(this, 'afterEach', html, text => renderMain.call(this, text))
|
||||
}
|
||||
if (this.isHTML) {
|
||||
html = this.result
|
||||
callback()
|
||||
next()
|
||||
} else {
|
||||
prerenderEmbed(
|
||||
{
|
||||
compiler: this.compiler,
|
||||
raw: text
|
||||
},
|
||||
tokens => {
|
||||
html = this.compiler.compile(tokens)
|
||||
callback()
|
||||
next()
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -4,8 +4,9 @@
|
||||
export function cached (fn) {
|
||||
const cache = Object.create(null)
|
||||
return function cachedFn (str) {
|
||||
const hit = cache[str]
|
||||
return hit || (cache[str] = fn(str))
|
||||
const key = isPrimitive(str) ? str : JSON.stringify(str)
|
||||
const hit = cache[key]
|
||||
return hit || (cache[key] = fn(str))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user