Merge branch 'develop' into update-config

This commit is contained in:
James George 2020-06-10 13:48:53 +05:30 committed by GitHub
commit 7f835b15e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 2122 additions and 1655 deletions

4
.codesandbox/ci.json Normal file
View File

@ -0,0 +1,4 @@
{
"sandboxes": ["2d17z"],
"packages": [".", "packages/docsify-server-renderer"]
}

4
.github/semantic.yml vendored Normal file
View File

@ -0,0 +1,4 @@
titleAndCommits: true
allowMergeCommits: true
allowRevertCommits: true
anyCommit: true

View File

@ -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 />

View File

@ -0,0 +1,6 @@
---
author: John Smith
date: 2020-1-1
---
> This is from the `example.md`

View File

@ -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
};
```
```

View File

@ -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.

View File

@ -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

View File

@ -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'

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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);

View File

@ -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>

View File

@ -32,6 +32,7 @@ export default function() {
externalLinkRel: 'noopener',
routerMode: 'hash',
noCompileLinks: [],
crossOriginLinks: [],
relativePath: false,
topMargin: 0,
},

View File

@ -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', () => {

View File

@ -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');

View File

@ -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 = {

View File

@ -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 });

View File

@ -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}"`);
}
}

View File

@ -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) {

View File

@ -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;

View File

@ -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__')
)

View File

@ -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

View File

@ -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(/&quot;/g, '')) || true;
return '';

View File

@ -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' });
}
});

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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);

View File

@ -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) {
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
};
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

View File

@ -4,6 +4,7 @@ section.cover
background-repeat no-repeat
background-size cover
height 100vh
width 100vw
display none
&.show

View File

@ -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) {

View File

@ -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>'
);
});
});

View File

@ -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() {