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) { path = first ? path : path.replace(/\/$/, '') path = getParentPath(path) if (!path) { return } get( vm.router.getFile(path + file) + qs, false, vm.config.requestHeaders ).then(next, _ => loadNested(path, qs, file, next, vm)) } export function fetchMixin(proto) { let last const abort = () => last && last.abort && last.abort() const request = (url, hasbar, requestHeaders) => { abort() last = get(url, true, requestHeaders) return last } const get404Path = (path, config) => { const {notFoundPage, ext} = config const defaultPath = '_404' + (ext || '.md') let key let path404 switch (typeof notFoundPage) { case 'boolean': path404 = defaultPath break case 'string': path404 = notFoundPage break 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() } const fn = result => { this._renderSidebar(result) cb() } // Load sidebar loadNested(path, qs, loadSidebar, fn, this, true) } } proto._fetch = function (cb = noop) { const {path, query} = this.route const qs = stringifyQuery(query, ['id']) const {loadNavbar, requestHeaders, loadSidebar} = this.config // Abort last request const file = this.router.getFile(path) const req = request(file + qs, true, requestHeaders) // Current page is html 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) } ) // Load nav loadNavbar && loadNested( path, qs, loadNavbar, text => this._renderNav(text), this, true ) } proto._fetchCover = function () { const {coverpage, requestHeaders} = this.config const query = this.route.query const root = getParentPath(this.route.path) if (coverpage) { let path = null const routePath = this.route.path if (typeof coverpage === 'string') { if (routePath === '/') { path = coverpage } } else if (Array.isArray(coverpage)) { path = coverpage.indexOf(routePath) > -1 && '_coverpage' } else { const cover = coverpage[routePath] path = cover === true ? '_coverpage' : cover } const coverOnly = Boolean(path) && this.config.onlyCover if (path) { path = this.router.getFile(root + path) this.coverIsHTML = /\.html$/g.test(path) get(path + stringifyQuery(query, ['id']), false, requestHeaders).then( text => this._renderCover(text, coverOnly) ) } else { this._renderCover(null, coverOnly) } return coverOnly } } proto.$fetch = function (cb = noop) { const done = () => { callHook(this, 'doneEach') cb() } const onlyCover = this._fetchCover() if (onlyCover) { done() } else { this._fetch(() => { this.$resetEvents() done() }) } } proto._fetchFallbackPage = function (path, qs, cb = noop) { const {requestHeaders, fallbackLanguages, loadSidebar} = this.config if (!fallbackLanguages) { return false } const local = path.split('/')[1] if (fallbackLanguages.indexOf(local) === -1) { return false } const newPath = path.replace(new RegExp(`^/${local}`), '') const req = request(newPath + qs, true, requestHeaders) req.then( (text, opt) => this._renderMain( text, opt, this._loadSideAndNav(path, qs, loadSidebar, cb) ), () => this._fetch404(path, qs, cb) ) return true } /** * Load the 404 page * @param path * @param qs * @param cb * @returns {*} * @private */ proto._fetch404 = function (path, qs, cb = noop) { const {loadSidebar, requestHeaders, notFoundPage} = this.config const fnLoadSideAndNav = this._loadSideAndNav(path, qs, loadSidebar, cb) if (notFoundPage) { 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 } this._renderMain(null, {}, fnLoadSideAndNav) return false } } export function initFetch(vm) { const {loadSidebar} = vm.config // Server-Side Rendering if (vm.rendered) { const activeEl = getAndActive(vm.router, '.sidebar-nav', true, true) if (loadSidebar && activeEl) { activeEl.parentNode.innerHTML += window.__SUB_SIDEBAR__ } vm._bindEventOnRendered(activeEl) vm.$resetEvents() callHook(vm, 'doneEach') callHook(vm, 'ready') } else { vm.$fetch(_ => callHook(vm, 'ready')) } }