Compare commits

..
51 changed files with 138 additions and 1803 deletions
+2
View File
@@ -0,0 +1,2 @@
<!-- Love docsify? Please consider supporting our collective:
👉 https://opencollective.com/docsify/donate -->
-37
View File
@@ -1,37 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
<!-- Please don't delete this template or we'll close your issue -->
<!-- Please use English language -->
<!-- Before creating an issue please make sure you are using the latest version of Docsify. -->
<!-- Please ask questions on StackOverflow: https://stackoverflow.com/questions/ask?tags=docsify -->
## Bug Report
#### Steps to reproduce
#### What is current behaviour
#### What is the expected behaviour
---
- [ ] Bug does still occur when all/other plugins are disabled?
<!-- Please type in your environment -->
Environment:
```
docsify version:
docsify plugins:
browser:
```
<!-- Love docsify? Please consider supporting our collective:
👉 https://opencollective.com/docsify/donate -->
-25
View File
@@ -1,25 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
<!-- Please don't delete this template or we'll close your issue -->
<!-- Please use English language -->
<!-- Before creating an issue please make sure you are using the latest version of Docsify. -->
<!-- Please ask questions on StackOverflow 👉 https://stackoverflow.com/questions/ask?tags=docsify -->
## Feature request
#### What problem does this feature solve?
#### What does the proposed API look like?
#### How should this be implemented in your opinion?
#### Are you willing to work on this yourself?
+3 -52
View File
@@ -1,54 +1,5 @@
<!-- Please use English language --> Please makes sure these boxes are checked before submitting your PR, thank you!
<!-- Please don't delete this template -->
<!-- PULL REQUEST TEMPLATE -->
<!-- (Update "[ ]" to "[x]" to check a box) -->
**Summary**
**What kind of change does this PR introduce?** (check at least one)
- [ ] Bugfix
- [ ] Feature
- [ ] Code style update
- [ ] Refactor
- [ ] Docs
- [ ] Build-related changes
- [ ] Other, please describe:
If changing the UI of default theme, please provide the **before/after** screenshot:
**Does this PR introduce a breaking change?** (check one)
- [ ] Yes
- [ ] No
If yes, please describe the impact and migration path for existing applications:
**The PR fulfills these requirements:**
- [ ] When resolving a specific issue, it's referenced in the PR's title (e.g. `fix #xxx[,#xxx]`, where "xxx" is the issue number)
You have tested in the following browsers: (Providing a detailed version will be better.)
- [ ] Chrome
- [ ] Firefox
- [ ] Safari
- [ ] Edge
- [ ] IE
If adding a **new feature**, the PR's description includes:
- [ ] A convincing reason for adding this feature
- [ ] Related documents have been updated
- [ ] Related tests have been updated
To avoid wasting your time, it's best to open a **feature request issue** first and wait for approval before working on it.
**Other information:**
---
* [ ] Make sure you are merging your commits to `master` branch.
* [ ] Add some descriptions and refer relative issues for you PR.
* [ ] DO NOT include files inside `lib` directory. * [ ] DO NOT include files inside `lib` directory.
-28
View File
@@ -1,31 +1,3 @@
<a name="4.9.1"></a>
## [4.9.1](https://github.com/docsifyjs/docsify/compare/v4.9.0...v4.9.1) (2019-02-21)
### Bug Fixes
* github assets url ([#774](https://github.com/docsifyjs/docsify/issues/774)) ([140bf10](https://github.com/docsifyjs/docsify/commit/140bf10))
<a name="4.9.0"></a>
# [4.9.0](https://github.com/docsifyjs/docsify/compare/v4.8.6...v4.9.0) (2019-02-19)
### Bug Fixes
* task list rendering (Fix [#749](https://github.com/docsifyjs/docsify/issues/749)) ([#757](https://github.com/docsifyjs/docsify/issues/757)) ([69ef489](https://github.com/docsifyjs/docsify/commit/69ef489))
* upgrade npm-run-all ([049726e](https://github.com/docsifyjs/docsify/commit/049726e))
### Features
* **search-plugin:** add namespace option ([#706](https://github.com/docsifyjs/docsify/issues/706)) ([28beff8](https://github.com/docsifyjs/docsify/commit/28beff8))
* Add new theme "dolphin" ([#735](https://github.com/docsifyjs/docsify/issues/735)) ([c3345ba](https://github.com/docsifyjs/docsify/commit/c3345ba))
* Provide code fragments feature ([#748](https://github.com/docsifyjs/docsify/issues/748)) ([1447c8a](https://github.com/docsifyjs/docsify/commit/1447c8a))
<a name="4.8.6"></a> <a name="4.8.6"></a>
## [4.8.6](https://github.com/docsifyjs/docsify/compare/v4.8.5...v4.8.6) (2018-11-12) ## [4.8.6](https://github.com/docsifyjs/docsify/compare/v4.8.5...v4.8.6) (2018-11-12)
+1 -1
View File
@@ -1,6 +1,6 @@
![logo](_media/icon.svg) ![logo](_media/icon.svg)
# docsify <small>4.9.1</small> # docsify <small>4.8.6</small>
> A magical documentation site generator. > A magical documentation site generator.
-16
View File
@@ -1,16 +0,0 @@
import fetch from 'fetch'
const URL = 'https://example.com'
const PORT = 8080
/// [demo]
const result = fetch(`${URL}:${PORT}`)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(JSON.stringify(myJson));
});
/// [demo]
result.then(console.log).catch(console.error)
-40
View File
@@ -150,46 +150,6 @@ window.$docsify = {
}; };
``` ```
## relativePath
- Type: `Boolean`
- Default: `false`
If **true** links are relative to the current context.
For example, the directory structure is as follows:
```text
.
└── docs
├── README.md
├── guide.md
└── zh-cn
├── README.md
├── guide.md
└── config
└── example.md
```
With relative path **enabled** and current URL `http://domain.com/zh-cn/README`, given links will resolve to:
```text
guide.md => http://domain.com/zh-cn/guide
config/example.md => http://domain.com/zh-cn/config/example
../README.md => http://domain.com/README
/README.md => http://domain.com/README
```
```js
window.$docsify = {
// Relative path enabled
relativePath: true,
// Relative path disabled (default value)
relativePath: false
};
```
## coverpage ## coverpage
- Type: `Boolean|String|String[]|Object` - Type: `Boolean|String|String[]|Object`
-42
View File
@@ -87,45 +87,3 @@ When using the HTML5 router, you need to set up redirect rules that redirect all
```sh ```sh
/* /index.html 200 /* /index.html 200
``` ```
## AWS Amplify
1. Set the routerMode in the Docsify project `index.html` to *history* mode.
```html
<script>
window.$docsify = {
loadSidebar: true,
routerMode: 'history'
}
</script>
```
2. Login to your [AWS Console](https://aws.amazon.com).
3. Go to the [AWS Amplify Dashboard](https://aws.amazon.com/amplify).
4. Choose the **Deploy** route to setup your project.
5. When prompted, keep the build settings empty if you're serving your docs within the root directory. If you're serving your docs from a different directory, customise your amplify.yml
```yml
version: 0.1
frontend:
phases:
build:
commands:
- echo "Nothing to build"
artifacts:
baseDirectory: /docs
files:
- '**/*'
cache:
paths: []
```
6. Add the following Redirect rules in their displayed order.
| Source address | Target address | Type |
|----------------|----------------|---------------|
| /<*>.md | /<*>.md | 200 (Rewrite) |
| /<*> | /index.html | 200 (Rewrite) |
-15
View File
@@ -39,21 +39,6 @@ You will get it
[filename](_media/example.md ':include :type=code') [filename](_media/example.md ':include :type=code')
## 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
[filename](_media/example.js ':include :type=code :fragment=demo')
```
In your code file you need to surround the fragment between `/// [demo]` lines (before and after the fragment).
Alternatively you can use `### [demo]`.
Example:
[filename](_media/example.js ':include :type=code :fragment=demo')
## Tag attribute ## Tag attribute
If you embed the file as `iframe`, `audio` and `video`, then you may need to set the attributes of these tags. If you embed the file as `iframe`, `audio` and `video`, then you may need to set the attributes of these tags.
-10
View File
@@ -72,16 +72,6 @@ You can specify `alias` to avoid unnecessary fallback.
!> You can create a `README.md` file in a subdirectory to use it as the landing page for the route. !> You can create a `README.md` file in a subdirectory to use it as the landing page for the route.
## Set Page Titles from Sidebar Selection
A page's `title` tag is generated from the _selected_ sidebar item name. For better SEO, you can customize the title by specifying a string after the filename.
```markdown
<!-- docs/_sidebar.md -->
* [Home](/)
* [Guide](guide.md "The greatest guide in the world")
```
## Table of Contents ## Table of Contents
Once you've created `_sidebar.md`, the sidebar content is automatically generated based on the headers in the markdown files. Once you've created `_sidebar.md`, the sidebar content is automatically generated based on the headers in the markdown files.
+1 -1
View File
@@ -111,7 +111,7 @@ var readFileSync = require('fs').readFileSync
// init // init
var renderer = new Renderer({ var renderer = new Renderer({
template: readFileSync('./docs/index.template.html', 'utf-8'), template: readFileSync('./docs/index.template.html', 'utf-8').,
config: { config: {
name: 'docsify', name: 'docsify',
repo: 'docsifyjs/docsify' repo: 'docsifyjs/docsify'
+1 -1
View File
@@ -79,7 +79,7 @@ window.$docsify = {
function(hook, vm) { function(hook, vm) {
hook.beforeEach(function(html) { hook.beforeEach(function(html) {
var url = var url =
'https://github.com/docsifyjs/docsify/blob/master/docs/' + 'https://github.com/docsifyjs/docsify/blob/master/docs' +
vm.route.file; vm.route.file;
var editHtml = '[📝 EDIT DOCUMENT](' + url + ')\n'; var editHtml = '[📝 EDIT DOCUMENT](' + url + ')\n';
+7 -40
View File
@@ -3157,7 +3157,7 @@ slugify.clear = function () {
}; };
function replace(m, $1) { function replace(m, $1) {
return '<img class="emoji" src="https://github.githubassets.com/images/icons/emoji/' + $1 + '.png" alt="' + $1 + '" />' return '<img class="emoji" src="https://assets-cdn.github.com/images/icons/emoji/' + $1 + '.png" alt="' + $1 + '" />'
} }
function emojify(text) { function emojify(text) {
@@ -3335,7 +3335,7 @@ function getAndRemoveConfig(str) {
str = str str = str
.replace(/^'/, '') .replace(/^'/, '')
.replace(/'$/, '') .replace(/'$/, '')
.replace(/(?:^|\s):([\w-]+)=?([\w-]+)?/g, function (m, key, value) { .replace(/:([\w-]+)=?([\w-]+)?/g, function (m, key, value) {
config[key] = (value && value.replace(/&quot;/g, '')) || true; config[key] = (value && value.replace(/&quot;/g, '')) || true;
return '' return ''
}) })
@@ -3483,7 +3483,6 @@ Compiler.prototype.compileEmbed = function compileEmbed (href, title) {
embed = compileMedia[type].call(this, href, title); embed = compileMedia[type].call(this, href, title);
embed.type = type; embed.type = type;
} }
embed.fragment = config.fragment;
return embed return embed
} }
@@ -3634,23 +3633,6 @@ Compiler.prototype._initRenderer = function _initRenderer () {
return ("<img src=\"" + url + "\"data-origin=\"" + href + "\" alt=\"" + text + "\"" + attrs + ">") return ("<img src=\"" + url + "\"data-origin=\"" + href + "\" alt=\"" + text + "\"" + attrs + ">")
}; };
origin.list = renderer.list = function (body, ordered, start) {
var isTaskList = /<li class="task-list-item">/.test(body.split('class="task-list"')[0]);
var isStartReq = start && start > 1;
var tag = ordered ? 'ol' : 'ul';
var tagAttrs = [
(isTaskList ? 'class="task-list"' : ''),
(isStartReq ? ("start=\"" + start + "\"") : '')
].join(' ').trim();
return ("<" + tag + " " + tagAttrs + ">" + body + "</" + tag + ">")
};
origin.listitem = renderer.listitem = function (text) {
var isTaskItem = /^(<input.*type="checkbox"[^>]*>)/.test(text);
var html = isTaskItem ? ("<li class=\"task-list-item\"><label>" + text + "</label></li>") : ("<li>" + text + "</li>");
return html
};
renderer.origin = origin; renderer.origin = origin;
@@ -3726,9 +3708,6 @@ function btn(el) {
var toggle = function (_) { return body.classList.toggle('close'); }; var toggle = function (_) { return body.classList.toggle('close'); };
el = getNode(el); el = getNode(el);
if (el == null) {
return
}
on(el, 'click', function (e) { on(el, 'click', function (e) {
e.stopPropagation(); e.stopPropagation();
toggle(); toggle();
@@ -3744,9 +3723,7 @@ function btn(el) {
function collapse(el) { function collapse(el) {
el = getNode(el); el = getNode(el);
if (el == null) {
return
}
on(el, 'click', function (ref) { on(el, 'click', function (ref) {
var target = ref.target; var target = ref.target;
@@ -3784,10 +3761,8 @@ function sticky() {
*/ */
function getAndActive(router, el, isParent, autoTitle) { function getAndActive(router, el, isParent, autoTitle) {
el = getNode(el); el = getNode(el);
var links = [];
if (el != null) { var links = findAll(el, 'a');
links = findAll(el, 'a');
}
var hash = decodeURI(router.toURL(router.getCurrentPath())); var hash = decodeURI(router.toURL(router.getCurrentPath()));
var target; var target;
@@ -3990,10 +3965,7 @@ function scrollActiveSidebar(router) {
coverHeight = cover ? cover.offsetHeight : 0; coverHeight = cover ? cover.offsetHeight : 0;
var sidebar = getNode('.sidebar'); var sidebar = getNode('.sidebar');
var lis = []; var lis = findAll(sidebar, 'li');
if (sidebar != null) {
lis = findAll(sidebar, 'li');
}
for (var i = 0, len = lis.length; i < len; i += 1) { for (var i = 0, len = lis.length; i < len; i += 1) {
var li = lis[i]; var li = lis[i];
@@ -4077,11 +4049,6 @@ function walkFetchEmbed(ref, cb) {
if (token.embed.type === 'markdown') { if (token.embed.type === 'markdown') {
embedToken = compile.lexer(text); embedToken = compile.lexer(text);
} else if (token.embed.type === 'code') { } else if (token.embed.type === 'code') {
if (token.embed.fragment) {
var fragment = token.embed.fragment;
var pattern = new RegExp(("(?:###|\\/\\/\\/)\\s*\\[" + fragment + "\\]([\\s\\S]*)(?:###|\\/\\/\\/)\\s*\\[" + fragment + "\\]"));
text = ((text.match(pattern) || [])[1] || '').trim();
}
embedToken = compile.lexer( embedToken = compile.lexer(
'```' + '```' +
token.embed.lang + token.embed.lang +
@@ -5046,7 +5013,7 @@ function initGlobalAPI () {
dom: dom, dom: dom,
get: get, get: get,
slugify: slugify, slugify: slugify,
version: '4.9.1' version: '4.8.6'
}; };
window.DocsifyCompiler = Compiler; window.DocsifyCompiler = Compiler;
window.marked = marked; window.marked = marked;
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -893,7 +893,7 @@ var AllGithubEmoji = [
window.emojify = function (match, $1) { window.emojify = function (match, $1) {
return AllGithubEmoji.indexOf($1) === -1 ? return AllGithubEmoji.indexOf($1) === -1 ?
match : match :
'<img class="emoji" src="https://github.githubassets.com/images/icons/emoji/' + '<img class="emoji" src="https://assets-cdn.github.com/images/icons/emoji/' +
$1 + $1 +
'.png" alt="' + '.png" alt="' +
$1 + $1 +
+1 -1
View File
File diff suppressed because one or more lines are too long
+7 -25
View File
@@ -1,18 +1,6 @@
(function () { (function () {
var INDEXS = {}; var INDEXS = {};
var LOCAL_STORAGE = {
EXPIRE_KEY: 'docsify.search.expires',
INDEX_KEY: 'docsify.search.index'
};
function resolveExpireKey(namespace) {
return namespace ? ((LOCAL_STORAGE.EXPIRE_KEY) + "/" + namespace) : LOCAL_STORAGE.EXPIRE_KEY
}
function resolveIndexKey(namespace) {
return namespace ? ((LOCAL_STORAGE.INDEX_KEY) + "/" + namespace) : LOCAL_STORAGE.INDEX_KEY
}
function escapeHtml(string) { function escapeHtml(string) {
var entityMap = { var entityMap = {
'&': '&amp;', '&': '&amp;',
@@ -46,9 +34,9 @@ function getAllPaths(router) {
return paths return paths
} }
function saveData(maxAge, expireKey, indexKey) { function saveData(maxAge) {
localStorage.setItem(expireKey, Date.now() + maxAge); localStorage.setItem('docsify.search.expires', Date.now() + maxAge);
localStorage.setItem(indexKey, JSON.stringify(INDEXS)); localStorage.setItem('docsify.search.index', JSON.stringify(INDEXS));
} }
function genIndex(path, content, router, depth) { function genIndex(path, content, router, depth) {
@@ -166,13 +154,9 @@ function search(query) {
function init$1(config, vm) { function init$1(config, vm) {
var isAuto = config.paths === 'auto'; var isAuto = config.paths === 'auto';
var isExpired = localStorage.getItem('docsify.search.expires') < Date.now();
var expireKey = resolveExpireKey(config.namespace); INDEXS = JSON.parse(localStorage.getItem('docsify.search.index'));
var indexKey = resolveIndexKey(config.namespace);
var isExpired = localStorage.getItem(expireKey) < Date.now();
INDEXS = JSON.parse(localStorage.getItem(indexKey));
if (isExpired) { if (isExpired) {
INDEXS = {}; INDEXS = {};
@@ -193,7 +177,7 @@ function init$1(config, vm) {
.get(vm.router.getFile(path), false, vm.config.requestHeaders) .get(vm.router.getFile(path), false, vm.config.requestHeaders)
.then(function (result) { .then(function (result) {
INDEXS[path] = genIndex(path, result, vm.router, config.depth); INDEXS[path] = genIndex(path, result, vm.router, config.depth);
len === ++count && saveData(config.maxAge, expireKey, indexKey); len === ++count && saveData(config.maxAge);
}); });
}); });
} }
@@ -327,8 +311,7 @@ var CONFIG = {
paths: 'auto', paths: 'auto',
depth: 2, depth: 2,
maxAge: 86400000, // 1 day maxAge: 86400000, // 1 day
hideOtherSidebarContent: false, hideOtherSidebarContent: false
namespace: undefined
}; };
var install = function (hook, vm) { var install = function (hook, vm) {
@@ -344,7 +327,6 @@ var install = function (hook, vm) {
CONFIG.noData = opts.noData || CONFIG.noData; CONFIG.noData = opts.noData || CONFIG.noData;
CONFIG.depth = opts.depth || CONFIG.depth; CONFIG.depth = opts.depth || CONFIG.depth;
CONFIG.hideOtherSidebarContent = opts.hideOtherSidebarContent || CONFIG.hideOtherSidebarContent; CONFIG.hideOtherSidebarContent = opts.hideOtherSidebarContent || CONFIG.hideOtherSidebarContent;
CONFIG.namespace = opts.namespace || CONFIG.namespace;
} }
var isAuto = CONFIG.paths === 'auto'; var isAuto = CONFIG.paths === 'auto';
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -811
View File
File diff suppressed because it is too large Load Diff
+2 -6
View File
@@ -1,6 +1,6 @@
{ {
"name": "docsify", "name": "docsify",
"version": "4.9.1", "version": "4.8.6",
"description": "A magical documentation generator.", "description": "A magical documentation generator.",
"author": { "author": {
"name": "qingwei-li", "name": "qingwei-li",
@@ -27,7 +27,7 @@
"dev": "run-p serve watch:*", "dev": "run-p serve watch:*",
"dev:ssr": "run-p serve:ssr watch:*", "dev:ssr": "run-p serve:ssr watch:*",
"lint": "eslint {src,packages} --fix", "lint": "eslint {src,packages} --fix",
"test": "mocha test/*/**", "test": "run-p lint",
"css": "stylus src/themes/*.styl -u autoprefixer-stylus", "css": "stylus src/themes/*.styl -u autoprefixer-stylus",
"watch:css": "run-p 'css -- -o themes -w'", "watch:css": "run-p 'css -- -o themes -w'",
"watch:js": "node build/build.js", "watch:js": "node build/build.js",
@@ -51,18 +51,14 @@
}, },
"devDependencies": { "devDependencies": {
"autoprefixer-stylus": "^0.14.0", "autoprefixer-stylus": "^0.14.0",
"chai": "^4.2.0",
"chokidar": "^2.0.2", "chokidar": "^2.0.2",
"conventional-changelog-cli": "^1.3.5", "conventional-changelog-cli": "^1.3.5",
"cross-env": "^5.1.3", "cross-env": "^5.1.3",
"cssnano": "^3.10.0", "cssnano": "^3.10.0",
"eslint": "^4.14.0", "eslint": "^4.14.0",
"eslint-config-xo-space": "^0.18.0", "eslint-config-xo-space": "^0.18.0",
"esm": "^3.1.4",
"jsdom": "^13.2.0",
"lerna": "^2.5.1", "lerna": "^2.5.1",
"live-server": "^1.2.1", "live-server": "^1.2.1",
"mocha": "^5.2.0",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"rimraf": "^2.6.2", "rimraf": "^2.6.2",
"rollup": "^0.53.3", "rollup": "^0.53.3",
+1 -1
View File
@@ -37,5 +37,5 @@
"integrity": "sha1-6DWIAbhrg7F1YNTjw4LXrvIQCUQ=" "integrity": "sha1-6DWIAbhrg7F1YNTjw4LXrvIQCUQ="
} }
}, },
"version": "4.9.1" "version": "4.8.6"
} }
@@ -1,6 +1,6 @@
{ {
"name": "docsify-server-renderer", "name": "docsify-server-renderer",
"version": "4.9.1", "version": "4.8.6",
"description": "docsify server renderer", "description": "docsify server renderer",
"author": { "author": {
"name": "qingwei-li", "name": "qingwei-li",
+1 -2
View File
@@ -25,8 +25,7 @@ export default function () {
formatUpdated: '', formatUpdated: '',
externalLinkTarget: '_blank', externalLinkTarget: '_blank',
routerMode: 'hash', routerMode: 'hash',
noCompileLinks: [], noCompileLinks: []
relativePath: false
}, },
window.$docsify window.$docsify
) )
+25 -4
View File
@@ -1,5 +1,6 @@
import {isMobile} from '../util/env' import {isMobile} from '../util/env'
import * as dom from '../util/dom' import * as dom from '../util/dom'
import image from '../util/image'
import Tweezer from 'tweezer.js' import Tweezer from 'tweezer.js'
const nav = {} const nav = {}
@@ -87,10 +88,7 @@ export function scrollActiveSidebar(router) {
coverHeight = cover ? cover.offsetHeight : 0 coverHeight = cover ? cover.offsetHeight : 0
const sidebar = dom.getNode('.sidebar') const sidebar = dom.getNode('.sidebar')
let lis = [] const lis = dom.findAll(sidebar, 'li')
if (sidebar != null) {
lis = dom.findAll(sidebar, 'li')
}
for (let i = 0, len = lis.length; i < len; i += 1) { for (let i = 0, len = lis.length; i < len; i += 1) {
const li = lis[i] const li = lis[i]
@@ -126,11 +124,34 @@ export function scrollActiveSidebar(router) {
}) })
} }
export let pausedScrollToView
export function proceedScrollToView() {
if (pausedScrollToView) {
const copy = pausedScrollToView.slice()
pausedScrollToView = undefined
scrollIntoView(...copy)
}
image.unsubscribe(proceedScrollToView)
}
export function scrollIntoView(path, id) { export function scrollIntoView(path, id) {
if (!id) { if (!id) {
return return
} }
if (pausedScrollToView) {
pausedScrollToView = [path, id]
return
}
if (!image.isAllImagesComplete()) {
pausedScrollToView = [path, id]
image.subscribe(proceedScrollToView)
return
}
const section = dom.find('#' + id) const section = dom.find('#' + id)
section && scrollTo(section) section && scrollTo(section)
+3 -10
View File
@@ -9,9 +9,6 @@ export function btn(el) {
const toggle = _ => dom.body.classList.toggle('close') const toggle = _ => dom.body.classList.toggle('close')
el = dom.getNode(el) el = dom.getNode(el)
if (el == null) {
return
}
dom.on(el, 'click', e => { dom.on(el, 'click', e => {
e.stopPropagation() e.stopPropagation()
toggle() toggle()
@@ -27,9 +24,7 @@ export function btn(el) {
export function collapse(el) { export function collapse(el) {
el = dom.getNode(el) el = dom.getNode(el)
if (el == null) {
return
}
dom.on(el, 'click', ({target}) => { dom.on(el, 'click', ({target}) => {
if ( if (
target.nodeName === 'A' && target.nodeName === 'A' &&
@@ -65,10 +60,8 @@ export function sticky() {
*/ */
export function getAndActive(router, el, isParent, autoTitle) { export function getAndActive(router, el, isParent, autoTitle) {
el = dom.getNode(el) el = dom.getNode(el)
let links = []
if (el != null) { const links = dom.findAll(el, 'a')
links = dom.findAll(el, 'a')
}
const hash = decodeURI(router.toURL(router.getCurrentPath())) const hash = decodeURI(router.toURL(router.getCurrentPath()))
let target let target
+3 -18
View File
@@ -6,6 +6,7 @@ import {slugify} from './slugify'
import {emojify} from './emojify' import {emojify} from './emojify'
import {isAbsolutePath, getPath, getParentPath} from '../router/util' import {isAbsolutePath, getPath, getParentPath} from '../router/util'
import {isFn, merge, cached, isPrimitive} from '../util/core' import {isFn, merge, cached, isPrimitive} from '../util/core'
import image from '../util/image'
// See https://github.com/PrismJS/prism/pull/1367 // See https://github.com/PrismJS/prism/pull/1367
import 'prismjs/components/prism-markup-templating' import 'prismjs/components/prism-markup-templating'
@@ -164,7 +165,6 @@ export class Compiler {
embed = compileMedia[type].call(this, href, title) embed = compileMedia[type].call(this, href, title)
embed.type = type embed.type = type
} }
embed.fragment = config.fragment
return embed return embed
} }
@@ -300,24 +300,9 @@ export class Compiler {
url = getPath(contentBase, getParentPath(router.getCurrentPath()), href) url = getPath(contentBase, getParentPath(router.getCurrentPath()), href)
} }
return `<img src="${url}"data-origin="${href}" alt="${text}"${attrs}>` image.increaseLoadingImageCount()
}
origin.list = renderer.list = function (body, ordered, start) {
const isTaskList = /<li class="task-list-item">/.test(body.split('class="task-list"')[0])
const isStartReq = start && start > 1
const tag = ordered ? 'ol' : 'ul'
const tagAttrs = [
(isTaskList ? 'class="task-list"' : ''),
(isStartReq ? `start="${start}"` : '')
].join(' ').trim()
return `<${tag} ${tagAttrs}>${body}</${tag}>` return `<img src="${url}" data-origin="${href}" alt="${text}" onload="javascript:Docsify.util.image.onLoad(this)" onerror="javascript:Docsify.util.image.onError(this)"${attrs}>`
}
origin.listitem = renderer.listitem = function (text) {
const isTaskItem = /^(<input.*type="checkbox"[^>]*>)/.test(text)
const html = isTaskItem ? `<li class="task-list-item"><label>${text}</label></li>` : `<li>${text}</li>`
return html
} }
renderer.origin = origin renderer.origin = origin
-5
View File
@@ -20,11 +20,6 @@ function walkFetchEmbed({embedTokens, compile, fetch}, cb) {
if (token.embed.type === 'markdown') { if (token.embed.type === 'markdown') {
embedToken = compile.lexer(text) embedToken = compile.lexer(text)
} else if (token.embed.type === 'code') { } else if (token.embed.type === 'code') {
if (token.embed.fragment) {
const fragment = token.embed.fragment
const pattern = new RegExp(`(?:###|\\/\\/\\/)\\s*\\[${fragment}\\]([\\s\\S]*)(?:###|\\/\\/\\/)\\s*\\[${fragment}\\]`)
text = ((text.match(pattern) || [])[1] || '').trim()
}
embedToken = compile.lexer( embedToken = compile.lexer(
'```' + '```' +
token.embed.lang + token.embed.lang +
+1 -1
View File
@@ -1,7 +1,7 @@
import {inBrowser} from '../util/env' import {inBrowser} from '../util/env'
function replace(m, $1) { function replace(m, $1) {
return '<img class="emoji" src="https://github.githubassets.com/images/icons/emoji/' + $1 + '.png" alt="' + $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) {
+2 -7
View File
@@ -3,8 +3,7 @@ import {
isAbsolutePath, isAbsolutePath,
stringifyQuery, stringifyQuery,
cleanPath, cleanPath,
replaceSlug, replaceSlug
resolvePath
} from '../util' } from '../util'
import {noop, merge} from '../../util/core' import {noop, merge} from '../../util/core'
@@ -74,13 +73,9 @@ export class History {
if (local) { if (local) {
const idIndex = currentRoute.indexOf('?') const idIndex = currentRoute.indexOf('?')
path = path =
(idIndex > 0 ? currentRoute.substring(0, idIndex) : currentRoute) + path (idIndex > 0 ? currentRoute.substr(0, idIndex) : currentRoute) + path
} }
if (this.config.relativePath && path.indexOf('/') !== 0) {
const currentDir = currentRoute.substring(0, currentRoute.lastIndexOf('/') + 1)
return cleanPath(resolvePath(currentDir + path))
}
return cleanPath('/' + path) return cleanPath('/' + path)
} }
} }
-14
View File
@@ -53,20 +53,6 @@ export const cleanPath = cached(path => {
return path.replace(/^\/+/, '/').replace(/([^:])\/{2,}/g, '$1/') return path.replace(/^\/+/, '/').replace(/([^:])\/{2,}/g, '$1/')
}) })
export const resolvePath = cached(path => {
const segments = path.replace(/^\//, '').split('/')
let resolved = []
for (let i = 0, len = segments.length; i < len; i++) {
const segment = segments[i]
if (segment === '..') {
resolved.pop()
} else if (segment !== '.') {
resolved.push(segment)
}
}
return '/' + resolved.join('/')
})
export function getPath(...args) { export function getPath(...args) {
return cleanPath(args.join('/')) return cleanPath(args.join('/'))
} }
+62
View File
@@ -0,0 +1,62 @@
export default (function () {
let loadingImageCount = 0
const subscribers = []
function subscribe(cb) {
subscribers.push(cb)
}
function unsubscribe(cb) {
const index = subscribers.indexOf(cb)
if (index !== -1) {
subscribers.splice(index, 1)
}
}
function notifyAllImagesComplete() {
for (let i = 0; i < subscribers.length; i++) {
subscribers[i]()
}
}
function increaseLoadingImageCount() {
loadingImageCount += 1
}
function decreaseLoadingImageCount() {
loadingImageCount -= 1
if (loadingImageCount === 0) {
notifyAllImagesComplete()
}
}
function cleanElement(ele) {
ele.removeAttribute('onload')
ele.removeAttribute('onerror')
}
function onLoad(ele) {
cleanElement(ele)
decreaseLoadingImageCount()
}
function onError(ele) {
cleanElement(ele)
decreaseLoadingImageCount()
}
function isAllImagesComplete() {
return loadingImageCount === 0
}
return {
subscribe,
unsubscribe,
increaseLoadingImageCount,
onLoad,
onError,
isAllImagesComplete
}
})()
+1
View File
@@ -1,3 +1,4 @@
export * from './core' export * from './core'
export * from './env' export * from './env'
export * from '../router/util' export * from '../router/util'
export {default as image} from './image'
+1 -1
View File
@@ -892,7 +892,7 @@ const AllGithubEmoji = [
window.emojify = function (match, $1) { window.emojify = function (match, $1) {
return AllGithubEmoji.indexOf($1) === -1 ? return AllGithubEmoji.indexOf($1) === -1 ?
match : match :
'<img class="emoji" src="https://github.githubassets.com/images/icons/emoji/' + '<img class="emoji" src="https://assets-cdn.github.com/images/icons/emoji/' +
$1 + $1 +
'.png" alt="' + '.png" alt="' +
$1 + $1 +
+4 -10
View File
@@ -7,16 +7,10 @@ function install(hook) {
const main = dom.getNode('#main') const main = dom.getNode('#main')
div.style = `width: ${main.clientWidth}px; margin: 0 auto 20px;` div.style = `width: ${main.clientWidth}px; margin: 0 auto 20px;`
dom.appendTo(dom.find('.content'), div) dom.appendTo(dom.find('.content'), div)
}) const script = dom.create('script')
const content = `gitalk.render('gitalk-container')`
hook.doneEach(_ => { script.textContent = content
const el = document.getElementById('gitalk-container') dom.appendTo(dom.body, script)
while (el.hasChildNodes()) {
el.removeChild(el.firstChild)
}
// eslint-disable-next-line
gitalk.render('gitalk-container')
}) })
} }
-6
View File
@@ -323,9 +323,6 @@ body.sticky
.markdown-section iframe .markdown-section iframe
border 1px solid #eee border 1px solid #eee
/* fix horizontal overflow on iOS Safari */
width 1px
min-width 100%
.markdown-section table .markdown-section table
border-collapse collapse border-collapse collapse
@@ -386,9 +383,6 @@ body.sticky
border-radius 2px border-radius 2px
padding 1rem padding 1rem
.markdown-section ul.task-list > li
list-style-type none
body.close body.close
.sidebar .sidebar
transform translateX(- $sidebar-width) transform translateX(- $sidebar-width)
-228
View File
@@ -1,228 +0,0 @@
@import url('https://fonts.googleapis.com/css?family=Thasadith:400,400i,700')
$color-primary = #00ffff
$color-bg = #f0ffff
$color-text = #34495e
$sidebar-width = 300px
@import 'basic/_layout'
@import 'basic/_coverpage'
body
background-color $color-bg
/* sidebar */
.sidebar
background-color $color-bg
color #364149
li
margin 6px 0 6px 0
ul li a
color #505d6b
font-size 14px
font-weight normal
overflow hidden
text-decoration none
text-overflow ellipsis
white-space nowrap
&:hover
text-decoration underline
ul li ul
padding 0
ul li.active > a
border-right 2px solid
color var(--theme-color, $color-primary)
font-weight 600
.app-sub-sidebar
li
&::before
content '-'
padding-right 4px
float left
/* markdown content found on pages */
.markdown-section h1, .markdown-section h2, .markdown-section h3, .markdown-section h4, .markdown-section strong
color #2c3e50
font-weight 600
.markdown-section a
color var(--theme-color, $color-primary)
font-weight 600
&:hover
text-decoration underline
.markdown-section h1
font-size 2rem
margin 0 0 1rem
.markdown-section h2
font-size 1.75rem
margin 45px 0 0.8rem
.markdown-section h3
font-size 1.5rem
margin 40px 0 0.6rem
.markdown-section h4
font-size 1.25rem
.markdown-section h5
font-size 1rem
.markdown-section h6
color #777
font-size 1rem
.markdown-section figure, .markdown-section p
margin 1.2em 0
.markdown-section p, .markdown-section ul, .markdown-section ol
line-height 1.6rem
word-spacing 0.05rem
.markdown-section ul, .markdown-section ol
padding-left 1.5rem
.markdown-section blockquote
border-left 4px solid var(--theme-color, $color-primary)
color #858585
margin 2em 0
padding-left 20px
.markdown-section blockquote p
font-weight 600
margin-left 0
.markdown-section iframe
margin 1em 0
.markdown-section em
color #7f8c8d
.markdown-section code
background-color #f8f8f8
border-radius 2px
color #e96900
font-family 'Roboto Mono', Monaco, courier, monospace
font-size 0.8rem
margin 0 2px
padding 3px 5px
white-space pre-wrap
.markdown-section pre
-moz-osx-font-smoothing initial
-webkit-font-smoothing initial
background-color #f8f8f8
font-family 'Roboto Mono', Monaco, courier, monospace
line-height 1.5rem
margin 1.2em 0
overflow auto
padding 0 1.4rem
position relative
word-wrap normal
/* code highlight */
.token.comment, .token.prolog, .token.doctype, .token.cdata
color #8e908c
.token.namespace
opacity 0.7
.token.boolean, .token.number
color #c76b29
.token.punctuation
color #525252
.token.property
color #c08b30
.token.tag
color #2973b7
.token.string
color var(--theme-color, $color-primary)
.token.selector
color #6679cc
.token.attr-name
color #2973b7
.token.entity, .token.url, .language-css .token.string, .style .token.string
color #22a2c9
.token.attr-value, .token.control, .token.directive, .token.unit
color var(--theme-color, $color-primary)
.token.keyword, .token.function
color #e96900
.token.statement, .token.regex, .token.atrule
color #22a2c9
.token.placeholder, .token.variable
color #3d8fd1
.token.deleted
text-decoration line-through
.token.inserted
border-bottom 1px dotted #202746
text-decoration none
.token.italic
font-style italic
.token.important, .token.bold
font-weight bold
.token.important
color #c94922
.token.entity
cursor help
.markdown-section pre > code
-moz-osx-font-smoothing initial
-webkit-font-smoothing initial
background-color #f8f8f8
border-radius 2px
color #525252
display block
font-family 'Roboto Mono', Monaco, courier, monospace
font-size 0.8rem
line-height inherit
margin 0 2px
max-width inherit
overflow inherit
padding 2.2em 5px
white-space inherit
.markdown-section code::after, .markdown-section code::before
letter-spacing 0.05rem
code .token
-moz-osx-font-smoothing initial
-webkit-font-smoothing initial
min-height 1.5rem
pre::after
color #ccc
content attr(data-lang)
font-size 0.6rem
font-weight 600
height 15px
line-height 15px
padding 5px 10px 0
position absolute
right 0
text-align right
top 0
-87
View File
@@ -1,87 +0,0 @@
// load ES6 modules in Node.js on the fly
require = require('esm')(module/*, options*/)
const path = require('path')
const {expect} = require('chai')
const {JSDOM} = require('jsdom')
function ready(callback) {
const state = document.readyState
if (state === 'complete' || state === 'interactive') {
return setTimeout(callback, 0)
}
document.addEventListener('DOMContentLoaded', callback)
}
module.exports.init = function(fixture = 'default', config = {}, markup) {
if (markup == null) {
markup = `<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="app"></div>
<script>
window.$docsify = ${JSON.stringify(config, null, 2)}
</script>
</body>
</html>`
}
const rootPath = path.join(__dirname, 'fixtures', fixture)
const dom = new JSDOM(markup)
dom.reconfigure({ url: 'file:///' + rootPath })
global.window = dom.window
global.document = dom.window.document
global.navigator = dom.window.navigator
global.location = dom.window.location
global.XMLHttpRequest = dom.window.XMLHttpRequest
// mimic src/core/index.js but for Node.js
function Docsify() {
this._init()
}
const proto = Docsify.prototype
const {initMixin} = require('../src/core/init')
const {routerMixin} = require('../src/core//router')
const {renderMixin} = require('../src/core//render')
const {fetchMixin} = require('../src/core/fetch')
const {eventMixin} = require('../src/core//event')
initMixin(proto)
routerMixin(proto)
renderMixin(proto)
fetchMixin(proto)
eventMixin(proto)
const NOT_INIT_PATTERN = '<!--main-->'
return new Promise((resolve, reject) => {
ready(() => {
const docsify = new Docsify()
// NOTE: I was not able to get it working with a callback, but polling works usually at the first time
const id = setInterval(() => {
if (dom.window.document.body.innerHTML.indexOf(NOT_INIT_PATTERN) == -1) {
clearInterval(id)
return resolve({
docsify: docsify,
dom: dom
})
}
}, 10)
})
})
}
module.exports.expectSameDom = function(actual, expected) {
const WHITESPACES_BETWEEN_TAGS = />(\s\s+)</g
function replacer(match, group1) {
return match.replace(group1, '')
}
expect(actual.replace(WHITESPACES_BETWEEN_TAGS, replacer).trim())
.equal(expected.replace(WHITESPACES_BETWEEN_TAGS, replacer).trim())
}
-6
View File
@@ -1,6 +0,0 @@
<!--
create your own fixture directory
if you need a custom README.md or sidebar
-->
-18
View File
@@ -1,18 +0,0 @@
# Heading
[another page](other.md)
## II 1
### III 1
#### IV 1
##### V 1
## II 2
### III 2
#### IV 2
-16
View File
@@ -1,16 +0,0 @@
# Other
## two 1
### three 1
#### four 1
##### five 1
## two 2
### three 2
#### four 2
-14
View File
@@ -1,14 +0,0 @@
const path = require('path')
const {expect} = require('chai')
const {init, expectSameDom} = require('../_helper')
describe('full docsify initialization', function() {
it('TODO: check generated markup', async function() {
const {docsify, dom} = await init('simple', {loadSidebar: true})
console.log(dom.window.document.body.innerHTML)
// TODO: add some expectations
})
})
-14
View File
@@ -1,14 +0,0 @@
const path = require('path')
const {expect} = require('chai')
const {init, expectSameDom} = require('../_helper')
describe('router', function() {
it('TODO: trigger to load another page', async function() {
const {docsify} = await init()
window.location = '/?foo=bar'
// TODO: add some expectations
})
})
-62
View File
@@ -1,62 +0,0 @@
/* eslint-env node, chai, mocha */
require = require('esm')(module/*, options*/)
const {expect} = require('chai')
const {History} = require('../../src/core/router/history/base')
class MockHistory extends History {
parse(path) {
return {path}
}
}
describe('router/history/base', function () {
describe('relativePath true', function () {
var history
beforeEach(function () {
history = new MockHistory({relativePath: true})
})
it('toURL', function () {
// WHEN
const url = history.toURL('guide.md', {}, '/zh-ch/')
// THEN
expect(url).equal('/zh-ch/guide')
})
it('toURL with double dot', function () {
// WHEN
const url = history.toURL('../README.md', {}, '/zh-ch/')
// THEN
expect(url).equal('/README')
})
it('toURL child path', function () {
// WHEN
const url = history.toURL('config/example.md', {}, '/zh-ch/')
// THEN
expect(url).equal('/zh-ch/config/example')
})
it('toURL absolute path', function () {
// WHEN
const url = history.toURL('/README', {}, '/zh-ch/')
// THEN
expect(url).equal('/README')
})
})
it('toURL without relative path', function () {
const history = new MockHistory({relativePath: false})
// WHEN
const url = history.toURL('README', {}, '/zh-ch/')
// THEN
expect(url).equal('/README')
})
})
-89
View File
@@ -1,89 +0,0 @@
const path = require('path')
const {expect} = require('chai')
const {init, expectSameDom} = require('../_helper')
describe('render', function() {
it('important content (tips)', async function() {
const {docsify, dom} = await init()
const output = docsify.compiler.compile('!> **Time** is money, my friend!')
expect(output).equal('<p class="tip"><strong>Time</strong> is money, my friend!</p>')
})
describe('lists', function() {
it('as unordered task list', async function() {
const {docsify, dom} = await init()
const output = docsify.compiler.compile(`
- [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>`)
})
it('as ordered task list', async function() {
const {docsify, dom} = await init()
const output = docsify.compiler.compile(`
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>`)
})
it('normal unordered', async function() {
const {docsify, dom} = await init()
const output = docsify.compiler.compile(`
- [linktext](link)
- just text`)
expectSameDom(output, `<ul >
<li><a href="#/link">linktext</a></li>
<li>just text</li>
</ul>`)
})
it('unordered with custom start', async function() {
const {docsify, dom} = await init()
const output = docsify.compiler.compile(`
1. first
2. second
text
3. third`)
expectSameDom(output, `<ol >
<li>first</li>
<li>second</li>
</ol>
<p>text</p>
<ol start="3">
<li>third</li>
</ol>`)
})
it('nested', async function() {
const {docsify, dom} = await init()
const output = docsify.compiler.compile(`
- 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>`)
})
})
})
-30
View File
@@ -1,30 +0,0 @@
/* eslint-env node, chai, mocha */
require = require('esm')(module/*, options*/)
const {expect} = require('chai')
const {resolvePath} = require('../../src/core/router/util')
describe('router/util', function () {
it('resolvePath', async function () {
// WHEN
const result = resolvePath('hello.md')
// THEN
expect(result).equal('/hello.md')
})
it('resolvePath with dot', async function () {
// WHEN
const result = resolvePath('./hello.md')
// THEN
expect(result).equal('/hello.md')
})
it('resolvePath with two dots', async function () {
// WHEN
const result = resolvePath('test/../hello.md')
// THEN
expect(result).equal('/hello.md')
})
})