mirror of
https://github.com/docsifyjs/docsify.git
synced 2025-12-08 19:55:52 +00:00
Merge branch 'develop' into update-config
This commit is contained in:
commit
7f835b15e3
4
.codesandbox/ci.json
Normal file
4
.codesandbox/ci.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"sandboxes": ["2d17z"],
|
||||
"packages": [".", "packages/docsify-server-renderer"]
|
||||
}
|
||||
4
.github/semantic.yml
vendored
Normal file
4
.github/semantic.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
titleAndCommits: true
|
||||
allowMergeCommits: true
|
||||
allowRevertCommits: true
|
||||
anyCommit: true
|
||||
@ -16,7 +16,7 @@
|
||||
<meta name="description" content="A magical documentation generator." />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
|
||||
content="width=device-width, initial-scale=1.0, minimum-scale=1.0"
|
||||
/>
|
||||
<link rel="stylesheet" href="lib/themes/vue.css" title="vue" />
|
||||
<link rel="stylesheet" href="lib/themes/dark.css" title="dark" disabled />
|
||||
|
||||
6
docs/_media/example-with-yaml.md
Normal file
6
docs/_media/example-with-yaml.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
author: John Smith
|
||||
date: 2020-1-1
|
||||
---
|
||||
|
||||
> This is from the `example.md`
|
||||
@ -144,6 +144,16 @@ window.$docsify = {
|
||||
};
|
||||
```
|
||||
|
||||
If you have a link to the homepage in the sidebar and want it to be shown as active when accessing the root url, make sure to update your sidebar accordingly:
|
||||
|
||||
```markdown
|
||||
- Sidebar
|
||||
- [Home](/)
|
||||
- [Another page](another.md)
|
||||
```
|
||||
|
||||
For more details, see [#1131](https://github.com/docsifyjs/docsify/issues/1131).
|
||||
|
||||
## basePath
|
||||
|
||||
- Type: `String`
|
||||
@ -265,7 +275,7 @@ window.$docsify = {
|
||||
- Type: `String`
|
||||
- Default: `window.location.pathname`
|
||||
|
||||
The name of the link.
|
||||
The URL that the website `name` links to.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
@ -446,11 +456,11 @@ window.$docsify = {
|
||||
- type: `String`
|
||||
- default: `noopener`
|
||||
|
||||
Default `'noopener'` (no opener) prevents the newly opened external page (when [externalLinkTarget](#externallinktarget) is `'_blank'`) from having the ability to control our page. No `rel` is set when its not `'_blank'`.
|
||||
Default `'noopener'` (no opener) prevents the newly opened external page (when [externalLinkTarget](#externallinktarget) is `'_blank'`) from having the ability to control our page. No `rel` is set when its not `'_blank'`. See [this post](https://mathiasbynens.github.io/rel-noopener/) for more information about why you may want to use this option.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
externalLinkTarget: '', // default: 'noopener'
|
||||
externalLinkRel: '', // default: 'noopener'
|
||||
};
|
||||
```
|
||||
|
||||
@ -587,4 +597,4 @@ Adds a space on top when scrolling content page to reach the selected section. T
|
||||
window.$docsify = {
|
||||
topMargin: 90, // default: 0
|
||||
};
|
||||
```
|
||||
```
|
||||
|
||||
@ -39,7 +39,20 @@ You will get it
|
||||
|
||||
[filename](_media/example.md ':include :type=code')
|
||||
|
||||
## Markdown with YAML Front Matter
|
||||
|
||||
When using Markdown, YAML front matter will be stripped from the rendered content. The attributes cannot be used in this case.
|
||||
|
||||
```markdown
|
||||
[filename](_media/example-with-yaml.md ':include')
|
||||
```
|
||||
|
||||
You will get just the content
|
||||
|
||||
[filename](_media/example-with-yaml.md ':include')
|
||||
|
||||
## Embedded code fragments
|
||||
|
||||
Sometimes you don't want to embed a whole file. Maybe because you need just a few lines but you want to compile and test the file in CI.
|
||||
|
||||
```markdown
|
||||
@ -53,7 +66,6 @@ Example:
|
||||
|
||||
[filename](_media/example.js ':include :type=code :fragment=demo')
|
||||
|
||||
|
||||
## Tag attribute
|
||||
|
||||
If you embed the file as `iframe`, `audio` and `video`, then you may need to set the attributes of these tags.
|
||||
|
||||
@ -65,6 +65,14 @@ You will get `<a href="/demo/">link</a>`html. Do not worry, you can still set ti
|
||||
[link](/demo ':disabled')
|
||||
```
|
||||
|
||||
## Cross-Origin link
|
||||
|
||||
Only when you both set the `routerMode: 'history'` and `externalLinkTarget: '_self'`, you need add this configuration for those Cross-Origin links.
|
||||
|
||||
```md
|
||||
[example.com](https://example.com/ ':crossorgin')
|
||||
```
|
||||
|
||||
## Github Task Lists
|
||||
|
||||
```md
|
||||
|
||||
@ -9,14 +9,14 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="keywords" content="doc,docs,documentation,gitbook,creator,generator,github,jekyll,github-pages">
|
||||
<meta name="description" content="A magical documentation generator.">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/vue.css" title="vue">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/dark.css" title="dark" disabled>
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/buble.css" title="buble" disabled>
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/pure.css" title="pure" disabled>
|
||||
|
||||
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-plugin-codefund/index.js"></script>
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify-dark-mode@0.6.1/dist/style.css"/>
|
||||
|
||||
<style>
|
||||
nav.app-nav li ul {
|
||||
min-width: 100px;
|
||||
@ -32,7 +32,7 @@
|
||||
'.*?/awesome': 'https://raw.githubusercontent.com/docsifyjs/awesome-docsify/master/README.md',
|
||||
'.*?/changelog': 'https://raw.githubusercontent.com/docsifyjs/docsify/master/CHANGELOG.md',
|
||||
'/.*/_navbar.md': '/_navbar.md',
|
||||
'/zh-cn/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-zh/master/$1',
|
||||
'/zh-cn/(.*)': 'https://cdn.jsdelivr.net/gh/docsifyjs/docs-zh@master/$1',
|
||||
'/de-de/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-de/master/$1',
|
||||
'/ru/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-ru/master/$1',
|
||||
'/es/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-es/master/$1'
|
||||
@ -64,11 +64,6 @@
|
||||
'/': 'Search'
|
||||
}
|
||||
},
|
||||
darkMode: {
|
||||
light: {
|
||||
toggleBtnBg: '#42b983'
|
||||
}
|
||||
},
|
||||
formatUpdated: '{MM}/{DD} {HH}:{mm}',
|
||||
plugins: [
|
||||
function (hook, vm) {
|
||||
@ -77,6 +72,10 @@
|
||||
url = vm.route.file
|
||||
.replace('raw.githubusercontent.com', 'github.com')
|
||||
.replace(/\/master/, '/blob/master')
|
||||
} else if (/jsdelivr\.net/.test(vm.route.file)) {
|
||||
url = vm.route.file
|
||||
.replace('cdn.jsdelivr.net/gh', 'github.com')
|
||||
.replace('@master', '/blob/master')
|
||||
} else {
|
||||
url = 'https://github.com/docsifyjs/docsify/blob/master/docs/' + vm.route.file
|
||||
}
|
||||
@ -99,7 +98,6 @@
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-markdown.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-nginx.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/docsify-dark-mode@0.6.1/dist/index.js"></script>
|
||||
<script>
|
||||
((window.gitter = {}).chat = {}).options = {
|
||||
room: 'docsifyjs/Lobby'
|
||||
|
||||
@ -68,7 +68,7 @@ You can provide a template for entire page's HTML. such as
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>docsify</title>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/themes/vue.css" title="vue">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
'.*?/awesome': 'https://raw.githubusercontent.com/docsifyjs/awesome-docsify/master/README.md',
|
||||
'.*?/changelog': 'https://raw.githubusercontent.com/docsifyjs/docsify/master/CHANGELOG.md',
|
||||
'/.*/_navbar.md': '/_navbar.md',
|
||||
'/zh-cn/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-zh/master/$1',
|
||||
'/zh-cn/(.*)': 'https://cdn.jsdelivr.net/gh/docsifyjs/docs-zh@master/$1',
|
||||
'/de-de/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-de/master/$1',
|
||||
'/ru/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-ru/master/$1',
|
||||
'/es/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-es/master/$1'
|
||||
@ -60,6 +60,10 @@
|
||||
url = vm.route.file
|
||||
.replace('raw.githubusercontent.com', 'github.com')
|
||||
.replace(/\/master/, '/blob/master')
|
||||
} else if (/jsdelivr\.net/.test(vm.route.file)) {
|
||||
url = vm.route.file
|
||||
.replace('cdn.jsdelivr.net/gh', 'github.com')
|
||||
.replace('@master', '/blob/master')
|
||||
} else {
|
||||
url = 'https://github.com/docsifyjs/docsify/blob/master/docs/' + vm.route.file
|
||||
}
|
||||
@ -76,6 +80,8 @@
|
||||
</script>
|
||||
<script src="/lib/docsify.js"></script>
|
||||
<script src="/lib/plugins/search.js"></script>
|
||||
<script src="/lib/plugins/emoji.js"></script>
|
||||
<script src="/lib/plugins/front-matter.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-markdown.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-nginx.min.js"></script>
|
||||
|
||||
@ -34,7 +34,7 @@ renderer.renderToString(url)
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>docsify</title>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/themes/buble.css" title="buble" disabled>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { resolve, basename } from 'path';
|
||||
import resolvePathname from 'resolve-pathname';
|
||||
import fetch from 'node-fetch';
|
||||
import debug from 'debug';
|
||||
import { AbstractHistory } from '../../src/core/router/history/abstract';
|
||||
import { Compiler } from '../../src/core/render/compiler';
|
||||
import { isAbsolutePath } from '../../src/core/router/util';
|
||||
import * as tpl from '../../src/core/render/tpl';
|
||||
import { prerenderEmbed } from '../../src/core/render/embed';
|
||||
import fetch from 'node-fetch';
|
||||
import debug from 'debug';
|
||||
|
||||
function cwd(...args) {
|
||||
return resolve(process.cwd(), ...args);
|
||||
|
||||
@ -11,7 +11,7 @@ if (isSSR) {
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>docsify</title>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="/themes/vue.css" title="vue">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@ -32,6 +32,7 @@ export default function() {
|
||||
externalLinkRel: 'noopener',
|
||||
routerMode: 'hash',
|
||||
noCompileLinks: [],
|
||||
crossOriginLinks: [],
|
||||
relativePath: false,
|
||||
topMargin: 0,
|
||||
},
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import Tweezer from 'tweezer.js';
|
||||
import { isMobile } from '../util/env';
|
||||
import * as dom from '../util/dom';
|
||||
import { removeParams } from '../router/util';
|
||||
import config from '../config';
|
||||
import Tweezer from 'tweezer.js';
|
||||
|
||||
const nav = {};
|
||||
let hoverOver = false;
|
||||
@ -59,8 +60,7 @@ function highlight(path) {
|
||||
return;
|
||||
}
|
||||
|
||||
const li =
|
||||
nav[getNavKey(decodeURIComponent(path), last.getAttribute('data-id'))];
|
||||
const li = nav[getNavKey(path, last.getAttribute('data-id'))];
|
||||
|
||||
if (!li || li === active) {
|
||||
return;
|
||||
@ -86,7 +86,7 @@ function highlight(path) {
|
||||
}
|
||||
|
||||
function getNavKey(path, id) {
|
||||
return `${path}?id=${id}`;
|
||||
return `${decodeURIComponent(path)}?id=${decodeURIComponent(id)}`;
|
||||
}
|
||||
|
||||
export function scrollActiveSidebar(router) {
|
||||
@ -127,7 +127,7 @@ export function scrollActiveSidebar(router) {
|
||||
return;
|
||||
}
|
||||
|
||||
const path = router.getCurrentPath();
|
||||
const path = removeParams(router.getCurrentPath());
|
||||
dom.off('scroll', () => highlight(path));
|
||||
dom.on('scroll', () => highlight(path));
|
||||
dom.on(sidebar, 'mouseover', () => {
|
||||
|
||||
@ -39,6 +39,7 @@ export function collapse(el) {
|
||||
if (
|
||||
target.nodeName === 'A' &&
|
||||
target.nextSibling &&
|
||||
target.nextSibling.classList &&
|
||||
target.nextSibling.classList.contains('app-sub-sidebar')
|
||||
) {
|
||||
dom.toggleClass(target.parentNode, 'collapse');
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import prism from 'prismjs';
|
||||
import marked from 'marked';
|
||||
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 prism from 'prismjs';
|
||||
import marked from 'marked';
|
||||
|
||||
export default function() {
|
||||
window.Docsify = {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import marked from 'marked';
|
||||
import { isAbsolutePath, getPath, getParentPath } from '../router/util';
|
||||
import { isFn, merge, cached, isPrimitive } from '../util/core';
|
||||
import { tree as treeTpl } from './tpl';
|
||||
@ -11,7 +12,6 @@ import { paragraphCompiler } from './compiler/paragraph';
|
||||
import { taskListCompiler } from './compiler/taskList';
|
||||
import { taskListItemCompiler } from './compiler/taskListItem';
|
||||
import { linkCompiler } from './compiler/link';
|
||||
import marked from 'marked';
|
||||
|
||||
const cachedLinks = {};
|
||||
|
||||
@ -121,6 +121,21 @@ export class Compiler {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulls content from file and renders inline on the page as a embedded item.
|
||||
*
|
||||
* This allows you to embed different file types on the returned
|
||||
* page.
|
||||
* The basic format is:
|
||||
* ```
|
||||
* [filename](_media/example.md ':include')
|
||||
* ```
|
||||
*
|
||||
* @param {string} href The href to the file to embed in the page.
|
||||
* @param {string} title Title of the link used to make the embed.
|
||||
*
|
||||
* @return {type} Return value description.
|
||||
*/
|
||||
compileEmbed(href, title) {
|
||||
const { str, config } = getAndRemoveConfig(title);
|
||||
let embed;
|
||||
@ -178,7 +193,7 @@ export class Compiler {
|
||||
|
||||
_initRenderer() {
|
||||
const renderer = new marked.Renderer();
|
||||
const { linkTarget, router, contentBase } = this;
|
||||
const { linkTarget, linkRel, router, contentBase } = this;
|
||||
const _self = this;
|
||||
const origin = {};
|
||||
|
||||
@ -218,6 +233,7 @@ export class Compiler {
|
||||
renderer,
|
||||
router,
|
||||
linkTarget,
|
||||
linkRel,
|
||||
compilerClass: _self,
|
||||
});
|
||||
origin.paragraph = paragraphCompiler({ renderer });
|
||||
|
||||
@ -22,7 +22,7 @@ export const imageCompiler = ({ renderer, contentBase, router }) =>
|
||||
if (height) {
|
||||
attrs.push(`width="${width}" height="${height}"`);
|
||||
} else {
|
||||
attrs.push(`width="${width}" height="${width}"`);
|
||||
attrs.push(`width="${width}"`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,21 @@
|
||||
import { getAndRemoveConfig } from '../utils';
|
||||
import { isAbsolutePath } from '../../router/util';
|
||||
|
||||
export const linkCompiler = ({ renderer, router, linkTarget, compilerClass }) =>
|
||||
export const linkCompiler = ({
|
||||
renderer,
|
||||
router,
|
||||
linkTarget,
|
||||
linkRel,
|
||||
compilerClass,
|
||||
}) =>
|
||||
(renderer.link = (href, title = '', text) => {
|
||||
let attrs = [];
|
||||
const { str, config } = getAndRemoveConfig(title);
|
||||
|
||||
linkTarget = config.target || linkTarget;
|
||||
linkRel =
|
||||
linkTarget === '_blank'
|
||||
? compilerClass.config.externalLinkRel || 'noopener'
|
||||
: '';
|
||||
title = str;
|
||||
|
||||
if (
|
||||
@ -24,10 +34,24 @@ export const linkCompiler = ({ renderer, router, linkTarget, compilerClass }) =>
|
||||
document.URL.replace(/\/(?!.*\/).*/, '/').replace('#/./', '') + href;
|
||||
}
|
||||
attrs.push(href.indexOf('mailto:') === 0 ? '' : `target="${linkTarget}"`);
|
||||
attrs.push(
|
||||
href.indexOf('mailto:') === 0
|
||||
? ''
|
||||
: linkRel !== ''
|
||||
? ` rel="${linkRel}"`
|
||||
: ''
|
||||
);
|
||||
}
|
||||
|
||||
if (config.target) {
|
||||
attrs.push(`target="${config.target}"`);
|
||||
// special case to check crossorigin urls
|
||||
if (
|
||||
config.crossorgin &&
|
||||
linkTarget === '_self' &&
|
||||
compilerClass.config.routerMode === 'history'
|
||||
) {
|
||||
if (compilerClass.config.crossOriginLinks.indexOf(href) === -1) {
|
||||
compilerClass.config.crossOriginLinks.push(href);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.disabled) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import stripIndent from 'strip-indent';
|
||||
import { get } from '../fetch/ajax';
|
||||
import { merge } from '../util/core';
|
||||
import stripIndent from 'strip-indent';
|
||||
|
||||
const cached = {};
|
||||
|
||||
@ -36,6 +36,13 @@ function walkFetchEmbed({ embedTokens, compile, fetch }, cb) {
|
||||
return x;
|
||||
});
|
||||
|
||||
// This may contain YAML front matter and will need to be stripped.
|
||||
const frontMatterInstalled =
|
||||
($docsify.frontMatter || {}).installed || false;
|
||||
if (frontMatterInstalled === true) {
|
||||
text = $docsify.frontMatter.parseMarkdown(text);
|
||||
}
|
||||
|
||||
embedToken = compile.lexer(text);
|
||||
} else if (token.embed.type === 'code') {
|
||||
if (token.embed.fragment) {
|
||||
@ -117,17 +124,27 @@ export function prerenderEmbed({ compiler, raw = '', fetch }, done) {
|
||||
}
|
||||
});
|
||||
|
||||
let moveIndex = 0;
|
||||
// keep track of which tokens have been embedded so far
|
||||
// so that we know where to insert the embedded tokens as they
|
||||
// are returned
|
||||
const moves = [];
|
||||
walkFetchEmbed({ compile, embedTokens, fetch }, ({ embedToken, token }) => {
|
||||
if (token) {
|
||||
const index = token.index + moveIndex;
|
||||
// iterate through the array of previously inserted tokens
|
||||
// to determine where the current embedded tokens should be inserted
|
||||
let index = token.index;
|
||||
moves.forEach(pos => {
|
||||
if (index > pos.start) {
|
||||
index += pos.length;
|
||||
}
|
||||
});
|
||||
|
||||
merge(links, embedToken.links);
|
||||
|
||||
tokens = tokens
|
||||
.slice(0, index)
|
||||
.concat(embedToken, tokens.slice(index + 1));
|
||||
moveIndex += embedToken.length - 1;
|
||||
moves.push({ start: index, length: embedToken.length - 1 });
|
||||
} else {
|
||||
cached[raw] = tokens.concat();
|
||||
tokens.links = cached[raw].links = links;
|
||||
|
||||
@ -12,6 +12,8 @@ function replace(m, $1) {
|
||||
|
||||
export function emojify(text) {
|
||||
return text
|
||||
.replace(/:\+1:/g, ':thumbsup:')
|
||||
.replace(/:-1:/g, ':thumbsdown:')
|
||||
.replace(/<(pre|template|code)[^>]*?>[\s\S]+?<\/(pre|template|code)>/g, m =>
|
||||
m.replace(/:/g, '__colon__')
|
||||
)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import tinydate from 'tinydate';
|
||||
import * as dom from '../util/dom';
|
||||
import cssVars from '../util/polyfill/css-vars';
|
||||
import { callHook } from '../init/lifecycle';
|
||||
@ -10,7 +11,6 @@ import { scrollActiveSidebar } from '../event/scroll';
|
||||
import { Compiler } from './compiler';
|
||||
import * as tpl from './tpl';
|
||||
import { prerenderEmbed } from './embed';
|
||||
import tinydate from 'tinydate';
|
||||
|
||||
function executeScript() {
|
||||
const script = dom
|
||||
|
||||
@ -1,3 +1,23 @@
|
||||
/**
|
||||
* Converts a colon formatted string to a object with properties.
|
||||
*
|
||||
* This is process a provided string and look for any tokens in the format
|
||||
* of `:name[=value]` and then convert it to a object and return.
|
||||
* An example of this is ':include :type=code :fragment=demo' is taken and
|
||||
* then converted to:
|
||||
*
|
||||
* ```
|
||||
* {
|
||||
* include: '',
|
||||
* type: 'code',
|
||||
* fragment: 'demo'
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {string} str The string to parse.
|
||||
*
|
||||
* @return {object} The original string and parsed object, { str, config }.
|
||||
*/
|
||||
export function getAndRemoveConfig(str = '') {
|
||||
const config = {};
|
||||
|
||||
@ -5,7 +25,7 @@ export function getAndRemoveConfig(str = '') {
|
||||
str = str
|
||||
.replace(/^'/, '')
|
||||
.replace(/'$/, '')
|
||||
.replace(/(?:^|\s):([\w-]+:?)=?([\w-]+)?/g, (m, key, value) => {
|
||||
.replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g, (m, key, value) => {
|
||||
if (key.indexOf(':') === -1) {
|
||||
config[key] = (value && value.replace(/"/g, '')) || true;
|
||||
return '';
|
||||
|
||||
@ -27,7 +27,12 @@ export class HTML5History extends History {
|
||||
if (el.tagName === 'A' && !/_blank/.test(el.target)) {
|
||||
e.preventDefault();
|
||||
const url = el.href;
|
||||
window.history.pushState({ key: url }, '', url);
|
||||
// solve history.pushState cross-origin issue
|
||||
if (this.config.crossOriginLinks.indexOf(url) !== -1) {
|
||||
window.open(url, '_self');
|
||||
} else {
|
||||
window.history.pushState({ key: url }, '', url);
|
||||
}
|
||||
cb({ event: e, source: 'navigate' });
|
||||
}
|
||||
});
|
||||
|
||||
@ -44,6 +44,10 @@ export const isAbsolutePath = cached(path => {
|
||||
return /(:|(\/{2}))/g.test(path);
|
||||
});
|
||||
|
||||
export const removeParams = cached(path => {
|
||||
return path.split(/[?#]/)[0];
|
||||
});
|
||||
|
||||
export const getParentPath = cached(path => {
|
||||
if (/\/$/g.test(path)) {
|
||||
return path;
|
||||
|
||||
3321
src/plugins/emoji.js
3321
src/plugins/emoji.js
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,14 @@
|
||||
import parser from './parser';
|
||||
|
||||
const install = function(hook, vm) {
|
||||
// Used to remove front matter from embedded pages if installed.
|
||||
vm.config.frontMatter = {};
|
||||
vm.config.frontMatter.installed = true;
|
||||
vm.config.frontMatter.parseMarkdown = function(content) {
|
||||
const { body } = parser(content);
|
||||
return body;
|
||||
};
|
||||
|
||||
hook.beforeEach(content => {
|
||||
const { attributes, body } = parser(content);
|
||||
|
||||
|
||||
@ -52,6 +52,7 @@ function style() {
|
||||
appearance: none;
|
||||
}
|
||||
.search .clear-button {
|
||||
cursor: pointer;
|
||||
width: 36px;
|
||||
text-align: right;
|
||||
display: none;
|
||||
@ -170,11 +171,20 @@ function bindEvents() {
|
||||
const $inputWrap = Docsify.dom.find($search, '.input-wrap');
|
||||
|
||||
let timeId;
|
||||
// Prevent to Fold sidebar
|
||||
|
||||
/**
|
||||
Prevent to Fold sidebar.
|
||||
|
||||
When searching on the mobile end,
|
||||
the sidebar is collapsed when you click the INPUT box,
|
||||
making it impossible to search.
|
||||
*/
|
||||
Docsify.dom.on(
|
||||
$search,
|
||||
'click',
|
||||
e => e.target.tagName !== 'A' && e.stopPropagation()
|
||||
e =>
|
||||
['A', 'H2', 'P', 'EM'].indexOf(e.target.tagName) === -1 &&
|
||||
e.stopPropagation()
|
||||
);
|
||||
Docsify.dom.on($input, 'input', e => {
|
||||
clearTimeout(timeId);
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import { getAndRemoveConfig } from '../../core/render/utils';
|
||||
|
||||
let INDEXS = {};
|
||||
|
||||
const LOCAL_STORAGE = {
|
||||
@ -25,10 +27,9 @@ function escapeHtml(string) {
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'/': '/',
|
||||
};
|
||||
|
||||
return String(string).replace(/[&<>"'/]/g, s => entityMap[s]);
|
||||
return String(string).replace(/[&<>"']/g, s => entityMap[s]);
|
||||
}
|
||||
|
||||
function getAllPaths(router) {
|
||||
@ -53,6 +54,17 @@ function getAllPaths(router) {
|
||||
return paths;
|
||||
}
|
||||
|
||||
function getTableData(token) {
|
||||
if (!token.text && token.type === 'table') {
|
||||
token.text = token.cells
|
||||
.map(function(rows) {
|
||||
return rows.join(' | ');
|
||||
})
|
||||
.join(' |\n ');
|
||||
}
|
||||
return token.text;
|
||||
}
|
||||
|
||||
function saveData(maxAge, expireKey, indexKey) {
|
||||
localStorage.setItem(expireKey, Date.now() + maxAge);
|
||||
localStorage.setItem(indexKey, JSON.stringify(INDEXS));
|
||||
@ -66,8 +78,15 @@ export function genIndex(path, content = '', router, depth) {
|
||||
|
||||
tokens.forEach(token => {
|
||||
if (token.type === 'heading' && token.depth <= depth) {
|
||||
slug = router.toURL(path, { id: slugify(token.text) });
|
||||
index[slug] = { slug, title: token.text, body: '' };
|
||||
const { str, config } = getAndRemoveConfig(token.text);
|
||||
|
||||
if (config.id) {
|
||||
slug = router.toURL(path, { id: slugify(config.id) });
|
||||
} else {
|
||||
slug = router.toURL(path, { id: slugify(escapeHtml(token.text)) });
|
||||
}
|
||||
|
||||
index[slug] = { slug, title: str, body: '' };
|
||||
} else {
|
||||
if (!slug) {
|
||||
return;
|
||||
@ -76,17 +95,11 @@ export function genIndex(path, content = '', router, depth) {
|
||||
if (!index[slug]) {
|
||||
index[slug] = { slug, title: '', body: '' };
|
||||
} else if (index[slug].body) {
|
||||
token.text = getTableData(token);
|
||||
|
||||
index[slug].body += '\n' + (token.text || '');
|
||||
} else {
|
||||
if (!token.text) {
|
||||
if (token.type === 'table') {
|
||||
token.text = token.cells
|
||||
.map(function(rows) {
|
||||
return rows.join(' | ');
|
||||
})
|
||||
.join(' |\n ');
|
||||
}
|
||||
}
|
||||
token.text = getTableData(token);
|
||||
|
||||
index[slug].body = index[slug].body
|
||||
? index[slug].body + token.text
|
||||
|
||||
@ -4,6 +4,7 @@ section.cover
|
||||
background-repeat no-repeat
|
||||
background-size cover
|
||||
height 100vh
|
||||
width 100vw
|
||||
display none
|
||||
|
||||
&.show
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
require = require('esm')(
|
||||
module /* , options */
|
||||
); /* eslint-disable-line no-global-assign */
|
||||
const { History } = require('../../src/core/router/history/base');
|
||||
const { expect } = require('chai');
|
||||
const { History } = require('../../src/core/router/history/base');
|
||||
|
||||
class MockHistory extends History {
|
||||
parse(path) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
const { init, expectSameDom } = require('../_helper');
|
||||
const { expect } = require('chai');
|
||||
const { init, expectSameDom } = require('../_helper');
|
||||
|
||||
describe('render', function() {
|
||||
it('important content (tips)', async function() {
|
||||
@ -14,88 +14,81 @@ describe('render', function() {
|
||||
it('as unordered task list', async function() {
|
||||
const { docsify } = await init();
|
||||
const output = docsify.compiler.compile(`
|
||||
- [x] Task 1
|
||||
- [ ] Task 2
|
||||
- [ ] Task 3`);
|
||||
- [x] Task 1
|
||||
- [ ] Task 2
|
||||
- [ ] Task 3`);
|
||||
expect(
|
||||
output,
|
||||
`<ul class="task-list">
|
||||
<li class="task-list-item"><label><input checked="" disabled="" type="checkbox"> Task 1</label></li>
|
||||
<li class="task-list-item"><label><input disabled="" type="checkbox"> Task 2</label></li>
|
||||
<li class="task-list-item"><label><input disabled="" type="checkbox"> Task 3</label></li>
|
||||
</ul>`
|
||||
<li class="task-list-item"><label><input checked="" disabled="" type="checkbox"> Task 1</label></li>
|
||||
<li class="task-list-item"><label><input disabled="" type="checkbox"> Task 2</label></li>
|
||||
<li class="task-list-item"><label><input disabled="" type="checkbox"> Task 3</label></li>
|
||||
</ul>`
|
||||
);
|
||||
});
|
||||
|
||||
it('as ordered task list', async function() {
|
||||
const { docsify } = await init();
|
||||
const output = docsify.compiler.compile(`
|
||||
1. [ ] Task 1
|
||||
2. [x] Task 2`);
|
||||
1. [ ] Task 1
|
||||
2. [x] Task 2`);
|
||||
expectSameDom(
|
||||
output,
|
||||
`<ol class="task-list">
|
||||
<li class="task-list-item"><label><input disabled="" type="checkbox"> Task 1</label></li>
|
||||
<li class="task-list-item"><label><input checked="" disabled="" type="checkbox"> Task 2</label></li>
|
||||
</ol>`
|
||||
<li class="task-list-item"><label><input disabled="" type="checkbox"> Task 1</label></li>
|
||||
<li class="task-list-item"><label><input checked="" disabled="" type="checkbox"> Task 2</label></li>
|
||||
</ol>`
|
||||
);
|
||||
});
|
||||
|
||||
it('normal unordered', async function() {
|
||||
const { docsify } = await init();
|
||||
const output = docsify.compiler.compile(`
|
||||
- [linktext](link)
|
||||
- just text`);
|
||||
- [linktext](link)
|
||||
- just text`);
|
||||
expectSameDom(
|
||||
output,
|
||||
`<ul >
|
||||
<li><a href="#/link" >linktext</a></li>
|
||||
<li>just text</li>
|
||||
</ul>`
|
||||
<li><a href="#/link" >linktext</a></li>
|
||||
<li>just text</li>
|
||||
</ul>`
|
||||
);
|
||||
});
|
||||
|
||||
it('unordered with custom start', async function() {
|
||||
const { docsify } = await init();
|
||||
const output = docsify.compiler.compile(`
|
||||
1. first
|
||||
2. second
|
||||
1. first
|
||||
2. second
|
||||
|
||||
text
|
||||
text
|
||||
|
||||
3. third`);
|
||||
3. third`);
|
||||
expectSameDom(
|
||||
output,
|
||||
`<ol >
|
||||
<li>first</li>
|
||||
<li>second</li>
|
||||
</ol>
|
||||
<p>text</p>
|
||||
<ol start="3">
|
||||
<li>third</li>
|
||||
</ol>`
|
||||
`<ol ><li><p>first</p></li><li><p>second</p><p>text</p></li><li><p>third</p></li></ol>`
|
||||
);
|
||||
});
|
||||
|
||||
it('nested', async function() {
|
||||
const { docsify } = await init();
|
||||
const output = docsify.compiler.compile(`
|
||||
- 1
|
||||
- 2
|
||||
- 2 a
|
||||
- 2 b
|
||||
- 3`);
|
||||
- 1
|
||||
- 2
|
||||
- 2 a
|
||||
- 2 b
|
||||
- 3`);
|
||||
expectSameDom(
|
||||
output,
|
||||
`<ul >
|
||||
<li>1</li>
|
||||
<li>2<ul >
|
||||
<li>2 a</li>
|
||||
<li>2 b</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>3</li>
|
||||
</ul>`
|
||||
<li>1</li>
|
||||
<li>2<ul >
|
||||
<li>2 a</li>
|
||||
<li>2 b</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>3</li>
|
||||
</ul>`
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -168,7 +161,7 @@ text
|
||||
|
||||
expectSameDom(
|
||||
output,
|
||||
'<p><img src="http://imageUrl" data-origin="http://imageUrl" alt="alt text" width="50" height="50" /></p>'
|
||||
'<p><img src="http://imageUrl" data-origin="http://imageUrl" alt="alt text" width="50" /></p>'
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -181,11 +174,11 @@ text
|
||||
expectSameDom(
|
||||
output,
|
||||
`
|
||||
<h1 id="h1-tag">
|
||||
<a href="#/?id=h1-tag" data-id="h1-tag" class="anchor">
|
||||
<span>h1 tag</span>
|
||||
</a>
|
||||
</h1>`
|
||||
<h1 id="h1-tag">
|
||||
<a href="#/?id=h1-tag" data-id="h1-tag" class="anchor">
|
||||
<span>h1 tag</span>
|
||||
</a>
|
||||
</h1>`
|
||||
);
|
||||
});
|
||||
|
||||
@ -195,11 +188,11 @@ text
|
||||
expectSameDom(
|
||||
output,
|
||||
`
|
||||
<h2 id="h2-tag">
|
||||
<a href="#/?id=h2-tag" data-id="h2-tag" class="anchor">
|
||||
<span>h2 tag</span>
|
||||
</a>
|
||||
</h2>`
|
||||
<h2 id="h2-tag">
|
||||
<a href="#/?id=h2-tag" data-id="h2-tag" class="anchor">
|
||||
<span>h2 tag</span>
|
||||
</a>
|
||||
</h2>`
|
||||
);
|
||||
});
|
||||
|
||||
@ -209,11 +202,11 @@ text
|
||||
expectSameDom(
|
||||
output,
|
||||
`
|
||||
<h3 id="h3-tag">
|
||||
<a href="#/?id=h3-tag" data-id="h3-tag" class="anchor">
|
||||
<span>h3 tag</span>
|
||||
</a>
|
||||
</h3>`
|
||||
<h3 id="h3-tag">
|
||||
<a href="#/?id=h3-tag" data-id="h3-tag" class="anchor">
|
||||
<span>h3 tag</span>
|
||||
</a>
|
||||
</h3>`
|
||||
);
|
||||
});
|
||||
|
||||
@ -223,11 +216,11 @@ text
|
||||
expectSameDom(
|
||||
output,
|
||||
`
|
||||
<h4 id="h4-tag">
|
||||
<a href="#/?id=h4-tag" data-id="h4-tag" class="anchor">
|
||||
<span>h4 tag</span>
|
||||
</a>
|
||||
</h4>`
|
||||
<h4 id="h4-tag">
|
||||
<a href="#/?id=h4-tag" data-id="h4-tag" class="anchor">
|
||||
<span>h4 tag</span>
|
||||
</a>
|
||||
</h4>`
|
||||
);
|
||||
});
|
||||
|
||||
@ -237,11 +230,11 @@ text
|
||||
expectSameDom(
|
||||
output,
|
||||
`
|
||||
<h5 id="h5-tag">
|
||||
<a href="#/?id=h5-tag" data-id="h5-tag" class="anchor">
|
||||
<span>h5 tag</span>
|
||||
</a>
|
||||
</h5>`
|
||||
<h5 id="h5-tag">
|
||||
<a href="#/?id=h5-tag" data-id="h5-tag" class="anchor">
|
||||
<span>h5 tag</span>
|
||||
</a>
|
||||
</h5>`
|
||||
);
|
||||
});
|
||||
|
||||
@ -251,11 +244,11 @@ text
|
||||
expectSameDom(
|
||||
output,
|
||||
`
|
||||
<h6 id="h6-tag">
|
||||
<a href="#/?id=h6-tag" data-id="h6-tag" class="anchor">
|
||||
<span>h6 tag</span>
|
||||
</a>
|
||||
</h6>`
|
||||
<h6 id="h6-tag">
|
||||
<a href="#/?id=h6-tag" data-id="h6-tag" class="anchor">
|
||||
<span>h6 tag</span>
|
||||
</a>
|
||||
</h6>`
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -267,7 +260,22 @@ text
|
||||
|
||||
expectSameDom(
|
||||
output,
|
||||
'<p><a href="http://url" target="_blank">alt text</a></p>'
|
||||
'<p><a href="http://url" target="_blank" rel="noopener">alt text</a></p>'
|
||||
);
|
||||
});
|
||||
|
||||
it('linkrel', async function() {
|
||||
const { docsify } = await init('default', {
|
||||
externalLinkTarget: '_blank',
|
||||
externalLinkRel: 'noopener',
|
||||
});
|
||||
const output = docsify.compiler.compile(
|
||||
'[alt text](http://www.example.com)'
|
||||
);
|
||||
|
||||
expectSameDom(
|
||||
output,
|
||||
'<p><a href="http://www.example.com" target="_blank" rel="noopener">alt text</a></p>'
|
||||
);
|
||||
});
|
||||
|
||||
@ -279,7 +287,7 @@ text
|
||||
|
||||
expectSameDom(
|
||||
output,
|
||||
'<p><a href="javascript:void(0)" target="_blank" disabled>alt text</a></p>'
|
||||
'<p><a href="javascript:void(0)" target="_blank" rel="noopener" disabled>alt text</a></p>'
|
||||
);
|
||||
});
|
||||
|
||||
@ -291,7 +299,7 @@ text
|
||||
|
||||
expectSameDom(
|
||||
output,
|
||||
'<p><a href="http://url" target="_blank" target="_self">alt text</a></p>'
|
||||
'<p><a href="http://url" target="_self" >alt text</a></p>'
|
||||
);
|
||||
});
|
||||
|
||||
@ -303,7 +311,7 @@ text
|
||||
|
||||
expectSameDom(
|
||||
output,
|
||||
'<p><a href="http://url" target="_blank" class="someCssClass">alt text</a></p>'
|
||||
'<p><a href="http://url" target="_blank" rel="noopener" class="someCssClass">alt text</a></p>'
|
||||
);
|
||||
});
|
||||
|
||||
@ -315,7 +323,7 @@ text
|
||||
|
||||
expectSameDom(
|
||||
output,
|
||||
'<p><a href="http://url" target="_blank" id="someCssID">alt text</a></p>'
|
||||
'<p><a href="http://url" target="_blank" rel="noopener" id="someCssID">alt text</a></p>'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
require = require('esm')(
|
||||
module /* , options */
|
||||
); /* eslint-disable-line no-global-assign */
|
||||
const { resolvePath } = require('../../src/core/router/util');
|
||||
const { expect } = require('chai');
|
||||
const { resolvePath } = require('../../src/core/router/util');
|
||||
|
||||
describe('router/util', function() {
|
||||
it('resolvePath', async function() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user