mirror of
https://github.com/docsifyjs/docsify.git
synced 2025-12-08 19:55:52 +00:00
refactor(core): and markdown compiler
This commit is contained in:
parent
30da0d5d46
commit
fe88c154b0
@ -2,8 +2,5 @@
|
|||||||
"extends": ["vue"],
|
"extends": ["vue"],
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true
|
"browser": true
|
||||||
},
|
|
||||||
"globals": {
|
|
||||||
"$docsify": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
import { get } from './ajax'
|
import { get } from './ajax'
|
||||||
import { callHook } from '../init/lifecycle'
|
import { callHook } from '../init/lifecycle'
|
||||||
import { getCurrentRoot } from '../route/util'
|
import { getRoot } from '../route/util'
|
||||||
|
import { noop } from '../util/core'
|
||||||
|
|
||||||
export function fetchMixin (Docsify) {
|
export function fetchMixin (Docsify) {
|
||||||
let last
|
let last
|
||||||
|
|
||||||
Docsify.prototype._fetch = function (cb) {
|
Docsify.prototype._fetch = function (cb = noop) {
|
||||||
const { path } = this.route
|
const { path } = this.route
|
||||||
const { loadNavbar, loadSidebar } = this.config
|
const { loadNavbar, loadSidebar } = this.config
|
||||||
const currentRoot = getCurrentRoot(path)
|
const root = getRoot(path)
|
||||||
|
|
||||||
// Abort last request
|
// Abort last request
|
||||||
last && last.abort && last.abort()
|
last && last.abort && last.abort()
|
||||||
@ -21,14 +22,14 @@ export function fetchMixin (Docsify) {
|
|||||||
const fn = result => { this._renderSidebar(result); cb() }
|
const fn = result => { this._renderSidebar(result); cb() }
|
||||||
|
|
||||||
// Load sidebar
|
// Load sidebar
|
||||||
get(this.$getFile(currentRoot + loadSidebar))
|
get(this.$getFile(root + loadSidebar))
|
||||||
.then(fn, _ => get(loadSidebar).then(fn))
|
.then(fn, _ => get(loadSidebar).then(fn))
|
||||||
},
|
},
|
||||||
_ => this._renderMain(null))
|
_ => this._renderMain(null))
|
||||||
|
|
||||||
// Load nav
|
// Load nav
|
||||||
loadNavbar &&
|
loadNavbar &&
|
||||||
get(this.$getFile(currentRoot + loadNavbar))
|
get(this.$getFile(root + loadNavbar))
|
||||||
.then(
|
.then(
|
||||||
this._renderNav,
|
this._renderNav,
|
||||||
_ => get(loadNavbar).then(this._renderNav)
|
_ => get(loadNavbar).then(this._renderNav)
|
||||||
|
|||||||
@ -23,4 +23,4 @@ initGlobalAPI()
|
|||||||
/**
|
/**
|
||||||
* Run Docsify
|
* Run Docsify
|
||||||
*/
|
*/
|
||||||
setTimeout(() => new Docsify(), 0)
|
new Docsify()
|
||||||
|
|||||||
@ -1,26 +1,56 @@
|
|||||||
import marked from 'marked'
|
import marked from 'marked'
|
||||||
import Prism from 'prismjs'
|
import Prism from 'prismjs'
|
||||||
|
import { helper as helperTpl } from './tpl'
|
||||||
|
import { slugify, clearSlugCache } from './slugify'
|
||||||
|
import { emojify } from './emojify'
|
||||||
|
import { toURL } from '../route/hash'
|
||||||
|
import { isFn, merge, cached } from '../util/core'
|
||||||
|
|
||||||
export const renderer = new marked.Renderer()
|
let markdownCompiler = marked
|
||||||
|
let contentBase = ''
|
||||||
export function markdown () {
|
let renderer = new marked.Renderer()
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const toc = []
|
const toc = []
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile markdown content
|
||||||
|
*/
|
||||||
|
export const markdown = cached(text => {
|
||||||
|
let html = ''
|
||||||
|
|
||||||
|
if (!text) return text
|
||||||
|
|
||||||
|
html = markdownCompiler(text)
|
||||||
|
html = emojify(html)
|
||||||
|
clearSlugCache()
|
||||||
|
|
||||||
|
return html
|
||||||
|
})
|
||||||
|
|
||||||
|
markdown.renderer = renderer
|
||||||
|
|
||||||
|
markdown.init = function (config = {}, context = window.location.pathname) {
|
||||||
|
contentBase = context
|
||||||
|
|
||||||
|
if (isFn(config)) {
|
||||||
|
markdownCompiler = config(marked, renderer)
|
||||||
|
} else {
|
||||||
|
renderer = merge(renderer, config.renderer)
|
||||||
|
marked.setOptions(merge(config, { renderer }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* render anchor tag
|
* render anchor tag
|
||||||
* @link https://github.com/chjj/marked#overriding-renderer-methods
|
* @link https://github.com/chjj/marked#overriding-renderer-methods
|
||||||
*/
|
*/
|
||||||
renderer.heading = function (text, level) {
|
renderer.heading = function (text, level) {
|
||||||
const slug = slugify(text)
|
const slug = slugify(text)
|
||||||
let route = ''
|
const url = toURL(contentBase, { id: slug })
|
||||||
|
|
||||||
route = `#/${getRoute()}`
|
toc.push({ level, slug: url, title: text })
|
||||||
toc.push({ level, slug: `${route}#${encodeURIComponent(slug)}`, title: text })
|
|
||||||
|
|
||||||
return `<h${level} id="${slug}"><a href="${route}#${slug}" data-id="${slug}" class="anchor"><span>${text}</span></a></h${level}>`
|
return `<h${level} id="${slug}"><a href="${url}" data-id="${slug}" class="anchor"><span>${text}</span></a></h${level}>`
|
||||||
}
|
}
|
||||||
// highlight code
|
// highlight code
|
||||||
renderer.code = function (code, lang = '') {
|
renderer.code = function (code, lang = '') {
|
||||||
@ -30,21 +60,31 @@ renderer.code = function (code, lang = '') {
|
|||||||
}
|
}
|
||||||
renderer.link = function (href, title, text) {
|
renderer.link = function (href, title, text) {
|
||||||
if (!/:|(\/{2})/.test(href)) {
|
if (!/:|(\/{2})/.test(href)) {
|
||||||
|
// TODO
|
||||||
href = `#/${href}`.replace(/\/+/g, '/')
|
href = `#/${href}`.replace(/\/+/g, '/')
|
||||||
}
|
}
|
||||||
return `<a href="${href}" title="${title || ''}">${text}</a>`
|
return `<a href="${href}" title="${title || ''}">${text}</a>`
|
||||||
}
|
}
|
||||||
renderer.paragraph = function (text) {
|
renderer.paragraph = function (text) {
|
||||||
if (/^!>/.test(text)) {
|
if (/^!>/.test(text)) {
|
||||||
return tpl.helper('tip', text)
|
return helperTpl('tip', text)
|
||||||
} else if (/^\?>/.test(text)) {
|
} else if (/^\?>/.test(text)) {
|
||||||
return tpl.helper('warn', text)
|
return helperTpl('warn', text)
|
||||||
}
|
}
|
||||||
return `<p>${text}</p>`
|
return `<p>${text}</p>`
|
||||||
}
|
}
|
||||||
renderer.image = function (href, title, text) {
|
renderer.image = function (href, title, text) {
|
||||||
const url = /:|(\/{2})/.test(href) ? href : ($docsify.basePath + href).replace(/\/+/g, '/')
|
// TODO
|
||||||
const titleHTML = title ? ` title="${title}"` : ''
|
// get base path
|
||||||
|
// const url = /:|(\/{2})/.test(href) ? href : ($docsify.basePath + href).replace(/\/+/g, '/')
|
||||||
|
// const titleHTML = title ? ` title="${title}"` : ''
|
||||||
|
|
||||||
|
// return `<img src="${url}" alt="${text}"${titleHTML} />`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile sidebar
|
||||||
|
*/
|
||||||
|
export function sidebar (text) {
|
||||||
|
|
||||||
return `<img src="${url}" alt="${text}"${titleHTML} />`
|
|
||||||
}
|
}
|
||||||
|
|||||||
6
src/core/render/emojify.js
Normal file
6
src/core/render/emojify.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export function emojify (text) {
|
||||||
|
return text
|
||||||
|
.replace(/<(pre|template)[^>]*?>([\s\S]+)<\/(pre|template)>/g, m => m.replace(/:/g, '__colon__'))
|
||||||
|
.replace(/:(\w+?):/ig, '<img class="emoji" src="https://assets-cdn.github.com/images/icons/emoji/$1.png" alt="$1" />')
|
||||||
|
.replace(/__colon__/g, ':')
|
||||||
|
}
|
||||||
27
src/core/render/gen-tree.js
Normal file
27
src/core/render/gen-tree.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
const headlines = []
|
||||||
|
const last = {}
|
||||||
|
|
||||||
|
toc.forEach(headline => {
|
||||||
|
const level = headline.level || 1
|
||||||
|
const len = level - 1
|
||||||
|
|
||||||
|
if (level > maxLevel) return
|
||||||
|
if (last[len]) {
|
||||||
|
last[len].children = last[len].children || []
|
||||||
|
last[len].children.push(headline)
|
||||||
|
} else {
|
||||||
|
headlines.push(headline)
|
||||||
|
}
|
||||||
|
last[level] = headline
|
||||||
|
})
|
||||||
|
|
||||||
|
return headlines
|
||||||
|
}
|
||||||
@ -1,30 +1,47 @@
|
|||||||
import * as dom from '../util/dom'
|
import * as dom from '../util/dom'
|
||||||
import cssVars from '../util/polyfill/css-vars'
|
import cssVars from '../util/polyfill/css-vars'
|
||||||
import * as tpl from './tpl'
|
import * as tpl from './tpl'
|
||||||
|
import { markdown, sidebar } from './compiler'
|
||||||
|
import { callHook } from '../init/lifecycle'
|
||||||
|
|
||||||
function renderMain () {
|
function renderMain (html) {
|
||||||
|
if (!html) {
|
||||||
}
|
// TODO: Custom 404 page
|
||||||
|
}
|
||||||
function renderNav () {
|
this._renderTo('.markdown-section', html)
|
||||||
}
|
|
||||||
|
|
||||||
function renderSidebar () {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderMixin (Docsify) {
|
export function renderMixin (Docsify) {
|
||||||
Docsify.prototype._renderTo = function (el, content, replace) {
|
const proto = Docsify.prototype
|
||||||
|
|
||||||
|
proto._renderTo = function (el, content, replace) {
|
||||||
const node = dom.getNode(el)
|
const node = dom.getNode(el)
|
||||||
if (node) node[replace ? 'outerHTML' : 'innerHTML'] = content
|
if (node) node[replace ? 'outerHTML' : 'innerHTML'] = content
|
||||||
}
|
}
|
||||||
|
|
||||||
Docsify.prototype._renderSidebar = renderSidebar
|
proto._renderSidebar = function (text) {
|
||||||
Docsify.prototype._renderNav = renderNav
|
this._renderTo('.sidebar-nav', sidebar(text))
|
||||||
Docsify.prototype._renderMain = renderMain
|
// bind event
|
||||||
|
}
|
||||||
|
|
||||||
|
proto._renderNav = function (text) {
|
||||||
|
this._renderTo('nav', markdown(text))
|
||||||
|
}
|
||||||
|
|
||||||
|
proto._renderMain = function (text) {
|
||||||
|
callHook(this, 'beforeEach', text, result => {
|
||||||
|
const html = markdown(result)
|
||||||
|
callHook(this, 'afterEach', html, text => renderMain.call(this, text))
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initRender (vm) {
|
export function initRender (vm) {
|
||||||
const config = vm.config
|
const config = vm.config
|
||||||
|
|
||||||
|
// Init markdown compiler
|
||||||
|
markdown.init(vm.config.markdown)
|
||||||
|
|
||||||
const id = config.el || '#app'
|
const id = config.el || '#app'
|
||||||
const navEl = dom.find('nav') || dom.create('nav')
|
const navEl = dom.find('nav') || dom.create('nav')
|
||||||
|
|
||||||
|
|||||||
27
src/core/render/slugify.js
Normal file
27
src/core/render/slugify.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
let cache = {}
|
||||||
|
const re = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,.\/:;<=>?@\[\]^`{|}~]/g
|
||||||
|
|
||||||
|
export function slugify (str) {
|
||||||
|
if (typeof str !== 'string') return ''
|
||||||
|
|
||||||
|
let slug = str.toLowerCase().trim()
|
||||||
|
.replace(/<[^>\d]+>/g, '')
|
||||||
|
.replace(re, '')
|
||||||
|
.replace(/\s/g, '-')
|
||||||
|
.replace(/-+/g, '-')
|
||||||
|
.replace(/^(\d)/, '_$1')
|
||||||
|
let count = cache[slug]
|
||||||
|
|
||||||
|
count = cache.hasOwnProperty(slug) ? (count + 1) : 0
|
||||||
|
cache[slug] = count
|
||||||
|
|
||||||
|
if (count) {
|
||||||
|
slug = slug + '-' + count
|
||||||
|
}
|
||||||
|
|
||||||
|
return slug
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearSlugCache () {
|
||||||
|
cache = {}
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
import { parseQuery } from './util'
|
import { merge } from '../util/core'
|
||||||
|
import { parseQuery, stringifyQuery, cleanPath } from './util'
|
||||||
|
|
||||||
function replaceHash (path) {
|
function replaceHash (path) {
|
||||||
const i = window.location.href.indexOf('#')
|
const i = window.location.href.indexOf('#')
|
||||||
@ -34,11 +35,11 @@ export function getHash () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the current url
|
* Parse the url
|
||||||
|
* @param {string} [path=window.location.herf]
|
||||||
* @return {object} { path, query }
|
* @return {object} { path, query }
|
||||||
*/
|
*/
|
||||||
export function parse () {
|
export function parse (path = window.location.href) {
|
||||||
let path = window.location.href
|
|
||||||
let query = ''
|
let query = ''
|
||||||
|
|
||||||
const queryIndex = path.indexOf('?')
|
const queryIndex = path.indexOf('?')
|
||||||
@ -57,9 +58,14 @@ export function parse () {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* to URL
|
* to URL
|
||||||
* @param {String} path
|
* @param {string} path
|
||||||
* @param {String} qs query string
|
* @param {object} qs query params
|
||||||
*/
|
*/
|
||||||
export function toURL (path, qs) {
|
export function toURL (path, params) {
|
||||||
|
const route = parse(path)
|
||||||
|
|
||||||
|
route.query = merge({}, route.query, params)
|
||||||
|
path = route.path + stringifyQuery(route.query)
|
||||||
|
|
||||||
|
return '#' + path
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,13 +30,19 @@ export function routeMixin (Docsify) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let lastRoute = {}
|
||||||
|
|
||||||
export function initRoute (vm) {
|
export function initRoute (vm) {
|
||||||
normalize()
|
normalize()
|
||||||
vm.route = parse()
|
lastRoute = vm.route = parse()
|
||||||
|
|
||||||
on('hashchange', _ => {
|
on('hashchange', _ => {
|
||||||
normalize()
|
normalize()
|
||||||
vm.route = parse()
|
lastRoute = vm.route = parse()
|
||||||
|
if (lastRoute.path === vm.route.path) {
|
||||||
|
// TODO: goto xxx
|
||||||
|
return
|
||||||
|
}
|
||||||
vm._fetch()
|
vm._fetch()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { cached } from '../util/core'
|
import { cached } from '../util/core'
|
||||||
|
|
||||||
const decode = decodeURIComponent
|
const decode = decodeURIComponent
|
||||||
|
const encode = encodeURIComponent
|
||||||
|
|
||||||
export const parseQuery = cached(query => {
|
export const parseQuery = cached(query => {
|
||||||
const res = {}
|
const res = {}
|
||||||
@ -11,35 +12,35 @@ export const parseQuery = cached(query => {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simple parse
|
||||||
query.split('&').forEach(function (param) {
|
query.split('&').forEach(function (param) {
|
||||||
const parts = param.replace(/\+/g, ' ').split('=')
|
const parts = param.replace(/\+/g, ' ').split('=')
|
||||||
const key = decode(parts.shift())
|
|
||||||
const val = parts.length > 0
|
|
||||||
? decode(parts.join('='))
|
|
||||||
: null
|
|
||||||
|
|
||||||
if (res[key] === undefined) {
|
res[parts[0]] = decode(parts[1])
|
||||||
res[key] = val
|
|
||||||
} else if (Array.isArray(res[key])) {
|
|
||||||
res[key].push(val)
|
|
||||||
} else {
|
|
||||||
res[key] = [res[key], val]
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return res
|
return res
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export function stringifyQuery (obj) {
|
||||||
|
const qs = []
|
||||||
|
|
||||||
|
for (const key in obj) {
|
||||||
|
qs.push(`${encode(key)}=${encode(obj[key])}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return qs.length ? `?${qs.join('&')}` : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getBasePath = cached(base => {
|
||||||
|
return /^(\/|https?:)/g.test(base)
|
||||||
|
? base
|
||||||
|
: cleanPath(window.location.pathname + '/' + base)
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getRoot = cached(path => {
|
||||||
|
return /\/$/g.test(path) ? path : path.match(/(\S*\/)[^\/]+$/)[1]
|
||||||
|
})
|
||||||
|
|
||||||
export function cleanPath (path) {
|
export function cleanPath (path) {
|
||||||
return path.replace(/\/+/g, '/')
|
return path.replace(/\/+/g, '/')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBasePath (base) {
|
|
||||||
return /^(\/|https?:)/g.test(base)
|
|
||||||
? base
|
|
||||||
: cleanPath(window.location.pathname + '/' + base)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getCurrentRoot (path) {
|
|
||||||
return /\/$/g.test(path) ? path : path.match(/(\S*\/)[^\/]+$/)[1]
|
|
||||||
}
|
|
||||||
|
|||||||
166
src/util.js
166
src/util.js
@ -1,166 +0,0 @@
|
|||||||
/**
|
|
||||||
* Simple ajax
|
|
||||||
* @param {String} url
|
|
||||||
* @param {String} [method=GET]
|
|
||||||
* @param {Function} [loading] handle loading
|
|
||||||
* @return {Promise}
|
|
||||||
*/
|
|
||||||
export function load (url, method = 'GET', loading) {
|
|
||||||
const xhr = new XMLHttpRequest()
|
|
||||||
|
|
||||||
xhr.open(method, url)
|
|
||||||
xhr.send()
|
|
||||||
|
|
||||||
return {
|
|
||||||
then: function (success, error = function () {}) {
|
|
||||||
if (loading) {
|
|
||||||
const id = setInterval(_ =>
|
|
||||||
loading({ step: Math.floor(Math.random() * 5 + 1) }),
|
|
||||||
500)
|
|
||||||
xhr.addEventListener('progress', loading)
|
|
||||||
xhr.addEventListener('loadend', evt => {
|
|
||||||
loading(evt)
|
|
||||||
clearInterval(id)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
xhr.addEventListener('error', error)
|
|
||||||
xhr.addEventListener('load', ({ target }) => {
|
|
||||||
target.status >= 400 ? error(target) : success(target.response)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
abort: () => xhr.readyState !== 4 && xhr.abort()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
const headlines = []
|
|
||||||
const last = {}
|
|
||||||
|
|
||||||
toc.forEach(headline => {
|
|
||||||
const level = headline.level || 1
|
|
||||||
const len = level - 1
|
|
||||||
|
|
||||||
if (level > maxLevel) return
|
|
||||||
if (last[len]) {
|
|
||||||
last[len].children = last[len].children || []
|
|
||||||
last[len].children.push(headline)
|
|
||||||
} else {
|
|
||||||
headlines.push(headline)
|
|
||||||
}
|
|
||||||
last[level] = headline
|
|
||||||
})
|
|
||||||
|
|
||||||
return headlines
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* camel to kebab
|
|
||||||
* @link https://github.com/bokuweb/kebab2camel/blob/master/index.js
|
|
||||||
* @param {String} str
|
|
||||||
* @return {String}
|
|
||||||
*/
|
|
||||||
export function camel2kebab (str) {
|
|
||||||
return str.replace(/([A-Z])/g, m => '-' + m.toLowerCase())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* is nil
|
|
||||||
* @param {Object} object
|
|
||||||
* @return {Boolean}
|
|
||||||
*/
|
|
||||||
export function isNil (o) {
|
|
||||||
return o === null || o === undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
let cacheRoute = null
|
|
||||||
let cacheHash = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash route
|
|
||||||
*/
|
|
||||||
export function getRoute () {
|
|
||||||
const loc = window.location
|
|
||||||
if (cacheHash === loc.hash && !isNil(cacheRoute)) return cacheRoute
|
|
||||||
|
|
||||||
let route = loc.hash.replace(/%23/g, '#').match(/^#\/([^#]+)/)
|
|
||||||
|
|
||||||
if (route && route.length === 2) {
|
|
||||||
route = route[1]
|
|
||||||
} else {
|
|
||||||
route = /^#\//.test(loc.hash) ? '' : loc.pathname
|
|
||||||
}
|
|
||||||
cacheRoute = route
|
|
||||||
cacheHash = loc.hash
|
|
||||||
|
|
||||||
return route
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isMobile () {
|
|
||||||
return document.body.clientWidth <= 600
|
|
||||||
}
|
|
||||||
|
|
||||||
export function slugify (string) {
|
|
||||||
const re = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,.\/:;<=>?@\[\]^`{|}~]/g
|
|
||||||
const maintainCase = false
|
|
||||||
const replacement = '-'
|
|
||||||
|
|
||||||
slugify.occurrences = slugify.occurrences || {}
|
|
||||||
|
|
||||||
if (typeof string !== 'string') return ''
|
|
||||||
if (!maintainCase) string = string.toLowerCase()
|
|
||||||
|
|
||||||
let slug = string.trim()
|
|
||||||
.replace(/<[^>\d]+>/g, '')
|
|
||||||
.replace(re, '')
|
|
||||||
.replace(/\s/g, replacement)
|
|
||||||
.replace(/-+/g, replacement)
|
|
||||||
.replace(/^(\d)/, '_$1')
|
|
||||||
let occurrences = slugify.occurrences[slug]
|
|
||||||
|
|
||||||
if (slugify.occurrences.hasOwnProperty(slug)) {
|
|
||||||
occurrences++
|
|
||||||
} else {
|
|
||||||
occurrences = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
slugify.occurrences[slug] = occurrences
|
|
||||||
|
|
||||||
if (occurrences) {
|
|
||||||
slug = slug + '-' + occurrences
|
|
||||||
}
|
|
||||||
|
|
||||||
return slug
|
|
||||||
}
|
|
||||||
|
|
||||||
slugify.clear = function () {
|
|
||||||
slugify.occurrences = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasOwnProperty = Object.prototype.hasOwnProperty
|
|
||||||
export const merge = Object.assign || function (to) {
|
|
||||||
for (let i = 1; i < arguments.length; i++) {
|
|
||||||
const from = Object(arguments[i])
|
|
||||||
|
|
||||||
for (const key in from) {
|
|
||||||
if (hasOwnProperty.call(from, key)) {
|
|
||||||
to[key] = from[key]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return to
|
|
||||||
}
|
|
||||||
|
|
||||||
export function emojify (text) {
|
|
||||||
return text
|
|
||||||
.replace(/<(pre|template)[^>]*?>([\s\S]+)<\/(pre|template)>/g, match => match.replace(/:/g, '__colon__'))
|
|
||||||
.replace(/:(\w+?):/ig, '<img class="emoji" src="https://assets-cdn.github.com/images/icons/emoji/$1.png" alt="$1" />')
|
|
||||||
.replace(/__colon__/g, ':')
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user