refactor: build config (#408)
* refactor: build config * chore: fix conflict * fix: 404 page path
This commit is contained in:
parent
9b3b4454de
commit
8352a1e489
64 changed files with 4246 additions and 5512 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { merge, hyphenate, isPrimitive } from './util/core'
|
||||
import {merge, hyphenate, isPrimitive, hasOwn} from './util/core'
|
||||
|
||||
const config = merge(
|
||||
{
|
||||
|
|
@ -37,18 +37,30 @@ const script =
|
|||
|
||||
if (script) {
|
||||
for (const prop in config) {
|
||||
const val = script.getAttribute('data-' + hyphenate(prop))
|
||||
if (hasOwn.call(config, prop)) {
|
||||
const val = script.getAttribute('data-' + hyphenate(prop))
|
||||
|
||||
if (isPrimitive(val)) {
|
||||
config[prop] = val === '' ? true : val
|
||||
if (isPrimitive(val)) {
|
||||
config[prop] = val === '' ? true : val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.loadSidebar === true) config.loadSidebar = '_sidebar' + config.ext
|
||||
if (config.loadNavbar === true) config.loadNavbar = '_navbar' + config.ext
|
||||
if (config.coverpage === true) config.coverpage = '_coverpage' + config.ext
|
||||
if (config.repo === true) config.repo = ''
|
||||
if (config.name === true) config.name = ''
|
||||
if (config.loadSidebar === true) {
|
||||
config.loadSidebar = '_sidebar' + config.ext
|
||||
}
|
||||
if (config.loadNavbar === true) {
|
||||
config.loadNavbar = '_navbar' + config.ext
|
||||
}
|
||||
if (config.coverpage === true) {
|
||||
config.coverpage = '_coverpage' + config.ext
|
||||
}
|
||||
if (config.repo === true) {
|
||||
config.repo = ''
|
||||
}
|
||||
if (config.name === true) {
|
||||
config.name = ''
|
||||
}
|
||||
}
|
||||
|
||||
window.$docsify = config
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { isMobile } from '../util/env'
|
||||
import { body, on } from '../util/dom'
|
||||
import {isMobile} from '../util/env'
|
||||
import {body, on} from '../util/dom'
|
||||
import * as sidebar from './sidebar'
|
||||
import { scrollIntoView } from './scroll'
|
||||
import {scrollIntoView} from './scroll'
|
||||
|
||||
export function eventMixin (proto) {
|
||||
export function eventMixin(proto) {
|
||||
proto.$resetEvents = function () {
|
||||
scrollIntoView(this.route.path, this.route.query.id)
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ export function eventMixin (proto) {
|
|||
}
|
||||
}
|
||||
|
||||
export function initEvent (vm) {
|
||||
export function initEvent(vm) {
|
||||
// Bind toggle button
|
||||
sidebar.btn('button.sidebar-toggle', vm.router)
|
||||
sidebar.collapse('.sidebar', vm.router)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { isMobile } from '../util/env'
|
||||
import {isMobile} from '../util/env'
|
||||
import * as dom from '../util/dom'
|
||||
import Tweezer from 'tweezer.js'
|
||||
|
||||
|
|
@ -8,8 +8,10 @@ let scroller = null
|
|||
let enableScrollEvent = true
|
||||
let coverHeight = 0
|
||||
|
||||
function scrollTo (el) {
|
||||
if (scroller) scroller.stop()
|
||||
function scrollTo(el) {
|
||||
if (scroller) {
|
||||
scroller.stop()
|
||||
}
|
||||
enableScrollEvent = false
|
||||
scroller = new Tweezer({
|
||||
start: window.pageYOffset,
|
||||
|
|
@ -24,8 +26,10 @@ function scrollTo (el) {
|
|||
.begin()
|
||||
}
|
||||
|
||||
function highlight (path) {
|
||||
if (!enableScrollEvent) return
|
||||
function highlight(path) {
|
||||
if (!enableScrollEvent) {
|
||||
return
|
||||
}
|
||||
const sidebar = dom.getNode('.sidebar')
|
||||
const anchors = dom.findAll('.anchor')
|
||||
const wrap = dom.find(sidebar, '.sidebar-nav')
|
||||
|
|
@ -38,22 +42,28 @@ function highlight (path) {
|
|||
const node = anchors[i]
|
||||
|
||||
if (node.offsetTop > top) {
|
||||
if (!last) last = node
|
||||
if (!last) {
|
||||
last = node
|
||||
}
|
||||
break
|
||||
} else {
|
||||
last = node
|
||||
}
|
||||
}
|
||||
if (!last) return
|
||||
if (!last) {
|
||||
return
|
||||
}
|
||||
const li = nav[getNavKey(path, last.getAttribute('data-id'))]
|
||||
|
||||
if (!li || li === active) return
|
||||
if (!li || li === active) {
|
||||
return
|
||||
}
|
||||
|
||||
active && active.classList.remove('active')
|
||||
li.classList.add('active')
|
||||
active = li
|
||||
|
||||
// scroll into view
|
||||
// Scroll into view
|
||||
// https://github.com/vuejs/vuejs.org/blob/master/themes/vue/source/js/common.js#L282-L297
|
||||
if (!hoverOver && dom.body.classList.contains('sticky')) {
|
||||
const height = sidebar.clientHeight
|
||||
|
|
@ -68,11 +78,11 @@ function highlight (path) {
|
|||
}
|
||||
}
|
||||
|
||||
function getNavKey (path, id) {
|
||||
function getNavKey(path, id) {
|
||||
return `${path}?id=${id}`
|
||||
}
|
||||
|
||||
export function scrollActiveSidebar (router) {
|
||||
export function scrollActiveSidebar(router) {
|
||||
const cover = dom.find('.cover.show')
|
||||
coverHeight = cover ? cover.offsetHeight : 0
|
||||
|
||||
|
|
@ -82,18 +92,26 @@ export function scrollActiveSidebar (router) {
|
|||
for (let i = 0, len = lis.length; i < len; i += 1) {
|
||||
const li = lis[i]
|
||||
const a = li.querySelector('a')
|
||||
if (!a) continue
|
||||
if (!a) {
|
||||
continue
|
||||
}
|
||||
let href = a.getAttribute('href')
|
||||
|
||||
if (href !== '/') {
|
||||
const { query: { id }, path } = router.parse(href)
|
||||
if (id) href = getNavKey(path, id)
|
||||
const {query: {id}, path} = router.parse(href)
|
||||
if (id) {
|
||||
href = getNavKey(path, id)
|
||||
}
|
||||
}
|
||||
|
||||
if (href) nav[decodeURIComponent(href)] = li
|
||||
if (href) {
|
||||
nav[decodeURIComponent(href)] = li
|
||||
}
|
||||
}
|
||||
|
||||
if (isMobile) return
|
||||
if (isMobile) {
|
||||
return
|
||||
}
|
||||
const path = router.getCurrentPath()
|
||||
dom.off('scroll', () => highlight(path))
|
||||
dom.on('scroll', () => highlight(path))
|
||||
|
|
@ -105,8 +123,10 @@ export function scrollActiveSidebar (router) {
|
|||
})
|
||||
}
|
||||
|
||||
export function scrollIntoView (path, id) {
|
||||
if (!id) return
|
||||
export function scrollIntoView(path, id) {
|
||||
if (!id) {
|
||||
return
|
||||
}
|
||||
|
||||
const section = dom.find('#' + id)
|
||||
section && scrollTo(section)
|
||||
|
|
@ -120,6 +140,6 @@ export function scrollIntoView (path, id) {
|
|||
|
||||
const scrollEl = dom.$.scrollingElement || dom.$.documentElement
|
||||
|
||||
export function scroll2Top (offset = 0) {
|
||||
export function scroll2Top(offset = 0) {
|
||||
scrollEl.scrollTop = offset === true ? 0 : Number(offset)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { isMobile } from '../util/env'
|
||||
import {isMobile} from '../util/env'
|
||||
import * as dom from '../util/dom'
|
||||
|
||||
const title = dom.$.title
|
||||
/**
|
||||
* Toggle button
|
||||
*/
|
||||
export function btn (el, router) {
|
||||
export function btn(el) {
|
||||
const toggle = _ => dom.body.classList.toggle('close')
|
||||
|
||||
el = dom.getNode(el)
|
||||
|
|
@ -22,10 +22,10 @@ export function btn (el, router) {
|
|||
)
|
||||
}
|
||||
|
||||
export function collapse (el, router) {
|
||||
export function collapse(el) {
|
||||
el = dom.getNode(el)
|
||||
|
||||
dom.on(el, 'click', ({ target }) => {
|
||||
dom.on(el, 'click', ({target}) => {
|
||||
if (
|
||||
target.nodeName === 'A' &&
|
||||
target.nextSibling &&
|
||||
|
|
@ -36,9 +36,11 @@ export function collapse (el, router) {
|
|||
})
|
||||
}
|
||||
|
||||
export function sticky () {
|
||||
export function sticky() {
|
||||
const cover = dom.getNode('section.cover')
|
||||
if (!cover) return
|
||||
if (!cover) {
|
||||
return
|
||||
}
|
||||
const coverHeight = cover.getBoundingClientRect().height
|
||||
|
||||
if (window.pageYOffset >= coverHeight || cover.classList.contains('hidden')) {
|
||||
|
|
@ -56,7 +58,7 @@ export function sticky () {
|
|||
* @param {Boolean} autoTitle auto set title
|
||||
* @return {element}
|
||||
*/
|
||||
export function getAndActive (router, el, isParent, autoTitle) {
|
||||
export function getAndActive(router, el, isParent, autoTitle) {
|
||||
el = dom.getNode(el)
|
||||
|
||||
const links = dom.findAll(el, 'a')
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import progressbar from '../render/progressbar'
|
||||
import { noop } from '../util/core'
|
||||
import {noop, hasOwn} from '../util/core'
|
||||
|
||||
const cache = {}
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ const cache = {}
|
|||
* @param {boolean} [hasBar=false] has progress bar
|
||||
* @return { then(resolve, reject), abort }
|
||||
*/
|
||||
export function get (url, hasBar = false, headers = {}) {
|
||||
export function get(url, hasBar = false, headers = {}) {
|
||||
const xhr = new XMLHttpRequest()
|
||||
const on = function () {
|
||||
xhr.addEventListener.apply(xhr, arguments)
|
||||
|
|
@ -17,12 +17,14 @@ export function get (url, hasBar = false, headers = {}) {
|
|||
const cached = cache[url]
|
||||
|
||||
if (cached) {
|
||||
return { then: cb => cb(cached.content, cached.opt), abort: noop }
|
||||
return {then: cb => cb(cached.content, cached.opt), abort: noop}
|
||||
}
|
||||
|
||||
xhr.open('GET', url)
|
||||
for (const i in headers) {
|
||||
xhr.setRequestHeader(i, headers[i])
|
||||
if (hasOwn.call(headers, i)) {
|
||||
xhr.setRequestHeader(i, headers[i])
|
||||
}
|
||||
}
|
||||
xhr.send()
|
||||
|
||||
|
|
@ -45,7 +47,7 @@ export function get (url, hasBar = false, headers = {}) {
|
|||
}
|
||||
|
||||
on('error', error)
|
||||
on('load', ({ target }) => {
|
||||
on('load', ({target}) => {
|
||||
if (target.status >= 400) {
|
||||
error(target)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import { get } from './ajax'
|
||||
import { callHook } from '../init/lifecycle'
|
||||
import { getParentPath, stringifyQuery } from '../router/util'
|
||||
import { noop } from '../util/core'
|
||||
import { getAndActive } from '../event/sidebar'
|
||||
import {get} from './ajax'
|
||||
import {callHook} from '../init/lifecycle'
|
||||
import {getParentPath, stringifyQuery} from '../router/util'
|
||||
import {noop} from '../util/core'
|
||||
import {getAndActive} from '../event/sidebar'
|
||||
|
||||
function loadNested (path, qs, file, next, vm, first) {
|
||||
function loadNested(path, qs, file, next, vm, first) {
|
||||
path = first ? path : path.replace(/\/$/, '')
|
||||
path = getParentPath(path)
|
||||
|
||||
if (!path) return
|
||||
if (!path) {
|
||||
return
|
||||
}
|
||||
|
||||
get(
|
||||
vm.router.getFile(path + file) + qs,
|
||||
|
|
@ -17,7 +19,7 @@ function loadNested (path, qs, file, next, vm, first) {
|
|||
).then(next, _ => loadNested(path, qs, file, next, vm))
|
||||
}
|
||||
|
||||
export function fetchMixin (proto) {
|
||||
export function fetchMixin(proto) {
|
||||
let last
|
||||
|
||||
const abort = () => last && last.abort && last.abort()
|
||||
|
|
@ -28,27 +30,39 @@ export function fetchMixin (proto) {
|
|||
}
|
||||
|
||||
const get404Path = (path, config) => {
|
||||
const { notFoundPage, ext } = config
|
||||
const {notFoundPage, ext} = config
|
||||
const defaultPath = '_404' + (ext || '.md')
|
||||
let key
|
||||
let path404
|
||||
|
||||
switch (typeof notFoundPage) {
|
||||
case 'boolean':
|
||||
return defaultPath
|
||||
path404 = defaultPath
|
||||
break
|
||||
case 'string':
|
||||
return notFoundPage
|
||||
case 'object':
|
||||
const key = Object
|
||||
.keys(notFoundPage)
|
||||
.sort((a, b) => b.length - a.length)
|
||||
.find((key) => path.match(new RegExp('^' + key)))
|
||||
path404 = notFoundPage
|
||||
break
|
||||
|
||||
return key && notFoundPage[key] || defaultPath
|
||||
case 'object':
|
||||
key = Object.keys(notFoundPage)
|
||||
.sort((a, b) => b.length - a.length)
|
||||
.find(key => path.match(new RegExp('^' + key)))
|
||||
|
||||
path404 = (key && notFoundPage[key]) || defaultPath
|
||||
break
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return path404
|
||||
}
|
||||
|
||||
proto._loadSideAndNav = function (path, qs, loadSidebar, cb) {
|
||||
return () => {
|
||||
if (!loadSidebar) return cb()
|
||||
if (!loadSidebar) {
|
||||
return cb()
|
||||
}
|
||||
|
||||
const fn = result => {
|
||||
this._renderSidebar(result)
|
||||
|
|
@ -61,9 +75,9 @@ export function fetchMixin (proto) {
|
|||
}
|
||||
|
||||
proto._fetch = function (cb = noop) {
|
||||
const { path, query } = this.route
|
||||
const {path, query} = this.route
|
||||
const qs = stringifyQuery(query, ['id'])
|
||||
const { loadNavbar, requestHeaders, loadSidebar } = this.config
|
||||
const {loadNavbar, requestHeaders, loadSidebar} = this.config
|
||||
// Abort last request
|
||||
|
||||
const file = this.router.getFile(path)
|
||||
|
|
@ -73,28 +87,32 @@ export function fetchMixin (proto) {
|
|||
this.isHTML = /\.html$/g.test(file)
|
||||
|
||||
// Load main content
|
||||
req
|
||||
.then(
|
||||
(text, opt) => this._renderMain(text, opt, this._loadSideAndNav(path, qs, loadSidebar, cb)),
|
||||
_ => {
|
||||
this._fetchFallbackPage(file, qs, cb) || this._fetch404(file, qs, cb)
|
||||
}
|
||||
)
|
||||
req.then(
|
||||
(text, opt) =>
|
||||
this._renderMain(
|
||||
text,
|
||||
opt,
|
||||
this._loadSideAndNav(path, qs, loadSidebar, cb)
|
||||
),
|
||||
_ => {
|
||||
this._fetchFallbackPage(file, qs, cb) || this._fetch404(file, qs, cb)
|
||||
}
|
||||
)
|
||||
|
||||
// Load nav
|
||||
loadNavbar &&
|
||||
loadNested(
|
||||
path,
|
||||
qs,
|
||||
loadNavbar,
|
||||
text => this._renderNav(text),
|
||||
this,
|
||||
true
|
||||
)
|
||||
loadNested(
|
||||
path,
|
||||
qs,
|
||||
loadNavbar,
|
||||
text => this._renderNav(text),
|
||||
this,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
proto._fetchCover = function () {
|
||||
const { coverpage, requestHeaders } = this.config
|
||||
const {coverpage, requestHeaders} = this.config
|
||||
const query = this.route.query
|
||||
const root = getParentPath(this.route.path)
|
||||
|
||||
|
|
@ -112,7 +130,7 @@ export function fetchMixin (proto) {
|
|||
path = cover === true ? '_coverpage' : cover
|
||||
}
|
||||
|
||||
const coverOnly = !!path && this.config.onlyCover
|
||||
const coverOnly = Boolean(path) && this.config.onlyCover
|
||||
if (path) {
|
||||
path = this.router.getFile(root + path)
|
||||
this.coverIsHTML = /\.html$/g.test(path)
|
||||
|
|
@ -137,7 +155,7 @@ export function fetchMixin (proto) {
|
|||
if (onlyCover) {
|
||||
done()
|
||||
} else {
|
||||
this._fetch(result => {
|
||||
this._fetch(() => {
|
||||
this.$resetEvents()
|
||||
done()
|
||||
})
|
||||
|
|
@ -145,7 +163,7 @@ export function fetchMixin (proto) {
|
|||
}
|
||||
|
||||
proto._fetchFallbackPage = function (path, qs, cb = noop) {
|
||||
const { requestHeaders, fallbackLanguages, loadSidebar } = this.config
|
||||
const {requestHeaders, fallbackLanguages, loadSidebar} = this.config
|
||||
|
||||
if (!fallbackLanguages) {
|
||||
return false
|
||||
|
|
@ -160,7 +178,12 @@ export function fetchMixin (proto) {
|
|||
const req = request(newPath + qs, true, requestHeaders)
|
||||
|
||||
req.then(
|
||||
(text, opt) => this._renderMain(text, opt, this._loadSideAndNav(path, qs, loadSidebar, cb)),
|
||||
(text, opt) =>
|
||||
this._renderMain(
|
||||
text,
|
||||
opt,
|
||||
this._loadSideAndNav(path, qs, loadSidebar, cb)
|
||||
),
|
||||
() => this._fetch404(path, qs, cb)
|
||||
)
|
||||
|
||||
|
|
@ -175,16 +198,16 @@ export function fetchMixin (proto) {
|
|||
* @private
|
||||
*/
|
||||
proto._fetch404 = function (path, qs, cb = noop) {
|
||||
const { loadSidebar, requestHeaders, notFoundPage } = this.config
|
||||
const {loadSidebar, requestHeaders, notFoundPage} = this.config
|
||||
|
||||
const fnLoadSideAndNav = this._loadSideAndNav(path, qs, loadSidebar, cb)
|
||||
|
||||
if (notFoundPage) {
|
||||
request(get404Path(path, this.config), true, requestHeaders)
|
||||
.then(
|
||||
(text, opt) => this._renderMain(text, opt, fnLoadSideAndNav),
|
||||
() => this._renderMain(null, {}, fnLoadSideAndNav)
|
||||
)
|
||||
const path404 = get404Path(path, this.config)
|
||||
|
||||
request(this.router.getFile(path404), true, requestHeaders).then(
|
||||
(text, opt) => this._renderMain(text, opt, fnLoadSideAndNav),
|
||||
() => this._renderMain(null, {}, fnLoadSideAndNav)
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -193,8 +216,8 @@ export function fetchMixin (proto) {
|
|||
}
|
||||
}
|
||||
|
||||
export function initFetch (vm) {
|
||||
const { loadSidebar } = vm.config
|
||||
export function initFetch(vm) {
|
||||
const {loadSidebar} = vm.config
|
||||
|
||||
// Server-Side Rendering
|
||||
if (vm.rendered) {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import * as util from './util'
|
||||
import * as dom from './util/dom'
|
||||
import { Compiler } from './render/compiler'
|
||||
import { slugify } from './render/slugify'
|
||||
import { get } from './fetch/ajax'
|
||||
import {Compiler} from './render/compiler'
|
||||
import {slugify} from './render/slugify'
|
||||
import {get} from './fetch/ajax'
|
||||
import marked from 'marked'
|
||||
import prism from 'prismjs'
|
||||
|
||||
export default function () {
|
||||
window.Docsify = { util, dom, get, slugify }
|
||||
window.Docsify = {util, dom, get, slugify}
|
||||
window.DocsifyCompiler = Compiler
|
||||
window.marked = marked
|
||||
window.Prism = prism
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { initMixin } from './init'
|
||||
import { routerMixin } from './router'
|
||||
import { renderMixin } from './render'
|
||||
import { fetchMixin } from './fetch'
|
||||
import { eventMixin } from './event'
|
||||
import {initMixin} from './init'
|
||||
import {routerMixin} from './router'
|
||||
import {renderMixin} from './render'
|
||||
import {fetchMixin} from './fetch'
|
||||
import {eventMixin} from './event'
|
||||
import initGlobalAPI from './global-api'
|
||||
|
||||
/**
|
||||
* Fork https://github.com/bendrucker/document-ready/blob/master/index.js
|
||||
*/
|
||||
function ready (callback) {
|
||||
function ready(callback) {
|
||||
const state = document.readyState
|
||||
|
||||
if (state === 'complete' || state === 'interactive') {
|
||||
|
|
@ -18,7 +18,7 @@ function ready (callback) {
|
|||
document.addEventListener('DOMContentLoaded', callback)
|
||||
}
|
||||
|
||||
function Docsify () {
|
||||
function Docsify() {
|
||||
this._init()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import config from '../config'
|
||||
import { initLifecycle, callHook } from './lifecycle'
|
||||
import { initRender } from '../render'
|
||||
import { initRouter } from '../router'
|
||||
import { initEvent } from '../event'
|
||||
import { initFetch } from '../fetch'
|
||||
import { isFn } from '../util/core'
|
||||
import {initLifecycle, callHook} from './lifecycle'
|
||||
import {initRender} from '../render'
|
||||
import {initRouter} from '../router'
|
||||
import {initEvent} from '../event'
|
||||
import {initFetch} from '../fetch'
|
||||
import {isFn} from '../util/core'
|
||||
|
||||
export function initMixin (proto) {
|
||||
export function initMixin(proto) {
|
||||
proto._init = function () {
|
||||
const vm = this
|
||||
vm.config = config || {}
|
||||
|
|
@ -22,6 +22,6 @@ export function initMixin (proto) {
|
|||
}
|
||||
}
|
||||
|
||||
function initPlugin (vm) {
|
||||
function initPlugin(vm) {
|
||||
[].concat(vm.config.plugins).forEach(fn => isFn(fn) && fn(vm._lifecycle, vm))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { noop } from '../util/core'
|
||||
import {noop} from '../util/core'
|
||||
|
||||
export function initLifecycle (vm) {
|
||||
export function initLifecycle(vm) {
|
||||
const hooks = [
|
||||
'init',
|
||||
'mounted',
|
||||
|
|
@ -18,28 +18,26 @@ export function initLifecycle (vm) {
|
|||
})
|
||||
}
|
||||
|
||||
export function callHook (vm, hook, data, next = noop) {
|
||||
export function callHook(vm, hook, data, next = noop) {
|
||||
const queue = vm._hooks[hook]
|
||||
|
||||
const step = function (index) {
|
||||
const hook = queue[index]
|
||||
if (index >= queue.length) {
|
||||
next(data)
|
||||
} else {
|
||||
if (typeof hook === 'function') {
|
||||
if (hook.length === 2) {
|
||||
hook(data, result => {
|
||||
data = result
|
||||
step(index + 1)
|
||||
})
|
||||
} else {
|
||||
const result = hook(data)
|
||||
data = result !== undefined ? result : data
|
||||
} else if (typeof hook === 'function') {
|
||||
if (hook.length === 2) {
|
||||
hook(data, result => {
|
||||
data = result
|
||||
step(index + 1)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
const result = hook(data)
|
||||
data = result === undefined ? data : result
|
||||
step(index + 1)
|
||||
}
|
||||
} else {
|
||||
step(index + 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
import marked from 'marked'
|
||||
import Prism from 'prismjs'
|
||||
import { helper as helperTpl, tree as treeTpl } from './tpl'
|
||||
import { genTree } from './gen-tree'
|
||||
import { slugify } from './slugify'
|
||||
import { emojify } from './emojify'
|
||||
import { isAbsolutePath, getPath } from '../router/util'
|
||||
import { isFn, merge, cached, isPrimitive } from '../util/core'
|
||||
import {helper as helperTpl, tree as treeTpl} from './tpl'
|
||||
import {genTree} from './gen-tree'
|
||||
import {slugify} from './slugify'
|
||||
import {emojify} from './emojify'
|
||||
import {isAbsolutePath, getPath} from '../router/util'
|
||||
import {isFn, merge, cached, isPrimitive} from '../util/core'
|
||||
|
||||
const cachedLinks = {}
|
||||
|
||||
export function getAndRemoveConfig (str = '') {
|
||||
export function getAndRemoveConfig(str = '') {
|
||||
const config = {}
|
||||
|
||||
if (str) {
|
||||
|
|
@ -21,35 +21,37 @@ export function getAndRemoveConfig (str = '') {
|
|||
.trim()
|
||||
}
|
||||
|
||||
return { str, config }
|
||||
return {str, config}
|
||||
}
|
||||
|
||||
const compileMedia = {
|
||||
markdown (url) {
|
||||
markdown(url) {
|
||||
return {
|
||||
url
|
||||
}
|
||||
},
|
||||
iframe (url, title) {
|
||||
iframe(url, title) {
|
||||
return {
|
||||
code: `<iframe src="${url}" ${title || 'width=100% height=400'}></iframe>`
|
||||
}
|
||||
},
|
||||
video (url, title) {
|
||||
video(url, title) {
|
||||
return {
|
||||
code: `<video src="${url}" ${title || 'controls'}>Not Support</video>`
|
||||
}
|
||||
},
|
||||
audio (url, title) {
|
||||
audio(url, title) {
|
||||
return {
|
||||
code: `<audio src="${url}" ${title || 'controls'}>Not Support</audio>`
|
||||
}
|
||||
},
|
||||
code (url, title) {
|
||||
code(url, title) {
|
||||
let lang = url.match(/\.(\w+)$/)
|
||||
|
||||
lang = title || (lang && lang[1])
|
||||
if (lang === 'md') lang = 'markdown'
|
||||
if (lang === 'md') {
|
||||
lang = 'markdown'
|
||||
}
|
||||
|
||||
return {
|
||||
url,
|
||||
|
|
@ -59,7 +61,7 @@ const compileMedia = {
|
|||
}
|
||||
|
||||
export class Compiler {
|
||||
constructor (config, router) {
|
||||
constructor(config, router) {
|
||||
this.config = config
|
||||
this.router = router
|
||||
this.cacheTree = {}
|
||||
|
|
@ -86,7 +88,9 @@ export class Compiler {
|
|||
this.compile = cached(text => {
|
||||
let html = ''
|
||||
|
||||
if (!text) return text
|
||||
if (!text) {
|
||||
return text
|
||||
}
|
||||
|
||||
if (isPrimitive(text)) {
|
||||
html = compile(text)
|
||||
|
|
@ -101,8 +105,8 @@ export class Compiler {
|
|||
})
|
||||
}
|
||||
|
||||
compileEmbed (href, title) {
|
||||
const { str, config } = getAndRemoveConfig(title)
|
||||
compileEmbed(href, title) {
|
||||
const {str, config} = getAndRemoveConfig(title)
|
||||
let embed
|
||||
title = str
|
||||
|
||||
|
|
@ -134,7 +138,7 @@ export class Compiler {
|
|||
}
|
||||
}
|
||||
|
||||
_matchNotCompileLink (link) {
|
||||
_matchNotCompileLink(link) {
|
||||
const links = this.config.noCompileLinks || []
|
||||
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
|
|
@ -147,18 +151,18 @@ export class Compiler {
|
|||
}
|
||||
}
|
||||
|
||||
_initRenderer () {
|
||||
_initRenderer() {
|
||||
const renderer = new marked.Renderer()
|
||||
const { linkTarget, router, contentBase } = this
|
||||
const {linkTarget, router, contentBase} = this
|
||||
const _self = this
|
||||
const origin = {}
|
||||
|
||||
/**
|
||||
* render anchor tag
|
||||
* Render anchor tag
|
||||
* @link https://github.com/chjj/marked#overriding-renderer-methods
|
||||
*/
|
||||
origin.heading = renderer.heading = function (text, level) {
|
||||
const nextToc = { level, title: text }
|
||||
const nextToc = {level, title: text}
|
||||
|
||||
if (/{docsify-ignore}/g.test(text)) {
|
||||
text = text.replace('{docsify-ignore}', '')
|
||||
|
|
@ -173,13 +177,13 @@ export class Compiler {
|
|||
}
|
||||
|
||||
const slug = slugify(text)
|
||||
const url = router.toURL(router.getCurrentPath(), { id: slug })
|
||||
const url = router.toURL(router.getCurrentPath(), {id: slug})
|
||||
nextToc.slug = url
|
||||
_self.toc.push(nextToc)
|
||||
|
||||
return `<h${level} id="${slug}"><a href="${url}" data-id="${slug}" class="anchor"><span>${text}</span></a></h${level}>`
|
||||
}
|
||||
// highlight code
|
||||
// Highlight code
|
||||
origin.code = renderer.code = function (code, lang = '') {
|
||||
code = code.replace(/@DOCSIFY_QM@/g, '`')
|
||||
const hl = Prism.highlight(
|
||||
|
|
@ -192,7 +196,7 @@ export class Compiler {
|
|||
origin.link = renderer.link = function (href, title = '', text) {
|
||||
let attrs = ''
|
||||
|
||||
const { str, config } = getAndRemoveConfig(title)
|
||||
const {str, config} = getAndRemoveConfig(title)
|
||||
title = str
|
||||
|
||||
if (
|
||||
|
|
@ -200,7 +204,9 @@ export class Compiler {
|
|||
!_self._matchNotCompileLink(href) &&
|
||||
!config.ignore
|
||||
) {
|
||||
if (href === _self.config.homepage) href = 'README'
|
||||
if (href === _self.config.homepage) {
|
||||
href = 'README'
|
||||
}
|
||||
href = router.toURL(href, null, router.getCurrentPath())
|
||||
} else {
|
||||
attrs += ` target="${linkTarget}"`
|
||||
|
|
@ -222,18 +228,21 @@ export class Compiler {
|
|||
return `<a href="${href}"${attrs}>${text}</a>`
|
||||
}
|
||||
origin.paragraph = renderer.paragraph = function (text) {
|
||||
let result
|
||||
if (/^!>/.test(text)) {
|
||||
return helperTpl('tip', text)
|
||||
result = helperTpl('tip', text)
|
||||
} else if (/^\?>/.test(text)) {
|
||||
return helperTpl('warn', text)
|
||||
result = helperTpl('warn', text)
|
||||
} else {
|
||||
result = `<p>${text}</p>`
|
||||
}
|
||||
return `<p>${text}</p>`
|
||||
return result
|
||||
}
|
||||
origin.image = renderer.image = function (href, title, text) {
|
||||
let url = href
|
||||
let attrs = ''
|
||||
|
||||
const { str, config } = getAndRemoveConfig(title)
|
||||
const {str, config} = getAndRemoveConfig(title)
|
||||
title = str
|
||||
|
||||
if (config['no-zoom']) {
|
||||
|
|
@ -271,7 +280,7 @@ export class Compiler {
|
|||
/**
|
||||
* Compile sidebar
|
||||
*/
|
||||
sidebar (text, level) {
|
||||
sidebar(text, level) {
|
||||
const currentPath = this.router.getCurrentPath()
|
||||
let html = ''
|
||||
|
||||
|
|
@ -290,13 +299,13 @@ export class Compiler {
|
|||
/**
|
||||
* Compile sub sidebar
|
||||
*/
|
||||
subSidebar (level) {
|
||||
subSidebar(level) {
|
||||
if (!level) {
|
||||
this.toc = []
|
||||
return
|
||||
}
|
||||
const currentPath = this.router.getCurrentPath()
|
||||
const { cacheTree, toc } = this
|
||||
const {cacheTree, toc} = this
|
||||
|
||||
toc[0] && toc[0].ignoreAllSubs && toc.splice(0)
|
||||
toc[0] && toc[0].level === 1 && toc.shift()
|
||||
|
|
@ -312,14 +321,14 @@ export class Compiler {
|
|||
return treeTpl(tree, '<ul class="app-sub-sidebar">')
|
||||
}
|
||||
|
||||
article (text) {
|
||||
article(text) {
|
||||
return this.compile(text)
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile cover page
|
||||
*/
|
||||
cover (text) {
|
||||
cover(text) {
|
||||
const cacheToc = this.toc.slice()
|
||||
const html = this.compile(text)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { get } from '../fetch/ajax'
|
||||
import { merge } from '../util/core'
|
||||
import {get} from '../fetch/ajax'
|
||||
import {merge} from '../util/core'
|
||||
|
||||
const cached = {}
|
||||
|
||||
function walkFetchEmbed ({ step = 0, embedTokens, compile, fetch }, cb) {
|
||||
function walkFetchEmbed({step = 0, embedTokens, compile, fetch}, cb) {
|
||||
const token = embedTokens[step]
|
||||
|
||||
if (!token) {
|
||||
|
|
@ -25,8 +25,8 @@ function walkFetchEmbed ({ step = 0, embedTokens, compile, fetch }, cb) {
|
|||
)
|
||||
}
|
||||
}
|
||||
cb({ token, embedToken })
|
||||
walkFetchEmbed({ step: ++step, compile, embedTokens, fetch }, cb)
|
||||
cb({token, embedToken})
|
||||
walkFetchEmbed({step: ++step, compile, embedTokens, fetch}, cb)
|
||||
}
|
||||
|
||||
if (process.env.SSR) {
|
||||
|
|
@ -36,7 +36,7 @@ function walkFetchEmbed ({ step = 0, embedTokens, compile, fetch }, cb) {
|
|||
}
|
||||
}
|
||||
|
||||
export function prerenderEmbed ({ compiler, raw = '', fetch }, done) {
|
||||
export function prerenderEmbed({compiler, raw = '', fetch}, done) {
|
||||
let hit
|
||||
if ((hit = cached[raw])) {
|
||||
return done(hit)
|
||||
|
|
@ -72,7 +72,7 @@ export function prerenderEmbed ({ compiler, raw = '', fetch }, done) {
|
|||
})
|
||||
|
||||
let moveIndex = 0
|
||||
walkFetchEmbed({ compile, embedTokens, fetch }, ({ embedToken, token }) => {
|
||||
walkFetchEmbed({compile, embedTokens, fetch}, ({embedToken, token}) => {
|
||||
if (token) {
|
||||
const index = token.index + moveIndex
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { inBrowser } from '../util/env'
|
||||
import {inBrowser} from '../util/env'
|
||||
|
||||
function replace (m, $1) {
|
||||
function replace(m, $1) {
|
||||
return '<img class="emoji" src="https://assets-cdn.github.com/images/icons/emoji/' + $1 + '.png" alt="' + $1 + '" />'
|
||||
}
|
||||
|
||||
export function emojify (text) {
|
||||
export function emojify(text) {
|
||||
return text
|
||||
.replace(/<(pre|template|code)[^>]*?>[\s\S]+?<\/(pre|template|code)>/g, m => m.replace(/:/g, '__colon__'))
|
||||
.replace(/:(\w+?):/ig, (inBrowser && window.emojify) || replace)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
/**
|
||||
* gen toc tree
|
||||
* Gen toc tree
|
||||
* @link https://github.com/killercup/grock/blob/5280ae63e16c5739e9233d9009bc235ed7d79a50/styles/solarized/assets/js/behavior.coffee#L54-L81
|
||||
* @param {Array} toc
|
||||
* @param {Number} maxLevel
|
||||
* @return {Array}
|
||||
*/
|
||||
export function genTree (toc, maxLevel) {
|
||||
export function genTree(toc, maxLevel) {
|
||||
const headlines = []
|
||||
const last = {}
|
||||
|
||||
|
|
@ -13,7 +13,9 @@ export function genTree (toc, maxLevel) {
|
|||
const level = headline.level || 1
|
||||
const len = level - 1
|
||||
|
||||
if (level > maxLevel) return
|
||||
if (level > maxLevel) {
|
||||
return
|
||||
}
|
||||
if (last[len]) {
|
||||
last[len].children = (last[len].children || []).concat(headline)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2,38 +2,42 @@ import * as dom from '../util/dom'
|
|||
import * as tpl from './tpl'
|
||||
import cssVars from '../util/polyfill/css-vars'
|
||||
import tinydate from 'tinydate'
|
||||
import { callHook } from '../init/lifecycle'
|
||||
import { Compiler } from './compiler'
|
||||
import { getAndActive, sticky } from '../event/sidebar'
|
||||
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'
|
||||
import {callHook} from '../init/lifecycle'
|
||||
import {Compiler} from './compiler'
|
||||
import {getAndActive, sticky} from '../event/sidebar'
|
||||
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 () {
|
||||
function executeScript() {
|
||||
const script = dom
|
||||
.findAll('.markdown-section>script')
|
||||
.filter(s => !/template/.test(s.type))[0]
|
||||
if (!script) return false
|
||||
if (!script) {
|
||||
return false
|
||||
}
|
||||
const code = script.innerText.trim()
|
||||
if (!code) return false
|
||||
if (!code) {
|
||||
return false
|
||||
}
|
||||
|
||||
setTimeout(_ => {
|
||||
window.__EXECUTE_RESULT__ = new Function(code)()
|
||||
}, 0)
|
||||
}
|
||||
|
||||
function formatUpdated (html, updated, fn) {
|
||||
function formatUpdated(html, updated, fn) {
|
||||
updated =
|
||||
typeof fn === 'function'
|
||||
? fn(updated)
|
||||
: typeof fn === 'string' ? tinydate(fn)(new Date(updated)) : updated
|
||||
typeof fn === 'function' ?
|
||||
fn(updated) :
|
||||
typeof fn === 'string' ? tinydate(fn)(new Date(updated)) : updated
|
||||
|
||||
return html.replace(/{docsify-updated}/g, updated)
|
||||
}
|
||||
|
||||
function renderMain (html) {
|
||||
function renderMain(html) {
|
||||
if (!html) {
|
||||
html = '<h1>404 - Not found</h1>'
|
||||
}
|
||||
|
|
@ -42,7 +46,7 @@ function renderMain (html) {
|
|||
// Render sidebar with the TOC
|
||||
!this.config.loadSidebar && this._renderSidebar()
|
||||
|
||||
// execute script
|
||||
// Execute script
|
||||
if (
|
||||
this.config.executeScript !== false &&
|
||||
typeof window.Vue !== 'undefined' &&
|
||||
|
|
@ -58,12 +62,14 @@ function renderMain (html) {
|
|||
}
|
||||
}
|
||||
|
||||
function renderNameLink (vm) {
|
||||
function renderNameLink(vm) {
|
||||
const el = dom.getNode('.app-name-link')
|
||||
const nameLink = vm.config.nameLink
|
||||
const path = vm.route.path
|
||||
|
||||
if (!el) return
|
||||
if (!el) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isPrimitive(vm.config.nameLink)) {
|
||||
el.setAttribute('href', nameLink)
|
||||
|
|
@ -74,14 +80,16 @@ function renderNameLink (vm) {
|
|||
}
|
||||
}
|
||||
|
||||
export function renderMixin (proto) {
|
||||
export function renderMixin(proto) {
|
||||
proto._renderTo = function (el, content, replace) {
|
||||
const node = dom.getNode(el)
|
||||
if (node) node[replace ? 'outerHTML' : 'innerHTML'] = content
|
||||
if (node) {
|
||||
node[replace ? 'outerHTML' : 'innerHTML'] = content
|
||||
}
|
||||
}
|
||||
|
||||
proto._renderSidebar = function (text) {
|
||||
const { maxLevel, subMaxLevel, loadSidebar } = this.config
|
||||
const {maxLevel, subMaxLevel, loadSidebar} = this.config
|
||||
|
||||
this._renderTo('.sidebar-nav', this.compiler.sidebar(text, maxLevel))
|
||||
const activeEl = getAndActive(this.router, '.sidebar-nav', true, true)
|
||||
|
|
@ -89,15 +97,15 @@ export function renderMixin (proto) {
|
|||
activeEl.parentNode.innerHTML +=
|
||||
this.compiler.subSidebar(subMaxLevel) || ''
|
||||
} else {
|
||||
// reset toc
|
||||
// Reset toc
|
||||
this.compiler.subSidebar()
|
||||
}
|
||||
// bind event
|
||||
// Bind event
|
||||
this._bindEventOnRendered(activeEl)
|
||||
}
|
||||
|
||||
proto._bindEventOnRendered = function (activeEl) {
|
||||
const { autoHeader, auto2top } = this.config
|
||||
const {autoHeader, auto2top} = this.config
|
||||
|
||||
scrollActiveSidebar(this.router)
|
||||
|
||||
|
|
@ -192,18 +200,18 @@ export function renderMixin (proto) {
|
|||
}
|
||||
|
||||
proto._updateRender = function () {
|
||||
// render name link
|
||||
// Render name link
|
||||
renderNameLink(this)
|
||||
}
|
||||
}
|
||||
|
||||
export function initRender (vm) {
|
||||
export function initRender(vm) {
|
||||
const config = vm.config
|
||||
|
||||
// Init markdown compiler
|
||||
vm.compiler = new Compiler(config, vm.router)
|
||||
if (inBrowser) {
|
||||
window['__current_docsify_compiler__'] = vm.compiler
|
||||
window.__current_docsify_compiler__ = vm.compiler
|
||||
}
|
||||
|
||||
const id = config.el || '#app'
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ let timeId
|
|||
/**
|
||||
* Init progress component
|
||||
*/
|
||||
function init () {
|
||||
function init() {
|
||||
const div = dom.create('div')
|
||||
|
||||
div.classList.add('progress')
|
||||
|
|
@ -16,7 +16,7 @@ function init () {
|
|||
/**
|
||||
* Render progress bar
|
||||
*/
|
||||
export default function ({ loaded, total, step }) {
|
||||
export default function ({loaded, total, step}) {
|
||||
let num
|
||||
|
||||
!barEl && init()
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
let cache = {}
|
||||
const re = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,.\/:;<=>?@\[\]^`{|}~]/g
|
||||
import {hasOwn} from '../util/core'
|
||||
|
||||
function lower (string) {
|
||||
let cache = {}
|
||||
const re = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g
|
||||
|
||||
function lower(string) {
|
||||
return string.toLowerCase()
|
||||
}
|
||||
|
||||
export function slugify (str) {
|
||||
if (typeof str !== 'string') return ''
|
||||
export function slugify(str) {
|
||||
if (typeof str !== 'string') {
|
||||
return ''
|
||||
}
|
||||
|
||||
let slug = str
|
||||
.trim()
|
||||
|
|
@ -18,7 +22,7 @@ export function slugify (str) {
|
|||
.replace(/^(\d)/, '_$1')
|
||||
let count = cache[slug]
|
||||
|
||||
count = cache.hasOwnProperty(slug) ? count + 1 : 0
|
||||
count = hasOwn.call(cache, slug) ? count + 1 : 0
|
||||
cache[slug] = count
|
||||
|
||||
if (count) {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
import { isMobile } from '../util/env'
|
||||
import {isMobile} from '../util/env'
|
||||
/**
|
||||
* Render github corner
|
||||
* @param {Object} data
|
||||
* @return {String}
|
||||
*/
|
||||
export function corner (data) {
|
||||
if (!data) return ''
|
||||
if (!/\/\//.test(data)) data = 'https://github.com/' + data
|
||||
export function corner(data) {
|
||||
if (!data) {
|
||||
return ''
|
||||
}
|
||||
if (!/\/\//.test(data)) {
|
||||
data = 'https://github.com/' + data
|
||||
}
|
||||
data = data.replace(/^git\+/, '')
|
||||
|
||||
return (
|
||||
|
|
@ -23,7 +27,7 @@ export function corner (data) {
|
|||
/**
|
||||
* Render main content
|
||||
*/
|
||||
export function main (config) {
|
||||
export function main(config) {
|
||||
const aside =
|
||||
'<button class="sidebar-toggle">' +
|
||||
'<div class="sidebar-toggle-button">' +
|
||||
|
|
@ -31,9 +35,9 @@ export function main (config) {
|
|||
'</div>' +
|
||||
'</button>' +
|
||||
'<aside class="sidebar">' +
|
||||
(config.name
|
||||
? `<h1><a class="app-name-link" data-nosearch>${config.name}</a></h1>`
|
||||
: '') +
|
||||
(config.name ?
|
||||
`<h1><a class="app-name-link" data-nosearch>${config.name}</a></h1>` :
|
||||
'') +
|
||||
'<div class="sidebar-nav"><!--sidebar--></div>' +
|
||||
'</aside>'
|
||||
|
||||
|
|
@ -49,7 +53,7 @@ export function main (config) {
|
|||
/**
|
||||
* Cover Page
|
||||
*/
|
||||
export function cover () {
|
||||
export function cover() {
|
||||
const SL = ', 100%, 85%'
|
||||
const bgc =
|
||||
'linear-gradient(to left bottom, ' +
|
||||
|
|
@ -70,8 +74,10 @@ export function cover () {
|
|||
* @param {String} tpl
|
||||
* @return {String}
|
||||
*/
|
||||
export function tree (toc, tpl = '') {
|
||||
if (!toc || !toc.length) return ''
|
||||
export function tree(toc, tpl = '') {
|
||||
if (!toc || !toc.length) {
|
||||
return ''
|
||||
}
|
||||
|
||||
toc.forEach(node => {
|
||||
tpl += `<li><a class="section-link" href="${node.slug}">${
|
||||
|
|
@ -85,10 +91,10 @@ export function tree (toc, tpl = '') {
|
|||
return tpl
|
||||
}
|
||||
|
||||
export function helper (className, content) {
|
||||
export function helper(className, content) {
|
||||
return `<p class="${className}">${content.slice(5).trim()}</p>`
|
||||
}
|
||||
|
||||
export function theme (color) {
|
||||
export function theme(color) {
|
||||
return `<style>:root{--theme-color: ${color};}</style>`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { History } from './base'
|
||||
import { parseQuery } from '../util'
|
||||
import {History} from './base'
|
||||
import {parseQuery} from '../util'
|
||||
|
||||
export class AbstractHistory extends History {
|
||||
constructor (config) {
|
||||
constructor(config) {
|
||||
super(config)
|
||||
this.mode = 'abstract'
|
||||
}
|
||||
|
||||
parse (path) {
|
||||
parse(path) {
|
||||
let query = ''
|
||||
|
||||
const queryIndex = path.indexOf('?')
|
||||
|
|
|
|||
|
|
@ -5,40 +5,40 @@ import {
|
|||
cleanPath,
|
||||
replaceSlug
|
||||
} from '../util'
|
||||
import { noop, merge } from '../../util/core'
|
||||
import {noop, merge} from '../../util/core'
|
||||
|
||||
const cached = {}
|
||||
|
||||
function getAlias (path, alias, last) {
|
||||
function getAlias(path, alias, last) {
|
||||
const match = Object.keys(alias).filter(key => {
|
||||
const re = cached[key] || (cached[key] = new RegExp(`^${key}$`))
|
||||
return re.test(path) && path !== last
|
||||
})[0]
|
||||
|
||||
return match
|
||||
? getAlias(path.replace(cached[match], alias[match]), alias, path)
|
||||
: path
|
||||
return match ?
|
||||
getAlias(path.replace(cached[match], alias[match]), alias, path) :
|
||||
path
|
||||
}
|
||||
|
||||
function getFileName (path, ext) {
|
||||
return new RegExp(`\\.(${ext.replace(/^\./, '')}|html)$`, 'g').test(path)
|
||||
? path
|
||||
: /\/$/g.test(path) ? `${path}README${ext}` : `${path}${ext}`
|
||||
function getFileName(path, ext) {
|
||||
return new RegExp(`\\.(${ext.replace(/^\./, '')}|html)$`, 'g').test(path) ?
|
||||
path :
|
||||
/\/$/g.test(path) ? `${path}README${ext}` : `${path}${ext}`
|
||||
}
|
||||
|
||||
export class History {
|
||||
constructor (config) {
|
||||
constructor(config) {
|
||||
this.config = config
|
||||
}
|
||||
|
||||
getBasePath () {
|
||||
getBasePath() {
|
||||
return this.config.basePath
|
||||
}
|
||||
|
||||
getFile (path = this.getCurrentPath(), isRelative) {
|
||||
const { config } = this
|
||||
getFile(path = this.getCurrentPath(), isRelative) {
|
||||
const {config} = this
|
||||
const base = this.getBasePath()
|
||||
const ext = typeof config.ext !== 'string' ? '.md' : config.ext
|
||||
const ext = typeof config.ext === 'string' ? config.ext : '.md'
|
||||
|
||||
path = config.alias ? getAlias(path, config.alias) : path
|
||||
path = getFileName(path, ext)
|
||||
|
|
@ -52,17 +52,17 @@ export class History {
|
|||
return path
|
||||
}
|
||||
|
||||
onchange (cb = noop) {
|
||||
onchange(cb = noop) {
|
||||
cb()
|
||||
}
|
||||
|
||||
getCurrentPath () {}
|
||||
getCurrentPath() {}
|
||||
|
||||
normalize () {}
|
||||
normalize() {}
|
||||
|
||||
parse () {}
|
||||
parse() {}
|
||||
|
||||
toURL (path, params, currentRoute) {
|
||||
toURL(path, params, currentRoute) {
|
||||
const local = currentRoute && path[0] === '#'
|
||||
const route = this.parse(replaceSlug(path))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
import { History } from './base'
|
||||
import { noop } from '../../util/core'
|
||||
import { on } from '../../util/dom'
|
||||
import { parseQuery, cleanPath, replaceSlug } from '../util'
|
||||
import {History} from './base'
|
||||
import {noop} from '../../util/core'
|
||||
import {on} from '../../util/dom'
|
||||
import {parseQuery, cleanPath, replaceSlug} from '../util'
|
||||
|
||||
function replaceHash (path) {
|
||||
function replaceHash(path) {
|
||||
const i = location.href.indexOf('#')
|
||||
location.replace(location.href.slice(0, i >= 0 ? i : 0) + '#' + path)
|
||||
}
|
||||
|
||||
export class HashHistory extends History {
|
||||
constructor (config) {
|
||||
constructor(config) {
|
||||
super(config)
|
||||
this.mode = 'hash'
|
||||
}
|
||||
|
||||
getBasePath () {
|
||||
getBasePath() {
|
||||
const path = window.location.pathname || ''
|
||||
const base = this.config.basePath
|
||||
|
||||
return /^(\/|https?:)/g.test(base) ? base : cleanPath(path + '/' + base)
|
||||
}
|
||||
|
||||
getCurrentPath () {
|
||||
getCurrentPath() {
|
||||
// We can't use location.hash here because it's not
|
||||
// consistent across browsers - Firefox will pre-decode it!
|
||||
const href = location.href
|
||||
|
|
@ -29,16 +29,18 @@ export class HashHistory extends History {
|
|||
return index === -1 ? '' : href.slice(index + 1)
|
||||
}
|
||||
|
||||
onchange (cb = noop) {
|
||||
onchange(cb = noop) {
|
||||
on('hashchange', cb)
|
||||
}
|
||||
|
||||
normalize () {
|
||||
normalize() {
|
||||
let path = this.getCurrentPath()
|
||||
|
||||
path = replaceSlug(path)
|
||||
|
||||
if (path.charAt(0) === '/') return replaceHash(path)
|
||||
if (path.charAt(0) === '/') {
|
||||
return replaceHash(path)
|
||||
}
|
||||
replaceHash('/' + path)
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +49,7 @@ export class HashHistory extends History {
|
|||
* @param {string} [path=location.herf]
|
||||
* @return {object} { path, query }
|
||||
*/
|
||||
parse (path = location.href) {
|
||||
parse(path = location.href) {
|
||||
let query = ''
|
||||
|
||||
const hashIndex = path.indexOf('#')
|
||||
|
|
@ -68,7 +70,7 @@ export class HashHistory extends History {
|
|||
}
|
||||
}
|
||||
|
||||
toURL (path, params, currentRoute) {
|
||||
toURL(path, params, currentRoute) {
|
||||
return '#' + super.toURL(path, params, currentRoute)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
import { History } from './base'
|
||||
import { noop } from '../../util/core'
|
||||
import { on } from '../../util/dom'
|
||||
import { parseQuery, getPath } from '../util'
|
||||
import {History} from './base'
|
||||
import {noop} from '../../util/core'
|
||||
import {on} from '../../util/dom'
|
||||
import {parseQuery, getPath} from '../util'
|
||||
|
||||
export class HTML5History extends History {
|
||||
constructor (config) {
|
||||
constructor(config) {
|
||||
super(config)
|
||||
this.mode = 'history'
|
||||
}
|
||||
|
||||
getCurrentPath () {
|
||||
getCurrentPath() {
|
||||
const base = this.getBasePath()
|
||||
let path = window.location.pathname
|
||||
|
||||
|
|
@ -20,14 +20,14 @@ export class HTML5History extends History {
|
|||
return (path || '/') + window.location.search + window.location.hash
|
||||
}
|
||||
|
||||
onchange (cb = noop) {
|
||||
onchange(cb = noop) {
|
||||
on('click', e => {
|
||||
const el = e.target.tagName === 'A' ? e.target : e.target.parentNode
|
||||
|
||||
if (el.tagName === 'A' && !/_blank/.test(el.target)) {
|
||||
e.preventDefault()
|
||||
const url = el.href
|
||||
window.history.pushState({ key: url }, '', url)
|
||||
window.history.pushState({key: url}, '', url)
|
||||
cb()
|
||||
}
|
||||
})
|
||||
|
|
@ -40,7 +40,7 @@ export class HTML5History extends History {
|
|||
* @param {string} [path=location.href]
|
||||
* @return {object} { path, query }
|
||||
*/
|
||||
parse (path = location.href) {
|
||||
parse(path = location.href) {
|
||||
let query = ''
|
||||
|
||||
const queryIndex = path.indexOf('?')
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
import { HashHistory } from './history/hash'
|
||||
import { HTML5History } from './history/html5'
|
||||
import { supportsPushState } from '../util/env'
|
||||
import {HashHistory} from './history/hash'
|
||||
import {HTML5History} from './history/html5'
|
||||
import {supportsPushState} from '../util/env'
|
||||
import * as dom from '../util/dom'
|
||||
|
||||
export function routerMixin (proto) {
|
||||
export function routerMixin(proto) {
|
||||
proto.route = {}
|
||||
}
|
||||
|
||||
let lastRoute = {}
|
||||
|
||||
function updateRender (vm) {
|
||||
function updateRender(vm) {
|
||||
vm.router.normalize()
|
||||
vm.route = vm.router.parse()
|
||||
dom.body.setAttribute('data-page', vm.route.file)
|
||||
}
|
||||
|
||||
export function initRouter (vm) {
|
||||
export function initRouter(vm) {
|
||||
const config = vm.config
|
||||
const mode = config.routerMode || 'hash'
|
||||
let router
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { cached } from '../util/core'
|
||||
import {cached} from '../util/core'
|
||||
|
||||
const decode = decodeURIComponent
|
||||
const encode = encodeURIComponent
|
||||
|
||||
export function parseQuery (query) {
|
||||
export function parseQuery(query) {
|
||||
const res = {}
|
||||
|
||||
query = query.trim().replace(/^(\?|#|&)/, '')
|
||||
|
|
@ -22,39 +22,41 @@ export function parseQuery (query) {
|
|||
return res
|
||||
}
|
||||
|
||||
export function stringifyQuery (obj, ignores = []) {
|
||||
export function stringifyQuery(obj, ignores = []) {
|
||||
const qs = []
|
||||
|
||||
for (const key in obj) {
|
||||
if (ignores.indexOf(key) > -1) continue
|
||||
if (ignores.indexOf(key) > -1) {
|
||||
continue
|
||||
}
|
||||
qs.push(
|
||||
obj[key]
|
||||
? `${encode(key)}=${encode(obj[key])}`.toLowerCase()
|
||||
: encode(key)
|
||||
obj[key] ?
|
||||
`${encode(key)}=${encode(obj[key])}`.toLowerCase() :
|
||||
encode(key)
|
||||
)
|
||||
}
|
||||
|
||||
return qs.length ? `?${qs.join('&')}` : ''
|
||||
}
|
||||
|
||||
export function getPath (...args) {
|
||||
return cleanPath(args.join('/'))
|
||||
}
|
||||
|
||||
export const isAbsolutePath = cached(path => {
|
||||
return /(:|(\/{2}))/g.test(path)
|
||||
})
|
||||
|
||||
export const getParentPath = cached(path => {
|
||||
return /\/$/g.test(path)
|
||||
? path
|
||||
: (path = path.match(/(\S*\/)[^\/]+$/)) ? path[1] : ''
|
||||
return /\/$/g.test(path) ?
|
||||
path :
|
||||
(path = path.match(/(\S*\/)[^/]+$/)) ? path[1] : ''
|
||||
})
|
||||
|
||||
export const cleanPath = cached(path => {
|
||||
return path.replace(/^\/+/, '/').replace(/([^:])\/{2,}/g, '$1/')
|
||||
})
|
||||
|
||||
export function getPath(...args) {
|
||||
return cleanPath(args.join('/'))
|
||||
}
|
||||
|
||||
export const replaceSlug = cached(path => {
|
||||
return path.replace('#', '?id=')
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
/**
|
||||
* Create a cached version of a pure function.
|
||||
*/
|
||||
export function cached (fn) {
|
||||
export function cached(fn) {
|
||||
const cache = Object.create(null)
|
||||
return function cachedFn (str) {
|
||||
return function (str) {
|
||||
const key = isPrimitive(str) ? str : JSON.stringify(str)
|
||||
const hit = cache[key]
|
||||
return hit || (cache[key] = fn(str))
|
||||
|
|
@ -17,14 +17,14 @@ export const hyphenate = cached(str => {
|
|||
return str.replace(/([A-Z])/g, m => '-' + m.toLowerCase())
|
||||
})
|
||||
|
||||
export const hasOwn = Object.prototype.hasOwnProperty
|
||||
|
||||
/**
|
||||
* Simple Object.assign polyfill
|
||||
*/
|
||||
export const merge =
|
||||
Object.assign ||
|
||||
function (to) {
|
||||
const hasOwn = Object.prototype.hasOwnProperty
|
||||
|
||||
for (let i = 1; i < arguments.length; i++) {
|
||||
const from = Object(arguments[i])
|
||||
|
||||
|
|
@ -41,18 +41,18 @@ export const merge =
|
|||
/**
|
||||
* Check if value is primitive
|
||||
*/
|
||||
export function isPrimitive (value) {
|
||||
export function isPrimitive(value) {
|
||||
return typeof value === 'string' || typeof value === 'number'
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform no operation.
|
||||
*/
|
||||
export function noop () {}
|
||||
export function noop() {}
|
||||
|
||||
/**
|
||||
* Check if value is function
|
||||
*/
|
||||
export function isFn (obj) {
|
||||
export function isFn(obj) {
|
||||
return typeof obj === 'function'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { isFn } from '../util/core'
|
||||
import { inBrowser } from './env'
|
||||
import {isFn} from '../util/core'
|
||||
import {inBrowser} from './env'
|
||||
|
||||
const cacheNode = {}
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ const cacheNode = {}
|
|||
* @param {Boolean} noCache
|
||||
* @return {Element}
|
||||
*/
|
||||
export function getNode (el, noCache = false) {
|
||||
export function getNode(el, noCache = false) {
|
||||
if (typeof el === 'string') {
|
||||
if (typeof window.Vue !== 'undefined') {
|
||||
return find(el)
|
||||
|
|
@ -32,7 +32,7 @@ export const head = inBrowser && $.head
|
|||
* find('nav') => document.querySelector('nav')
|
||||
* find(nav, 'a') => nav.querySelector('a')
|
||||
*/
|
||||
export function find (el, node) {
|
||||
export function find(el, node) {
|
||||
return node ? el.querySelector(node) : $.querySelector(el)
|
||||
}
|
||||
|
||||
|
|
@ -42,36 +42,38 @@ export function find (el, node) {
|
|||
* findAll('a') => [].slice.call(document.querySelectorAll('a'))
|
||||
* findAll(nav, 'a') => [].slice.call(nav.querySelectorAll('a'))
|
||||
*/
|
||||
export function findAll (el, node) {
|
||||
export function findAll(el, node) {
|
||||
return [].slice.call(
|
||||
node ? el.querySelectorAll(node) : $.querySelectorAll(el)
|
||||
)
|
||||
}
|
||||
|
||||
export function create (node, tpl) {
|
||||
export function create(node, tpl) {
|
||||
node = $.createElement(node)
|
||||
if (tpl) node.innerHTML = tpl
|
||||
if (tpl) {
|
||||
node.innerHTML = tpl
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
export function appendTo (target, el) {
|
||||
export function appendTo(target, el) {
|
||||
return target.appendChild(el)
|
||||
}
|
||||
|
||||
export function before (target, el) {
|
||||
export function before(target, el) {
|
||||
return target.insertBefore(el, target.children[0])
|
||||
}
|
||||
|
||||
export function on (el, type, handler) {
|
||||
isFn(type)
|
||||
? window.addEventListener(el, type)
|
||||
: el.addEventListener(type, handler)
|
||||
export function on(el, type, handler) {
|
||||
isFn(type) ?
|
||||
window.addEventListener(el, type) :
|
||||
el.addEventListener(type, handler)
|
||||
}
|
||||
|
||||
export function off (el, type, handler) {
|
||||
isFn(type)
|
||||
? window.removeEventListener(el, type)
|
||||
: el.removeEventListener(type, handler)
|
||||
export function off(el, type, handler) {
|
||||
isFn(type) ?
|
||||
window.removeEventListener(el, type) :
|
||||
el.removeEventListener(type, handler)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -81,10 +83,10 @@ export function off (el, type, handler) {
|
|||
* toggleClass(el, 'active') => el.classList.toggle('active')
|
||||
* toggleClass(el, 'add', 'active') => el.classList.add('active')
|
||||
*/
|
||||
export function toggleClass (el, type, val) {
|
||||
export function toggleClass(el, type, val) {
|
||||
el && el.classList[val ? type : 'toggle'](val || type)
|
||||
}
|
||||
|
||||
export function style (content) {
|
||||
export function style(content) {
|
||||
appendTo(head, create('style', content))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export const supportsPushState =
|
|||
window.history &&
|
||||
window.history.pushState &&
|
||||
window.history.replaceState &&
|
||||
// pushState isn’t reliable on iOS until 5.
|
||||
// PushState isn’t reliable on iOS until 5.
|
||||
!navigator.userAgent.match(
|
||||
/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import * as dom from '../dom'
|
||||
import { get } from '../../fetch/ajax'
|
||||
import {get} from '../../fetch/ajax'
|
||||
|
||||
function replaceVar (block, color) {
|
||||
function replaceVar(block, color) {
|
||||
block.innerHTML = block.innerHTML.replace(
|
||||
/var\(\s*--theme-color.*?\)/g,
|
||||
color
|
||||
|
|
@ -10,16 +10,20 @@ function replaceVar (block, color) {
|
|||
|
||||
export default function (color) {
|
||||
// Variable support
|
||||
if (window.CSS && window.CSS.supports && window.CSS.supports('(--v:red)')) { return }
|
||||
if (window.CSS && window.CSS.supports && window.CSS.supports('(--v:red)')) {
|
||||
return
|
||||
}
|
||||
|
||||
const styleBlocks = dom.findAll('style:not(.inserted),link')
|
||||
;[].forEach.call(styleBlocks, block => {
|
||||
const styleBlocks = dom.findAll('style:not(.inserted),link');
|
||||
[].forEach.call(styleBlocks, block => {
|
||||
if (block.nodeName === 'STYLE') {
|
||||
replaceVar(block, color)
|
||||
} else if (block.nodeName === 'LINK') {
|
||||
const href = block.getAttribute('href')
|
||||
|
||||
if (!/\.css$/.test(href)) return
|
||||
if (!/\.css$/.test(href)) {
|
||||
return
|
||||
}
|
||||
|
||||
get(href).then(res => {
|
||||
const style = dom.create('style', res)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue