feat(compiler): support embedded markdown, html, video, etc files, close #383, close #333

This commit is contained in:
qingwei.li 2018-02-10 12:08:56 +08:00 committed by cinwell.li
parent a90a2e49e1
commit 524f52f882
4 changed files with 69 additions and 14 deletions

View File

@ -2,6 +2,7 @@ import progressbar from '../render/progressbar'
import { noop } from '../util/core'
const cache = {}
let uid = 0
/**
* Simple ajax get
@ -24,6 +25,7 @@ export function get (url, hasBar = false) {
xhr.send()
return {
uid: uid++,
then: function (success, error = noop) {
if (hasBar) {
const id = setInterval(

View File

@ -6,6 +6,7 @@ import { slugify } from './slugify'
import { emojify } from './emojify'
import { isAbsolutePath, getPath } from '../router/util'
import { isFn, merge, cached } from '../util/core'
import { get } from '../fetch/ajax'
const cachedLinks = {}
function getAndRemoveConfig (str = '') {
@ -22,6 +23,27 @@ function getAndRemoveConfig (str = '') {
return { str, config }
}
const compileMedia = {
markdown (url, config) {
const request = get(url, false)
const id = `docsify-get-${request.uid}`
request.then(text => {
document.getElementById(id).innerHTML = this.compile(text)
})
return `<div data-origin="${url}" id=${id}></div>`
},
html (url, config) {
return `<iframe src="${url}" ${config || 'width=100% height=400'}></iframe>`
},
video (url, config) {
return `<video src="${url}" ${config || 'controls'}>Not Support</video>`
},
audio (url, config) {
return `<audio src="${url}" ${config || 'controls'}>Not Support</audio>`
}
}
export class Compiler {
constructor (config, router) {
@ -172,6 +194,25 @@ export class Compiler {
url = getPath(contentBase, href)
}
let media
if (config.type && (media = compileMedia[config.type])) {
return media.call(_self, url, title)
}
let type = null
if (/\.(md|markdown)/.test(url)) {
type = 'markdown'
} else if (/\.html?/.test(url)) {
type = 'html'
} else if (/\.(mp4|ogg)/.test(url)) {
type = 'video'
} else if (/\.mp3/.test(url)) {
type = 'audio'
}
if (type) {
return compileMedia[type].call(_self, url, title)
}
return `<img src="${url}"data-origin="${href}" alt="${text}"${attrs}>`
}
@ -179,7 +220,10 @@ export class Compiler {
origin.listitem = renderer.listitem = function (text) {
const checked = CHECKED_RE.exec(text)
if (checked) {
text = text.replace(CHECKED_RE, `<input type="checkbox" ${checked[1] === 'x' ? 'checked' : ''} />`)
text = text.replace(
CHECKED_RE,
`<input type="checkbox" ${checked[1] === 'x' ? 'checked' : ''} />`
)
}
return `<li${checked ? ` class="task-list-item"` : ''}>${text}</li>\n`
}

View File

@ -11,8 +11,9 @@ import { isPrimitive } from '../util/core'
import { scrollActiveSidebar, scroll2Top } from '../event/scroll'
function executeScript () {
const script = dom.findAll('.markdown-section>script')
.filter(s => !/template/.test(s.type))[0]
const script = dom
.findAll('.markdown-section>script')
.filter(s => !/template/.test(s.type))[0]
if (!script) return false
const code = script.innerText.trim()
if (!code) return false
@ -23,11 +24,10 @@ function executeScript () {
}
function formatUpdated (html, updated, fn) {
updated = typeof fn === 'function'
? fn(updated)
: typeof fn === 'string'
? tinydate(fn)(new Date(updated))
: updated
updated =
typeof fn === 'function'
? fn(updated)
: typeof fn === 'string' ? tinydate(fn)(new Date(updated)) : updated
return html.replace(/{docsify-updated}/g, updated)
}
@ -43,9 +43,11 @@ function renderMain (html) {
!this.config.loadSidebar && this._renderSidebar()
// execute script
if (this.config.executeScript !== false &&
typeof window.Vue !== 'undefined' &&
!executeScript()) {
if (
this.config.executeScript !== false &&
typeof window.Vue !== 'undefined' &&
!executeScript()
) {
setTimeout(_ => {
const vueVM = window.__EXECUTE_RESULT__
vueVM && vueVM.$destroy && vueVM.$destroy()
@ -84,7 +86,8 @@ export function renderMixin (proto) {
this._renderTo('.sidebar-nav', this.compiler.sidebar(text, maxLevel))
const activeEl = getAndActive(this.router, '.sidebar-nav', true, true)
if (loadSidebar && activeEl) {
activeEl.parentNode.innerHTML += (this.compiler.subSidebar(subMaxLevel) || '')
activeEl.parentNode.innerHTML +=
this.compiler.subSidebar(subMaxLevel) || ''
} else {
// reset toc
this.compiler.subSidebar()
@ -140,7 +143,9 @@ export function renderMixin (proto) {
dom.toggleClass(el, 'add', 'show')
let html = this.coverIsHTML ? text : this.compiler.cover(text)
const m = html.trim().match('<p><img.*?data-origin="(.*?)"[^a]+alt="(.*?)">([^<]*?)</p>$')
const m = html
.trim()
.match('<p><img.*?data-origin="(.*?)"[^a]+alt="(.*?)">([^<]*?)</p>$')
if (m) {
if (m[2] === 'color') {

View File

@ -95,7 +95,7 @@ kbd {
list-style-type: none;
}
li input[type=checkbox] {
li input[type='checkbox'] {
margin: 0 0.2em 0.25em -1.6em;
vertical-align: middle;
}
@ -381,6 +381,10 @@ body.sticky {
margin: 2em 0;
}
.markdown-section iframe {
border: 1px solid #eee;
}
.markdown-section table {
border-collapse: collapse;
border-spacing: 0;