diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..a3b8548
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,5 @@
+.git
+packages/docsify-server-renderer/build.js
+node_modules
+build
+server.js
\ No newline at end of file
diff --git a/.eslintrc b/.eslintrc
index d5691ad..a8f7cd0 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,6 +1,20 @@
{
- "extends": ["vue"],
+ "extends": "xo-space/browser",
+ "rules": {
+ "semi": [2, "never"],
+ "no-return-assign": "off",
+ "no-unused-expressions": "off",
+ "no-new-func": "off",
+ "no-multi-assign": "off",
+ "no-mixed-operators": "off",
+ "max-params": "off",
+ "no-script-url": "off",
+ "camelcase": "off",
+ "no-warning-comments": "off"
+ },
"globals": {
- "XMLHttpRequest": true
+ "Docsify": true,
+ "$docsify": true,
+ "process": true
}
}
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..35d6b90
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+
+---
+
+
+
+
+
+## Bug Report
+
+#### Steps to reproduce
+
+
+
+#### What is current behaviour
+
+
+
+#### What is the expected behaviour
+
+
+
+#### Other relevant information
+
+
+- [ ] Bug does still occur when all/other plugins are disabled?
+
+- Your OS:
+- Node.js version:
+- npm/yarn version:
+- Browser version:
+- Docsify version:
+- Docsify plugins:
+
+
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..501e4de
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,25 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+
+---
+
+
+
+
+
+## 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?
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..bb31bd4
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+**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:**
+
+---
+
+* [ ] DO NOT include files inside `lib` directory.
+
diff --git a/.gitignore b/.gitignore
index a1ee562..ea4b5b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,9 @@
-.DS_Store
*.log
+.DS_Store
+.idea
node_modules
-yarn.lock
-/themes
\ No newline at end of file
+themes/
+lib/
+
+# exceptions
+!.gitkeep
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..41b1431
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,5 @@
+.eslintignore
+.eslintrc
+.github/
+.gitignore
+.travis.yml
diff --git a/.travis.yml b/.travis.yml
index fb0b83e..87576c5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,3 @@
sudo: false
-cache:
- directories:
- - $HOME/.yarn-cache
language: node_js
node_js: stable
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..b7d6eb8
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "prettier.eslintIntegration": true
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f5f28c4..267d402 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,175 +1,753 @@
-## 1.4.0 Happly new year 🎉
+
+## [4.9.4](https://github.com/docsifyjs/docsify/compare/v4.9.2...v4.9.4) (2019-05-05)
+
+
+
+
+## [4.9.2](https://github.com/docsifyjs/docsify/compare/v4.9.1...v4.9.2) (2019-04-21)
+
+
+### Bug Fixes
+
+* re-render gitalk when router changed ([11ea1f8](https://github.com/docsifyjs/docsify/commit/11ea1f8))
+
+
### Features
-- Display TOC in the custom sidebar, `data-sub-max-level`.
-- Custom background in coverpage.
-### Bug fixes
-- Fix scroll highlight when Vue exist.
+* allows relative path, fixed [#590](https://github.com/docsifyjs/docsify/issues/590) ([31654f1](https://github.com/docsifyjs/docsify/commit/31654f1))
-## 1.3.5
-### Bug fixes
-- Fix vue
-## 1.3.4
-### Bug fixes
-- Supports [vuep](https://github.com/QingWei-Li/vuep)
+
+## [4.9.1](https://github.com/docsifyjs/docsify/compare/v4.9.0...v4.9.1) (2019-02-21)
-## 1.3.3
-### Bug fixes
-- Fixed cover rendering timing
-## 1.3.2
+### Bug Fixes
-### Bug fixes
-- Fixed render link
+* github assets url ([#774](https://github.com/docsifyjs/docsify/issues/774)) ([140bf10](https://github.com/docsifyjs/docsify/commit/140bf10))
-## 1.3.1
-### Bug fixes
-- Fixed cover page style
-- Generate the correct link when rendering the article
-## 1.3.0
+
+# [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
-- Add cover page
-- add `` style
-- headling can be cliked
-### Bug fixes
-- sidebar highlight
+* **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))
-### break change
-- Navbar no longer fixed at the top
-## 1.2.0
+
+## [4.8.6](https://github.com/docsifyjs/docsify/compare/v4.8.5...v4.8.6) (2018-11-12)
+
+
+### Bug Fixes
+
+* IE10 compatibility ([#691](https://github.com/docsifyjs/docsify/issues/691)) ([4db8cd6](https://github.com/docsifyjs/docsify/commit/4db8cd6))
+
+
+
+
+## [4.8.5](https://github.com/docsifyjs/docsify/compare/v4.8.4...v4.8.5) (2018-11-02)
+
+
+### Bug Fixes
+
+* expose version info for Docsify, fixed [#641](https://github.com/docsifyjs/docsify/issues/641) ([aa719e3](https://github.com/docsifyjs/docsify/commit/aa719e3))
+
+
+
+
+## [4.8.4](https://github.com/docsifyjs/docsify/compare/v4.8.3...v4.8.4) (2018-11-01)
+
+
+### Bug Fixes
+
+* **cover:** Compatible with legacy styles, fixed [#677](https://github.com/docsifyjs/docsify/issues/677) ([#678](https://github.com/docsifyjs/docsify/issues/678)) ([1a945d4](https://github.com/docsifyjs/docsify/commit/1a945d4))
+
+
+
+
+
+## [4.8.3](https://github.com/docsifyjs/docsify/compare/v4.8.2...v4.8.3) (2018-11-01)
+
+Fix the last release files has the old version marked...
+
+
+
+## [4.8.2](https://github.com/docsifyjs/docsify/compare/v4.8.1...v4.8.2) (2018-11-01)
+
+### Bug Fixes
+
+- cover button style, fixed [#670](https://github.com/docsifyjs/docsify/issues/670), fixed [#665](https://github.com/docsifyjs/docsify/issues/665) ([#675](https://github.com/docsifyjs/docsify/issues/675)) ([fcd1087](https://github.com/docsifyjs/docsify/commit/fcd1087))
+- update match regex ([#669](https://github.com/docsifyjs/docsify/issues/669)) ([2edf47e](https://github.com/docsifyjs/docsify/commit/2edf47e))
+- use copy of cached value ([#668](https://github.com/docsifyjs/docsify/issues/668)) ([5fcf210](https://github.com/docsifyjs/docsify/commit/5fcf210))
+- **compiler:** import prism-markup-templating, fixed [#672](https://github.com/docsifyjs/docsify/issues/672) ([#676](https://github.com/docsifyjs/docsify/issues/676)) ([fdd8826](https://github.com/docsifyjs/docsify/commit/fdd8826))
+
### Features
-- custom basePath
-- custom homepage
-## 1.1.7
-### Bug fixes
-- Optimize progress bar
+- add heading config id ([#671](https://github.com/docsifyjs/docsify/issues/671)) ([ab19b13](https://github.com/docsifyjs/docsify/commit/ab19b13))
+
+
+
+## [4.8.1](https://github.com/docsifyjs/docsify/compare/v4.8.0...v4.8.1) (2018-10-31)
+
+### Bug Fixes
+
+- ssr package dep, fixed [#605](https://github.com/docsifyjs/docsify/issues/605) ([2bc880d](https://github.com/docsifyjs/docsify/commit/2bc880d))
+- **compiler:** extra quotes for codeblock ([4f588e0](https://github.com/docsifyjs/docsify/commit/4f588e0))
+- **compiler:** prevent render of html code in paragraph, fixed [#663](https://github.com/docsifyjs/docsify/issues/663) ([d35059d](https://github.com/docsifyjs/docsify/commit/d35059d))
-## 1.1.6
### Features
-- Add logo 😂
-### Bug fixes
-- Remove table background color
-- Fixed highlight sidebar using chinese ids
+- upgrade PrismJS, fixed [#534](https://github.com/docsifyjs/docsify/issues/534) ([4805cb5](https://github.com/docsifyjs/docsify/commit/4805cb5))
+
+
+
+# [4.8.0](https://github.com/docsifyjs/docsify/compare/v4.7.1...v4.8.0) (2018-10-31)
+
+### Bug Fixes
+
+- Cache TOC for later usage in the case of cached file html ([#649](https://github.com/docsifyjs/docsify/issues/649)) ([9e86017](https://github.com/docsifyjs/docsify/commit/9e86017))
+- improve external script plugin ([#632](https://github.com/docsifyjs/docsify/issues/632)) ([50c2434](https://github.com/docsifyjs/docsify/commit/50c2434))
+- missing variable declaration ([#660](https://github.com/docsifyjs/docsify/issues/660)) ([1ce37bd](https://github.com/docsifyjs/docsify/commit/1ce37bd))
+- Remove target for mailto links ([#652](https://github.com/docsifyjs/docsify/issues/652)) ([18f0f03](https://github.com/docsifyjs/docsify/commit/18f0f03))
+- Update getAllPath query selector ([#653](https://github.com/docsifyjs/docsify/issues/653)) ([f6f4e32](https://github.com/docsifyjs/docsify/commit/f6f4e32))
+- Update vue.styl ([#634](https://github.com/docsifyjs/docsify/issues/634)) ([bf060be](https://github.com/docsifyjs/docsify/commit/bf060be))
-## 1.1.5
### Features
-- Add table style
-### Bug fixes
-- Not fixed position of hte navbar in the mobile browser
-- Correct calculation of whether the mobile browser
+- Add docsify version to $window.docsify object ([#641](https://github.com/docsifyjs/docsify/issues/641)) ([94bc415](https://github.com/docsifyjs/docsify/commit/94bc415)), closes [#521](https://github.com/docsifyjs/docsify/issues/521)
+- **compiler:** support embedded mermaid ([#629](https://github.com/docsifyjs/docsify/issues/629)) ([42ea8af](https://github.com/docsifyjs/docsify/commit/42ea8af))
+- Add hideOtherSidebarContent option ([#661](https://github.com/docsifyjs/docsify/issues/661)) ([4a23c4a](https://github.com/docsifyjs/docsify/commit/4a23c4a))
+- Allow base64, external, and relative logo values ([#642](https://github.com/docsifyjs/docsify/issues/642)) ([0a0802a](https://github.com/docsifyjs/docsify/commit/0a0802a)), closes [#577](https://github.com/docsifyjs/docsify/issues/577)
+- upgrade marked to 0.5.x, fixed [#645](https://github.com/docsifyjs/docsify/issues/645), close [#644](https://github.com/docsifyjs/docsify/issues/644) ([#662](https://github.com/docsifyjs/docsify/issues/662)) ([a39b214](https://github.com/docsifyjs/docsify/commit/a39b214))
-## 1.1.4
-### Bug fixes
-- Fixed chinese auchor link
+
-## 1.1.3
-### Bug fixes
-- Optimize progress bar again
+## [4.7.1](https://github.com/docsifyjs/docsify/compare/v4.7.0...v4.7.1) (2018-08-30)
-## 1.1.2
-### Bug fixes
-- fix failed `auto2top` in mobile
+
+# [4.7.0](https://github.com/QingWei-Li/docsify/compare/v4.6.9...v4.7.0) (2018-06-29)
-## 1.1.1
-### Bug fixes
-- Optimize progress bar
+### Bug Fixes
-## 1.1.0
-## Features
-- Add progress bar
-- Add `auto2top` option for hash router
+- alldow addition content in sidebar, fix [#518](https://github.com/QingWei-Li/docsify/issues/518), fix 539 ([#543](https://github.com/QingWei-Li/docsify/issues/543)) ([04b36b0](https://github.com/QingWei-Li/docsify/commit/04b36b0))
+- async install config, fixed [#425](https://github.com/QingWei-Li/docsify/issues/425) ([e4e011c](https://github.com/QingWei-Li/docsify/commit/e4e011c))
+- loading embed files synchronously, fixed [#525](https://github.com/QingWei-Li/docsify/issues/525), fixed [#527](https://github.com/QingWei-Li/docsify/issues/527) ([#544](https://github.com/QingWei-Li/docsify/issues/544)) ([feea7f9](https://github.com/QingWei-Li/docsify/commit/feea7f9))
+- path include chinese character cause hilight bug ([#556](https://github.com/QingWei-Li/docsify/issues/556)) ([a5f333a](https://github.com/QingWei-Li/docsify/commit/a5f333a))
-## 1.0.3
-### Bug fixes
-- Fix cache
-
-## 1.0.2
-### Bug fixes
-- Fix binding events bug, fixed #24
-- Fix regular expression, fixed #23
-
-## 1.0.1
-### Bug fixes
-- `img` style
-
-## 1.0.0
-## Features
-- Support hash router
-
-### Bug fixes
-- Improved scrolling on mobile
-
-## 0.7.0
-### Breaking change
-- `themes/` was removed, only exists in the npm package.
-
-### Bug fixes
-- Fix style.
-- Fix sidebar animation again.
-
-## 0.6.1
-### Bug fixes
-- In the mobile, it should collapse the sidebar when toggle is clicked.
-- Fix the dropdown list style.
-- Fix sidebar animation.
-
-## 0.6.0
### Features
-- Navbar support dropdown list, #6
-- Sidebar with toggle
-### Bug fixes
-- Fix ineffective option, fixed #10
+- add logo option, [#264](https://github.com/QingWei-Li/docsify/issues/264) ([#541](https://github.com/QingWei-Li/docsify/issues/541)) ([ee72dd0](https://github.com/QingWei-Li/docsify/commit/ee72dd0))
+- add unpkg field, close [#531](https://github.com/QingWei-Li/docsify/issues/531) ([#558](https://github.com/QingWei-Li/docsify/issues/558)) ([5c0de0a](https://github.com/QingWei-Li/docsify/commit/5c0de0a))
+- support image resizing, resolve [#508](https://github.com/QingWei-Li/docsify/issues/508) ([#545](https://github.com/QingWei-Li/docsify/issues/545)) ([3a7ad62](https://github.com/QingWei-Li/docsify/commit/3a7ad62))
+
+
+
+## [4.6.10](https://github.com/QingWei-Li/docsify/compare/v4.6.9...v4.6.10) (2018-03-25)
+
+### Bug Fixes
+
+- async install config, fixed [#425](https://github.com/QingWei-Li/docsify/issues/425) ([e4e011c](https://github.com/QingWei-Li/docsify/commit/e4e011c))
+
+
+
+## [4.6.9](https://github.com/QingWei-Li/docsify/compare/v4.6.8...v4.6.9) (2018-03-10)
+
+### Bug Fixes
+
+- upgrade medium-zoom, fixed [#417](https://github.com/QingWei-Li/docsify/issues/417) ([6a3d69a](https://github.com/QingWei-Li/docsify/commit/6a3d69a))
+
+
+
+## [4.6.8](https://github.com/QingWei-Li/docsify/compare/v4.6.7...v4.6.8) (2018-03-06)
+
+### Bug Fixes
+
+- resolve path of image and embed files, fixed [#412](https://github.com/QingWei-Li/docsify/issues/412) ([bfd0d18](https://github.com/QingWei-Li/docsify/commit/bfd0d18))
+
+
+
+## [4.6.7](https://github.com/QingWei-Li/docsify/compare/v4.6.6...v4.6.7) (2018-03-03)
+
+### Bug Fixes
+
+- layout css, fixed [#409](https://github.com/QingWei-Li/docsify/issues/409) ([aeb692e](https://github.com/QingWei-Li/docsify/commit/aeb692e))
+
+
+
+## [4.6.6](https://github.com/QingWei-Li/docsify/compare/v4.6.5...v4.6.6) (2018-03-03)
+
+
+
+## [4.6.5](https://github.com/QingWei-Li/docsify/compare/v4.6.4...v4.6.5) (2018-03-03)
+
+### Bug Fixes
+
+- **navbar:** Now Navbar isn't append to DOM when loadNavbar is falsy ([#407](https://github.com/QingWei-Li/docsify/issues/407)) ([0933445](https://github.com/QingWei-Li/docsify/commit/0933445))
-## 0.5.0
### Features
-- Custom sidebars and navbars by markdown file
-## 0.4.2
-### Bug fixes
-- Correct catch ajax error
+- **config:** Add 404 page options. ([#406](https://github.com/QingWei-Li/docsify/issues/406)) ([9b3b445](https://github.com/QingWei-Li/docsify/commit/9b3b445))
-## 0.4.1
-### Bug fixes
-- catch ajax error
+
+
+## [4.6.4](https://github.com/QingWei-Li/docsify/compare/v4.6.3...v4.6.4) (2018-03-01)
+
+### Bug Fixes
+
+- **render:** Disable markdown parsing when the file is an HTML ([#403](https://github.com/QingWei-Li/docsify/issues/403)) ([278a75e](https://github.com/QingWei-Li/docsify/commit/278a75e))
-## 0.4.0
### Features
-- Custom sidebar
-### Bug fixes
-- Fix undefined language
+- **fetch:** Add fallback languages configuration. ([#402](https://github.com/QingWei-Li/docsify/issues/402)) ([ecc0e04](https://github.com/QingWei-Li/docsify/commit/ecc0e04))
-## 0.3.1
-### Bug fixes
-- Strip HTML tag when rendering the headings
+
+
+## [4.6.3](https://github.com/QingWei-Li/docsify/compare/v4.6.2...v4.6.3) (2018-02-15)
+
+### Bug Fixes
+
+- **hook:** beforeEach don\'t work, fixed [#393](https://github.com/QingWei-Li/docsify/issues/393) ([6a09059](https://github.com/QingWei-Li/docsify/commit/6a09059))
+
+
+
+## [4.6.2](https://github.com/QingWei-Li/docsify/compare/v4.6.1...v4.6.2) (2018-02-14)
+
+### Bug Fixes
+
+- **embed:** broken in IE, fixed [#389](https://github.com/QingWei-Li/docsify/issues/389), fixed [#391](https://github.com/QingWei-Li/docsify/issues/391) ([45a7464](https://github.com/QingWei-Li/docsify/commit/45a7464))
+- **embed:** init value ([890a7bf](https://github.com/QingWei-Li/docsify/commit/890a7bf))
+
+
+
+## [4.6.1](https://github.com/QingWei-Li/docsify/compare/v4.6.0...v4.6.1) (2018-02-12)
+
+### Bug Fixes
+
+- **embed** compatible ssr ([dc0c3ce](https://github.com/QingWei-Li/docsify/commit/dc0c3ce))
+- **embed** async fetch embed files, fixed [#387](https://github.com/QingWei-Li/docsify/issues/387)
+
+
+
+# [4.6.0](https://github.com/QingWei-Li/docsify/compare/v4.5.9...v4.6.0) (2018-02-11)
+
+### Bug Fixes
+
+- **search:** custom clear button, fixed [#271](https://github.com/QingWei-Li/docsify/issues/271) ([864aa18](https://github.com/QingWei-Li/docsify/commit/864aa18))
+- **search:** escape special characters for search, fixed [#369](https://github.com/QingWei-Li/docsify/issues/369) ([9755439](https://github.com/QingWei-Li/docsify/commit/9755439))
+- build config ([342438f](https://github.com/QingWei-Li/docsify/commit/342438f))
+- button style for coverpage, fixed [#362](https://github.com/QingWei-Li/docsify/issues/362) ([85428ef](https://github.com/QingWei-Li/docsify/commit/85428ef))
+- dropdown scroll style, fixed [#346](https://github.com/QingWei-Li/docsify/issues/346) ([c4d83f2](https://github.com/QingWei-Li/docsify/commit/c4d83f2))
+- highlight homepage link, fixed [#304](https://github.com/QingWei-Li/docsify/issues/304) ([f960c19](https://github.com/QingWei-Li/docsify/commit/f960c19))
+- homepage link ([e097f88](https://github.com/QingWei-Li/docsify/commit/e097f88))
+- onlyCover ([033be4f](https://github.com/QingWei-Li/docsify/commit/033be4f))
+- ssr compatible embedd ([ebc10c4](https://github.com/QingWei-Li/docsify/commit/ebc10c4))
+- ssr coverpage, fixed [#273](https://github.com/QingWei-Li/docsify/issues/273) ([9e824a4](https://github.com/QingWei-Li/docsify/commit/9e824a4))
-## 0.3.0
### Features
-- Add minified css files
-- Add max level option
-- Add pure.css
-## 0.2.1
-### Bug fixes
-- Fix vue.css
+- click sidebar menu add collapse and expand, close [#294](https://github.com/QingWei-Li/docsify/issues/294) ([5e161a1](https://github.com/QingWei-Li/docsify/commit/5e161a1))
+- **compiler:** support embedded file as code block, close [#134](https://github.com/QingWei-Li/docsify/issues/134) ([761ccc2](https://github.com/QingWei-Li/docsify/commit/761ccc2))
+- **compiler:** support embedded markdown, html, video, etc files, close [#383](https://github.com/QingWei-Li/docsify/issues/383), close [#333](https://github.com/QingWei-Li/docsify/issues/333) ([524f52f](https://github.com/QingWei-Li/docsify/commit/524f52f))
+- **cover:** add onlyCover option, close [#382](https://github.com/QingWei-Li/docsify/issues/382) ([b265fdd](https://github.com/QingWei-Li/docsify/commit/b265fdd))
+- **fetch:** add requestHeaders option, fixed [#336](https://github.com/QingWei-Li/docsify/issues/336) ([54ab4c9](https://github.com/QingWei-Li/docsify/commit/54ab4c9))
+- **render:** add ext option for custom file extenstion, close [#340](https://github.com/QingWei-Li/docsify/issues/340) ([248aa72](https://github.com/QingWei-Li/docsify/commit/248aa72))
+- **render:** mutilple coverpage, close [#315](https://github.com/QingWei-Li/docsify/issues/315) ([f68ddf5](https://github.com/QingWei-Li/docsify/commit/f68ddf5))
-## 0.2.0
-### Bug fixes
-- Fix route
-- Remove dynamic title
+
+
+## [4.5.9](https://github.com/QingWei-Li/docsify/compare/v4.5.8...v4.5.9) (2018-02-07)
+
+### Bug Fixes
+
+- upgrade marked ([4157173](https://github.com/QingWei-Li/docsify/commit/4157173))
+
+
+
+## [4.5.8](https://github.com/QingWei-Li/docsify/compare/v4.5.6...v4.5.8) (2018-02-07)
+
+### Bug Fixes
+
+- cover style, fixed [#381](https://github.com/QingWei-Li/docsify/issues/381) ([368754e](https://github.com/QingWei-Li/docsify/commit/368754e))
+- updated deps ([#337](https://github.com/QingWei-Li/docsify/issues/337)) ([a12d393](https://github.com/QingWei-Li/docsify/commit/a12d393))
+
+
+
+## [4.5.7](https://github.com/QingWei-Li/docsify/compare/v4.5.6...v4.5.7) (2017-12-29)
-## 0.1.0
### Features
-- Add buble.css
\ No newline at end of file
+
+- add navigation plugin, closed [#180](https://github.com/QingWei-Li/docsify/issues/180) ([f78be4c](https://github.com/QingWei-Li/docsify/commit/f78be4c))
+
+
+
+## [4.5.6](https://github.com/QingWei-Li/docsify/compare/v4.5.3...v4.5.6) (2017-12-14)
+
+### Bug Fixes
+
+- **style:** increase the tap targets of menu button, fixed [#325](https://github.com/QingWei-Li/docsify/issues/325) ([888f217](https://github.com/QingWei-Li/docsify/commit/888f217))
+
+
+
+## [4.5.5](https://github.com/QingWei-Li/docsify/compare/v4.5.4...v4.5.5) (2017-11-30)
+
+### Bug Fixes
+
+- disqus plugin issue ([#318](https://github.com/QingWei-Li/docsify/issues/318)) ([041b33e](https://github.com/QingWei-Li/docsify/commit/041b33e)), closes [#317](https://github.com/QingWei-Li/docsify/issues/317)
+
+
+
+## [4.5.4](https://github.com/QingWei-Li/docsify/compare/v4.5.2...v4.5.4) (2017-11-29)
+
+### Bug Fixes
+
+- **compiler:** task lists style, fixed [#215](https://github.com/QingWei-Li/docsify/issues/215) ([e43ded4](https://github.com/QingWei-Li/docsify/commit/e43ded4))
+
+### Features
+
+- add gitalk plugin ([#306](https://github.com/QingWei-Li/docsify/issues/306)) ([9208e64](https://github.com/QingWei-Li/docsify/commit/9208e64))
+
+
+
+## [4.5.3](https://github.com/QingWei-Li/docsify/compare/v4.5.2...v4.5.3) (2017-11-11)
+
+### Features
+
+- add gitalk plugin ([#306](https://github.com/QingWei-Li/docsify/issues/306)) ([9208e64](https://github.com/QingWei-Li/docsify/commit/9208e64))
+
+
+
+## [4.5.2](https://github.com/QingWei-Li/docsify/compare/v4.5.1...v4.5.2) (2017-11-09)
+
+### Features
+
+- github task lists, close [#215](https://github.com/QingWei-Li/docsify/issues/215) ([#305](https://github.com/QingWei-Li/docsify/issues/305)) ([d486eef](https://github.com/QingWei-Li/docsify/commit/d486eef))
+
+
+
+## [4.5.1](https://github.com/QingWei-Li/docsify/compare/v4.5.0...v4.5.1) (2017-11-07)
+
+### Features
+
+- fetch files with the query params, fixed [#303](https://github.com/QingWei-Li/docsify/issues/303) ([2a2ed96](https://github.com/QingWei-Li/docsify/commit/2a2ed96))
+
+
+
+# [4.5.0](https://github.com/QingWei-Li/docsify/compare/v4.4.1...v4.5.0) (2017-11-04)
+
+### Features
+
+- add disqus plugin, closed [#123](https://github.com/QingWei-Li/docsify/issues/123) ([fd7d4e0](https://github.com/QingWei-Li/docsify/commit/fd7d4e0))
+
+
+
+## [4.4.1](https://github.com/QingWei-Li/docsify/compare/v4.4.0...v4.4.1) (2017-10-31)
+
+### Bug Fixes
+
+- {docsify-ignore-all} and {docsify-ignore} bug ([#299](https://github.com/QingWei-Li/docsify/issues/299)) ([cc98f56](https://github.com/QingWei-Li/docsify/commit/cc98f56))
+- zoom image plugin issue, fixed [#187](https://github.com/QingWei-Li/docsify/issues/187) ([#300](https://github.com/QingWei-Li/docsify/issues/300)) ([fa772cf](https://github.com/QingWei-Li/docsify/commit/fa772cf))
+
+
+
+# [4.4.0](https://github.com/QingWei-Li/docsify/compare/v4.3.15...v4.4.0) (2017-10-30)
+
+### Bug Fixes
+
+- sidebar style issue on firefox, fixed [#184](https://github.com/QingWei-Li/docsify/issues/184) ([#297](https://github.com/QingWei-Li/docsify/issues/297)) ([36bfc9d](https://github.com/QingWei-Li/docsify/commit/36bfc9d))
+
+### Features
+
+- add helper for disabled link, fixed [#295](https://github.com/QingWei-Li/docsify/issues/295) ([#296](https://github.com/QingWei-Li/docsify/issues/296)) ([4ad96f3](https://github.com/QingWei-Li/docsify/commit/4ad96f3))
+
+
+
+## [4.3.15](https://github.com/QingWei-Li/docsify/compare/v4.3.14...v4.3.15) (2017-10-20)
+
+### Bug Fixes
+
+- scroll active sidebar ([a2b8eae](https://github.com/QingWei-Li/docsify/commit/a2b8eae))
+
+
+
+## [4.3.14](https://github.com/QingWei-Li/docsify/compare/v4.3.13...v4.3.14) (2017-10-20)
+
+### Bug Fixes
+
+- codesponsor style ([ab68268](https://github.com/QingWei-Li/docsify/commit/ab68268))
+
+
+
+## [4.3.13](https://github.com/QingWei-Li/docsify/compare/v4.3.12...v4.3.13) (2017-10-17)
+
+### Bug Fixes
+
+- duplicate results in search fixed [#257](https://github.com/QingWei-Li/docsify/issues/257) ([#284](https://github.com/QingWei-Li/docsify/issues/284)) ([3476f6f](https://github.com/QingWei-Li/docsify/commit/3476f6f))
+
+### Features
+
+- make whole search result clickable ([#285](https://github.com/QingWei-Li/docsify/issues/285)) ([1b91227](https://github.com/QingWei-Li/docsify/commit/1b91227))
+
+
+
+## [4.3.12](https://github.com/QingWei-Li/docsify/compare/v4.3.11...v4.3.12) (2017-10-15)
+
+### Bug Fixes
+
+- incorrect active link ([#281](https://github.com/QingWei-Li/docsify/issues/281)) ([a3ab379](https://github.com/QingWei-Li/docsify/commit/a3ab379))
+
+
+
+## [4.3.11](https://github.com/QingWei-Li/docsify/compare/v4.3.10...v4.3.11) (2017-10-15)
+
+### Bug Fixes
+
+- broken links to same page heading, fix [#278](https://github.com/QingWei-Li/docsify/issues/278), fix [#279](https://github.com/QingWei-Li/docsify/issues/279) ([91d6337](https://github.com/QingWei-Li/docsify/commit/91d6337))
+
+
+
+## [4.3.10](https://github.com/QingWei-Li/docsify/compare/v4.3.9...v4.3.10) (2017-10-12)
+
+### Bug Fixes
+
+- link render issue after page refreshing ([#276](https://github.com/QingWei-Li/docsify/issues/276)) ([abd885e](https://github.com/QingWei-Li/docsify/commit/abd885e))
+
+
+
+## [4.3.9](https://github.com/QingWei-Li/docsify/compare/v4.3.8...v4.3.9) (2017-10-11)
+
+### Bug Fixes
+
+- scroll issue in IE ([#275](https://github.com/QingWei-Li/docsify/issues/275)) ([3e94cb6](https://github.com/QingWei-Li/docsify/commit/3e94cb6))
+
+
+
+## [4.3.8](https://github.com/QingWei-Li/docsify/compare/v4.3.7...v4.3.8) (2017-10-07)
+
+### Bug Fixes
+
+- **slugify:** GitHub compatible heading links, fixed [#272](https://github.com/QingWei-Li/docsify/issues/272) ([9b4e666](https://github.com/QingWei-Li/docsify/commit/9b4e666))
+
+
+
+## [4.3.7](https://github.com/QingWei-Li/docsify/compare/v4.3.6...v4.3.7) (2017-10-02)
+
+### Bug Fixes
+
+- **slugify:** GitHub compatible heading links, fixed [#267](https://github.com/QingWei-Li/docsify/issues/267) ([c195d2d](https://github.com/QingWei-Li/docsify/commit/c195d2d))
+
+
+
+## [4.3.6](https://github.com/QingWei-Li/docsify/compare/v4.3.5...v4.3.6) (2017-09-21)
+
+### Bug Fixes
+
+- style for codesponsor plugin ([08afec7](https://github.com/QingWei-Li/docsify/commit/08afec7))
+
+
+
+## [4.3.5](https://github.com/QingWei-Li/docsify/compare/v4.3.4...v4.3.5) (2017-09-20)
+
+### Bug Fixes
+
+- missed symbol ([#254](https://github.com/QingWei-Li/docsify/issues/254)) ([6c702d3](https://github.com/QingWei-Li/docsify/commit/6c702d3))
+
+### Features
+
+- **plugin:** add codesponsor plugin ([46ac4c3](https://github.com/QingWei-Li/docsify/commit/46ac4c3))
+
+
+
+## [4.3.4](https://github.com/QingWei-Li/docsify/compare/v4.3.3...v4.3.4) (2017-09-07)
+
+### Bug Fixes
+
+- scroll position issue, fixed [#234](https://github.com/QingWei-Li/docsify/issues/234) ([388ed3d](https://github.com/QingWei-Li/docsify/commit/388ed3d))
+
+
+
+## [4.3.3](https://github.com/QingWei-Li/docsify/compare/v4.3.2...v4.3.3) (2017-09-06)
+
+### Bug Fixes
+
+- **buble.css:** tweaks code block style, fixed [#249](https://github.com/QingWei-Li/docsify/issues/249) ([9d43051](https://github.com/QingWei-Li/docsify/commit/9d43051))
+
+### Features
+
+- add doc for react and vue demo box plugin ([#247](https://github.com/QingWei-Li/docsify/issues/247)) ([f0aca19](https://github.com/QingWei-Li/docsify/commit/f0aca19))
+
+
+
+## [4.3.2](https://github.com/QingWei-Li/docsify/compare/v4.3.1...v4.3.2) (2017-09-01)
+
+### Bug Fixes
+
+- sidebar highlight ([f82f419](https://github.com/QingWei-Li/docsify/commit/f82f419))
+
+### Features
+
+- add Edit on github plugin (thanks [@njleonzhang](https://github.com/njleonzhang)) ([a0e1ea8](https://github.com/QingWei-Li/docsify/commit/a0e1ea8))
+
+
+
+## [4.3.1](https://github.com/QingWei-Li/docsify/compare/v4.2.9...v4.3.1) (2017-08-30)
+
+### Features
+
+- **markdown:** supports mermaid [#137](https://github.com/QingWei-Li/docsify/issues/137) ([f4800e0](https://github.com/QingWei-Li/docsify/commit/f4800e0))
+
+
+
+# [4.3.0](https://github.com/QingWei-Li/docsify/compare/v4.2.9...v4.3.0) (2017-08-17)
+
+### Features
+
+- **markdown:** supports mermaid [#137](https://github.com/QingWei-Li/docsify/issues/137) ([f4800e0](https://github.com/QingWei-Li/docsify/commit/f4800e0))
+
+
+
+## [4.2.9](https://github.com/QingWei-Li/docsify/compare/v4.2.8...v4.2.9) (2017-08-15)
+
+### Bug Fixes
+
+- ensure document ready before init Docsify [#233](https://github.com/QingWei-Li/docsify/issues/233)
+
+
+
+## [4.2.8](https://github.com/QingWei-Li/docsify/compare/v4.2.7...v4.2.8) (2017-08-10)
+
+### Features
+
+- **compiler:** support for setting target attribute for link, fixed [#230](https://github.com/QingWei-Li/docsify/issues/230) ([7f270f9](https://github.com/QingWei-Li/docsify/commit/7f270f9))
+
+
+
+## [4.2.7](https://github.com/QingWei-Li/docsify/compare/v4.2.4...v4.2.7) (2017-08-05)
+
+### Bug Fixes
+
+- **release:** release shell ([628e211](https://github.com/QingWei-Li/docsify/commit/628e211))
+- **style:** nowrap => pre-wrap, fixed [#228](https://github.com/QingWei-Li/docsify/issues/228) ([a88252c](https://github.com/QingWei-Li/docsify/commit/a88252c))
+
+
+
+## [4.2.6](https://github.com/QingWei-Li/docsify/compare/v4.2.4...v4.2.6) (2017-07-27)
+
+### Bug Fixes
+
+- **css:** hide the nav when the content has not yet been loaded ([1fa1619](https://github.com/QingWei-Li/docsify/commit/1fa1619))
+- **release:** release shell ([628e211](https://github.com/QingWei-Li/docsify/commit/628e211))
+
+
+
+## [4.2.4](https://github.com/QingWei-Li/docsify/compare/v4.2.2...v4.2.4) (2017-07-26)
+
+### Bug Fixes
+
+- **render:** Remove getRootNode to be compatible with the lower version of Chrome, fixed [#225](https://github.com/QingWei-Li/docsify/issues/225) ([b8dd346](https://github.com/QingWei-Li/docsify/commit/b8dd346))
+
+
+
+## [4.2.3](https://github.com/QingWei-Li/docsify/compare/v4.2.2...v4.2.3) (2017-07-26)
+
+### Features
+
+- **search:** Supports the max depth of the search headline, fixed [#223](https://github.com/QingWei-Li/docsify/issues/223), resolve [#129](https://github.com/QingWei-Li/docsify/issues/129) ([b7b589b](https://github.com/QingWei-Li/docsify/commit/b7b589b))
+
+
+
+## [4.2.2](https://github.com/QingWei-Li/docsify/compare/v4.2.1...v4.2.2) (2017-07-24)
+
+### Bug Fixes
+
+- style rerender due to setting themeColor ([17ff3d1](https://github.com/QingWei-Li/docsify/commit/17ff3d1))
+
+
+
+## [4.2.1](https://github.com/QingWei-Li/docsify/compare/v4.2.0...v4.2.1) (2017-07-19)
+
+- give the navbar some line-height (#216)
+- Remove unnecessary moduleName option from rollup config for plugins (#209)
+
+
+
+# [4.2.0](https://github.com/QingWei-Li/docsify/compare/v4.1.14...v4.2.0) (2017-07-10)
+
+### Bug Fixes
+
+- not found page ([9af8559](https://github.com/QingWei-Li/docsify/commit/9af8559))
+
+### Features
+
+- alias option supports regexp, resolve [#183](https://github.com/QingWei-Li/docsify/issues/183) ([c4aa22c](https://github.com/QingWei-Li/docsify/commit/c4aa22c))
+- ignore to compiled link, fixed [#203](https://github.com/QingWei-Li/docsify/issues/203) ([#204](https://github.com/QingWei-Li/docsify/issues/204)) ([2e00f4c](https://github.com/QingWei-Li/docsify/commit/2e00f4c))
+
+
+
+## [4.1.14](https://github.com/QingWei-Li/docsify/compare/v4.1.13...v4.1.14) (2017-06-24)
+
+### Bug Fixes
+
+- get file path, fixed jrappen/sublime-distractionless/commit/81bfadd391428823191cc03eca956a2312e04d13#commitcomment-22427070 ([e8117e5](https://github.com/QingWei-Li/docsify/commit/e8117e5)), closes [jrappen/sublime-distractionless/commit/81bfadd391428823191cc03eca956a2312e04d13#commitcomment-22427070](https://github.com/jrappen/sublime-distractionless/commit/81bfadd391428823191cc03eca956a2312e04d13/issues/commitcomment-22427070)
+
+### Features
+
+- add context attribute, fixed [#191](https://github.com/QingWei-Li/docsify/issues/191) ([ce0e9ac](https://github.com/QingWei-Li/docsify/commit/ce0e9ac))
+
+
+
+## [4.1.13](https://github.com/QingWei-Li/docsify/compare/v4.1.12...v4.1.13) (2017-06-11)
+
+
+
+## [4.1.12](https://github.com/QingWei-Li/docsify/compare/v4.1.11...v4.1.12) (2017-06-03)
+
+### Bug Fixes
+
+- **render:** subtitle in side bar shows undefined, fixed [#182](https://github.com/QingWei-Li/docsify/issues/182) ([d087d57](https://github.com/QingWei-Li/docsify/commit/d087d57))
+
+
+
+## [4.1.11](https://github.com/QingWei-Li/docsify/compare/v4.1.10...v4.1.11) (2017-06-02)
+
+### Bug Fixes
+
+- **compiler:** force reset toc when rendering sidebar fixed [#181](https://github.com/QingWei-Li/docsify/issues/181) ([ccf4c7c](https://github.com/QingWei-Li/docsify/commit/ccf4c7c))
+- **render:** autoHeader does not work ([1304d2e](https://github.com/QingWei-Li/docsify/commit/1304d2e))
+
+
+
+## [4.1.10](https://github.com/QingWei-Li/docsify/compare/v4.1.9...v4.1.10) (2017-06-02)
+
+### Bug Fixes
+
+- **hash:** hash routing crashes when url has querystring ([6d48ce1](https://github.com/QingWei-Li/docsify/commit/6d48ce1))
+
+
+
+## [4.1.9](https://github.com/QingWei-Li/docsify/compare/v4.1.8...v4.1.9) (2017-05-31)
+
+### Bug Fixes
+
+- can't render toc on first load ([d9b487e](https://github.com/QingWei-Li/docsify/commit/d9b487e))
+- **lifecycle:** continue to handle data ([955d3d5](https://github.com/QingWei-Li/docsify/commit/955d3d5))
+- **render:** broken name link, fixed [#167](https://github.com/QingWei-Li/docsify/issues/167) ([91b66a5](https://github.com/QingWei-Li/docsify/commit/91b66a5))
+
+
+
+## [4.1.8](https://github.com/QingWei-Li/docsify/compare/v4.1.7...v4.1.8) (2017-05-31)
+
+### Bug Fixes
+
+- auto replace version ([22b50f0](https://github.com/QingWei-Li/docsify/commit/22b50f0))
+- update edit button demo ([ec887c1](https://github.com/QingWei-Li/docsify/commit/ec887c1))
+
+### Features
+
+- add edit button demo ([a64cee1](https://github.com/QingWei-Li/docsify/commit/a64cee1))
+- add edit button demo, close [#162](https://github.com/QingWei-Li/docsify/issues/162) ([036fdac](https://github.com/QingWei-Li/docsify/commit/036fdac))
+
+
+
+## [4.1.7](https://github.com/QingWei-Li/docsify/compare/v4.1.6...v4.1.7) (2017-05-30)
+
+### Bug Fixes
+
+- **ssr:** clean files ([0014895](https://github.com/QingWei-Li/docsify/commit/0014895))
+
+
+
+## [4.1.6](https://github.com/QingWei-Li/docsify/compare/v4.1.5...v4.1.6) (2017-05-30)
+
+### Bug Fixes
+
+- **ssr:** add debug ([6b9e092](https://github.com/QingWei-Li/docsify/commit/6b9e092))
+
+
+
+## [4.1.5](https://github.com/QingWei-Li/docsify/compare/v4.1.4...v4.1.5) (2017-05-30)
+
+### Bug Fixes
+
+- **ssr:** missing package ([6db8c9e](https://github.com/QingWei-Li/docsify/commit/6db8c9e))
+
+
+
+## [4.1.4](https://github.com/QingWei-Li/docsify/compare/v4.1.3...v4.1.4) (2017-05-30)
+
+### Bug Fixes
+
+- **ssr:** file path ([79a83bc](https://github.com/QingWei-Li/docsify/commit/79a83bc))
+
+
+
+## [4.1.3](https://github.com/QingWei-Li/docsify/compare/v4.1.2...v4.1.3) (2017-05-30)
+
+### Bug Fixes
+
+- update babel config ([9825db4](https://github.com/QingWei-Li/docsify/commit/9825db4))
+
+
+
+## [4.1.2](https://github.com/QingWei-Li/docsify/compare/v4.1.1...v4.1.2) (2017-05-30)
+
+### Bug Fixes
+
+- update babel config ([80dba19](https://github.com/QingWei-Li/docsify/commit/80dba19))
+
+
+
+## [4.1.1](https://github.com/QingWei-Li/docsify/compare/v4.1.0...v4.1.1) (2017-05-30)
+
+### Bug Fixes
+
+- build for ssr package ([4cb20a5](https://github.com/QingWei-Li/docsify/commit/4cb20a5))
+- remove history mode ([0e74e6c](https://github.com/QingWei-Li/docsify/commit/0e74e6c))
+
+
+
+# [4.1.0](https://github.com/QingWei-Li/docsify/compare/v4.0.2...v4.1.0) (2017-05-30)
+
+
+
+## [4.0.2](https://github.com/QingWei-Li/docsify/compare/v4.0.1...v4.0.2) (2017-05-30)
+
+### Bug Fixes
+
+- basePath for history mode ([fc1cd3f](https://github.com/QingWei-Li/docsify/commit/fc1cd3f))
+
+
+
+## [4.0.1](https://github.com/QingWei-Li/docsify/compare/v4.0.0...v4.0.1) (2017-05-29)
+
+### Bug Fixes
+
+- **ssr:** remove context ([4626157](https://github.com/QingWei-Li/docsify/commit/4626157))
+- lint ([b764b6e](https://github.com/QingWei-Li/docsify/commit/b764b6e))
+
+
+
+# [4.0.0](https://github.com/QingWei-Li/docsify/compare/v3.7.3...v4.0.0) (2017-05-29)
+
+### Bug Fixes
+
+- **render:** init event in ssr ([eba1c98](https://github.com/QingWei-Li/docsify/commit/eba1c98))
+- lint ([1f4514d](https://github.com/QingWei-Li/docsify/commit/1f4514d))
+
+### Features
+
+- finish ssr ([3444884](https://github.com/QingWei-Li/docsify/commit/3444884))
+- init ocsify-server-renderer ([6dea685](https://github.com/QingWei-Li/docsify/commit/6dea685))
+- support history mode ([f095eb8](https://github.com/QingWei-Li/docsify/commit/f095eb8))
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..77d2ce7
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,67 @@
+# Contribute
+
+## Introduction
+
+First, thank you for considering contributing to docsify! It's people like you that make the open source community such a great community! 😊
+
+We welcome any type of contribution, not only code. You can help with
+- **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
+- **Marketing**: writing blog posts, howto's, printing stickers, ...
+- **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
+- **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them.
+- **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/docsify).
+
+## Your First Contribution
+
+Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
+
+## Submitting code
+
+Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests.
+
+## Code review process
+
+The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge.
+It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you?
+
+## Financial contributions
+
+We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/docsify).
+Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed.
+
+## Questions
+
+If you have any questions, create an [issue](issue) (protip: do a quick search first to see if someone else didn't ask the same question before!).
+You can also reach us at hello@docsify.opencollective.com.
+
+## Credits
+
+### Contributors
+
+Thank you to all the people who have already contributed to docsify!
+
+
+
+### Backers
+
+Thank you to all our backers! [[Become a backer](https://opencollective.com/docsify#backer)]
+
+
+
+
+### Sponsors
+
+Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/docsify#sponsor))
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/HISTORY.md b/HISTORY.md
new file mode 100644
index 0000000..fb720fd
--- /dev/null
+++ b/HISTORY.md
@@ -0,0 +1,736 @@
+
+
+## [3.7.3](https://github.com/QingWei-Li/docsify/compare/v3.7.2...v3.7.3) (2017-05-22)
+
+
+### Bug Fixes
+
+* **render:** find => filter ([eca3368](https://github.com/QingWei-Li/docsify/commit/eca3368))
+
+
+
+
+## [3.7.2](https://github.com/QingWei-Li/docsify/compare/v3.7.1...v3.7.2) (2017-05-19)
+
+
+
+
+## [3.7.1](https://github.com/QingWei-Li/docsify/compare/v3.7.0...v3.7.1) (2017-05-19)
+
+
+### Bug Fixes
+
+* docsify-updated is undefined ([b2b4742](https://github.com/QingWei-Li/docsify/commit/b2b4742))
+
+
+
+
+# [3.7.0](https://github.com/QingWei-Li/docsify/compare/v3.6.6...v3.7.0) (2017-05-16)
+
+
+### Features
+
+* add docsify-updated, close [#158](https://github.com/QingWei-Li/docsify/issues/158) ([d2be5ae](https://github.com/QingWei-Li/docsify/commit/d2be5ae))
+* add externalLinkTarget, close [#149](https://github.com/QingWei-Li/docsify/issues/149) ([2d73285](https://github.com/QingWei-Li/docsify/commit/2d73285))
+
+
+
+
+## [3.6.6](https://github.com/QingWei-Li/docsify/compare/v3.6.5...v3.6.6) (2017-05-06)
+
+
+### Features
+
+* support query string for the search, fixed [#156](https://github.com/QingWei-Li/docsify/issues/156) ([da75d70](https://github.com/QingWei-Li/docsify/commit/da75d70))
+
+
+
+
+## [3.6.5](https://github.com/QingWei-Li/docsify/compare/v3.6.4...v3.6.5) (2017-04-28)
+
+
+### Bug Fixes
+
+* **util:** fix crash, fixed [#154](https://github.com/QingWei-Li/docsify/issues/154) ([51832d3](https://github.com/QingWei-Li/docsify/commit/51832d3))
+
+
+
+
+## [3.6.4](https://github.com/QingWei-Li/docsify/compare/v3.6.3...v3.6.4) (2017-04-28)
+
+
+### Bug Fixes
+
+* **util:** correctly clean up duplicate slashes, fixed [#153](https://github.com/QingWei-Li/docsify/issues/153) ([76c041a](https://github.com/QingWei-Li/docsify/commit/76c041a))
+
+
+
+
+## [3.6.3](https://github.com/QingWei-Li/docsify/compare/v3.6.2...v3.6.3) (2017-04-25)
+
+
+### Bug Fixes
+
+* **external-script:** script attrs ([2653849](https://github.com/QingWei-Li/docsify/commit/2653849))
+
+
+
+
+## [3.6.2](https://github.com/QingWei-Li/docsify/compare/v3.6.0...v3.6.2) (2017-04-12)
+
+
+### Features
+
+* **event:** Collapse the sidebar when click outside element in the small screen ([9b7e5f5](https://github.com/QingWei-Li/docsify/commit/9b7e5f5))
+* **external-script:** detect more than one script dom, fixed [#146](https://github.com/QingWei-Li/docsify/issues/146) ([94d6603](https://github.com/QingWei-Li/docsify/commit/94d6603))
+
+
+
+
+# [3.6.0](https://github.com/QingWei-Li/docsify/compare/v3.5.2...v3.6.0) (2017-04-09)
+
+
+### Features
+
+* **render:** add mergeNavbar option, close [#125](https://github.com/QingWei-Li/docsify/issues/125), [#124](https://github.com/QingWei-Li/docsify/issues/124) ([#145](https://github.com/QingWei-Li/docsify/issues/145)) ([9220523](https://github.com/QingWei-Li/docsify/commit/9220523))
+
+
+
+
+## [3.5.2](https://github.com/QingWei-Li/docsify/compare/v3.5.1...v3.5.2) (2017-04-05)
+
+
+
+
+## [3.5.1](https://github.com/QingWei-Li/docsify/compare/v3.5.0...v3.5.1) (2017-03-25)
+
+
+### Bug Fixes
+
+* .md file extension regex ([594299f](https://github.com/QingWei-Li/docsify/commit/594299f))
+
+
+
+
+# [3.5.0](https://github.com/QingWei-Li/docsify/compare/v3.4.4...v3.5.0) (2017-03-25)
+
+
+### Bug Fixes
+
+* adjust display on small screens ([bf35471](https://github.com/QingWei-Li/docsify/commit/bf35471))
+* navbar labels for German ([b022aaf](https://github.com/QingWei-Li/docsify/commit/b022aaf))
+
+
+### Features
+
+* **route:** auto remove .md extension ([8f11653](https://github.com/QingWei-Li/docsify/commit/8f11653))
+
+
+
+
+## [3.4.4](https://github.com/QingWei-Li/docsify/compare/v3.4.3...v3.4.4) (2017-03-17)
+
+
+### Bug Fixes
+
+* **search:** fix input style ([2d6a51b](https://github.com/QingWei-Li/docsify/commit/2d6a51b))
+
+
+
+
+## [3.4.3](https://github.com/QingWei-Li/docsify/compare/v3.4.2...v3.4.3) (2017-03-16)
+
+
+
+
+## [3.4.2](https://github.com/QingWei-Li/docsify/compare/v3.4.1...v3.4.2) (2017-03-11)
+
+
+### Features
+
+* **emojify:** add no-emoji option ([3aef37a](https://github.com/QingWei-Li/docsify/commit/3aef37a))
+
+
+
+
+## [3.4.1](https://github.com/QingWei-Li/docsify/compare/v3.4.0...v3.4.1) (2017-03-10)
+
+
+### Bug Fixes
+
+* **dom:** Disable the dom cache when vue is present, fixed [#119](https://github.com/QingWei-Li/docsify/issues/119) ([b9a7275](https://github.com/QingWei-Li/docsify/commit/b9a7275))
+
+
+
+
+# [3.4.0](https://github.com/QingWei-Li/docsify/compare/v3.3.0...v3.4.0) (2017-03-09)
+
+
+### Features
+
+* **zoom-image:** add plugin ([50fa6fc](https://github.com/QingWei-Li/docsify/commit/50fa6fc))
+
+
+
+
+# [3.3.0](https://github.com/QingWei-Li/docsify/compare/v3.2.0...v3.3.0) (2017-03-07)
+
+
+
+
+# [3.2.0](https://github.com/QingWei-Li/docsify/compare/v3.1.2...v3.2.0) (2017-02-28)
+
+
+### Bug Fixes
+
+* **fetch:** load sidebar and navbar for parent path, fixed [#100](https://github.com/QingWei-Li/docsify/issues/100) ([f3fc596](https://github.com/QingWei-Li/docsify/commit/f3fc596))
+* **render:** Toc rendering error, fixed [#106](https://github.com/QingWei-Li/docsify/issues/106) ([0d59ee9](https://github.com/QingWei-Li/docsify/commit/0d59ee9))
+
+
+### Features
+
+* **search:** Localization for no data tip, close [#103](https://github.com/QingWei-Li/docsify/issues/103) ([d3c9fbd](https://github.com/QingWei-Li/docsify/commit/d3c9fbd))
+
+
+
+
+## [3.1.2](https://github.com/QingWei-Li/docsify/compare/v3.1.1...v3.1.2) (2017-02-27)
+
+
+
+
+## [3.1.1](https://github.com/QingWei-Li/docsify/compare/v3.1.0...v3.1.1) (2017-02-24)
+
+
+### Bug Fixes
+
+* **render:** custom cover background image ([8f9bf29](https://github.com/QingWei-Li/docsify/commit/8f9bf29))
+* **search:** don't search nameLink, fixed [#102](https://github.com/QingWei-Li/docsify/issues/102) ([507d9e8](https://github.com/QingWei-Li/docsify/commit/507d9e8))
+* **tpl:** extra character, fixed [#101](https://github.com/QingWei-Li/docsify/issues/101) ([d67d25f](https://github.com/QingWei-Li/docsify/commit/d67d25f))
+
+
+
+
+# [3.1.0](https://github.com/QingWei-Li/docsify/compare/v3.0.5...v3.1.0) (2017-02-22)
+
+
+### Bug Fixes
+
+* **search:** incorrect anchor link, fixed [#90](https://github.com/QingWei-Li/docsify/issues/90) ([b8a3d8f](https://github.com/QingWei-Li/docsify/commit/b8a3d8f))
+* **sw:** update white list ([f2975a5](https://github.com/QingWei-Li/docsify/commit/f2975a5))
+
+
+### Features
+
+* **emoji:** add emoji plugin ([855c450](https://github.com/QingWei-Li/docsify/commit/855c450))
+
+
+
+
+## [3.0.5](https://github.com/QingWei-Li/docsify/compare/v3.0.4...v3.0.5) (2017-02-21)
+
+
+### Bug Fixes
+
+* **event:** highlight sidebar when clicked, fixed [#86](https://github.com/QingWei-Li/docsify/issues/86) ([2a1157a](https://github.com/QingWei-Li/docsify/commit/2a1157a))
+* **gen-tree:** cache toc list, fixed [#88](https://github.com/QingWei-Li/docsify/issues/88) ([3394ebb](https://github.com/QingWei-Li/docsify/commit/3394ebb))
+* **layout.css:** loading style ([42b2dba](https://github.com/QingWei-Li/docsify/commit/42b2dba))
+
+
+### Features
+
+* **pwa:** add sw.js ([f7111b5](https://github.com/QingWei-Li/docsify/commit/f7111b5))
+
+
+
+
+## [3.0.4](https://github.com/QingWei-Li/docsify/compare/v3.0.3...v3.0.4) (2017-02-20)
+
+
+### Bug Fixes
+
+* **render:** disable rendering sub list when loadSidebar is false ([35dd2e1](https://github.com/QingWei-Li/docsify/commit/35dd2e1))
+* **render:** execute script ([780c1e5](https://github.com/QingWei-Li/docsify/commit/780c1e5))
+
+
+
+
+## [3.0.3](https://github.com/QingWei-Li/docsify/compare/v3.0.2...v3.0.3) (2017-02-19)
+
+
+
+
+## [3.0.2](https://github.com/QingWei-Li/docsify/compare/v3.0.1...v3.0.2) (2017-02-19)
+
+
+### Bug Fixes
+
+* **compiler:** link ([3b127a1](https://github.com/QingWei-Li/docsify/commit/3b127a1))
+* **search:** add lazy input ([bf593a7](https://github.com/QingWei-Li/docsify/commit/bf593a7))
+
+
+
+
+## [3.0.1](https://github.com/QingWei-Li/docsify/compare/v3.0.0...v3.0.1) (2017-02-19)
+
+
+### Bug Fixes
+
+* **route:** empty alias ([cd99b52](https://github.com/QingWei-Li/docsify/commit/cd99b52))
+
+
+
+
+# [3.0.0](https://github.com/QingWei-Li/docsify/compare/v2.4.3...v3.0.0) (2017-02-19)
+
+
+### Bug Fixes
+
+* **compiler:** link ([c7e09c3](https://github.com/QingWei-Li/docsify/commit/c7e09c3))
+* **render:** support html file ([7b6a2ac](https://github.com/QingWei-Li/docsify/commit/7b6a2ac))
+* **search:** escape html ([fcb66e8](https://github.com/QingWei-Li/docsify/commit/fcb66e8))
+* **search:** fix default config ([2efd859](https://github.com/QingWei-Li/docsify/commit/2efd859))
+
+
+### Features
+
+* **front-matter:** add front matter[WIP] ([dbb9278](https://github.com/QingWei-Li/docsify/commit/dbb9278))
+* **render:** add auto header ([b7768b1](https://github.com/QingWei-Li/docsify/commit/b7768b1))
+* **search:** Localization for search placeholder, close [#80](https://github.com/QingWei-Li/docsify/issues/80) ([2351c3e](https://github.com/QingWei-Li/docsify/commit/2351c3e))
+* **themes:** add loading info ([86594a3](https://github.com/QingWei-Li/docsify/commit/86594a3))
+
+
+
+
+## [2.4.3](https://github.com/QingWei-Li/docsify/compare/v2.4.2...v2.4.3) (2017-02-15)
+
+
+
+
+## [2.4.2](https://github.com/QingWei-Li/docsify/compare/v2.4.1...v2.4.2) (2017-02-14)
+
+
+### Bug Fixes
+
+* **index:** load file path error ([dc536a3](https://github.com/QingWei-Li/docsify/commit/dc536a3))
+
+
+
+
+## [2.4.1](https://github.com/QingWei-Li/docsify/compare/v2.4.0...v2.4.1) (2017-02-13)
+
+
+### Bug Fixes
+
+* **index:** cover page ([dd0c84b](https://github.com/QingWei-Li/docsify/commit/dd0c84b))
+
+
+
+
+# [2.4.0](https://github.com/QingWei-Li/docsify/compare/v2.3.0...v2.4.0) (2017-02-13)
+
+
+### Features
+
+* **hook:** add doneEach ([c6f7602](https://github.com/QingWei-Li/docsify/commit/c6f7602))
+
+
+
+
+# [2.3.0](https://github.com/QingWei-Li/docsify/compare/v2.2.1...v2.3.0) (2017-02-13)
+
+
+### Bug Fixes
+
+* **event:** has no effect on a FF mobile browser, fixed [#67](https://github.com/QingWei-Li/docsify/issues/67) ([0ff36c2](https://github.com/QingWei-Li/docsify/commit/0ff36c2))
+* **render:** custom marked renderer ([bf559b4](https://github.com/QingWei-Li/docsify/commit/bf559b4))
+* **render:** fix render link ([a866744](https://github.com/QingWei-Li/docsify/commit/a866744))
+* **render:** image url ([6f87529](https://github.com/QingWei-Li/docsify/commit/6f87529))
+* **render:** render link ([38ea660](https://github.com/QingWei-Li/docsify/commit/38ea660))
+* **src:** fix route ([324301a](https://github.com/QingWei-Li/docsify/commit/324301a))
+* **src:** get alias ([784173e](https://github.com/QingWei-Li/docsify/commit/784173e))
+* **src:** get alias ([ce99a04](https://github.com/QingWei-Li/docsify/commit/ce99a04))
+* **themes:** fix navbar style ([fa54b52](https://github.com/QingWei-Li/docsify/commit/fa54b52))
+* **themes:** update navbar style ([4864d1b](https://github.com/QingWei-Li/docsify/commit/4864d1b))
+
+
+### Features
+
+* **hook:** support custom plugin ([9e81a59](https://github.com/QingWei-Li/docsify/commit/9e81a59))
+* **src:** add alias feature ([24412cd](https://github.com/QingWei-Li/docsify/commit/24412cd))
+* **src:** dynamic title and fix sidebar style ([6b30eb6](https://github.com/QingWei-Li/docsify/commit/6b30eb6))
+
+
+
+
+## [2.2.1](https://github.com/QingWei-Li/docsify/compare/v2.2.0...v2.2.1) (2017-02-11)
+
+
+### Bug Fixes
+
+* **event:** scroll active sidebar ([50f5fc2](https://github.com/QingWei-Li/docsify/commit/50f5fc2))
+* **search:** crash when not content, fixed [#68](https://github.com/QingWei-Li/docsify/issues/68) ([9d3cc89](https://github.com/QingWei-Li/docsify/commit/9d3cc89))
+* **search:** not work in mobile ([3941304](https://github.com/QingWei-Li/docsify/commit/3941304))
+
+
+
+
+# [2.2.0](https://github.com/QingWei-Li/docsify/compare/v2.1.0...v2.2.0) (2017-02-09)
+
+
+### Features
+
+* **plugins:** add Google Analytics plugin ([#66](https://github.com/QingWei-Li/docsify/issues/66)) ([ac61bb0](https://github.com/QingWei-Li/docsify/commit/ac61bb0))
+
+
+
+
+# [2.1.0](https://github.com/QingWei-Li/docsify/compare/v2.0.3...v2.1.0) (2017-02-09)
+
+
+### Bug Fixes
+
+* render name ([12e2479](https://github.com/QingWei-Li/docsify/commit/12e2479))
+* **vue.css:** update sidebar style ([fc140ef](https://github.com/QingWei-Li/docsify/commit/fc140ef))
+
+
+### Features
+
+* add search, close [#43](https://github.com/QingWei-Li/docsify/issues/43) ([eb5ff3e](https://github.com/QingWei-Li/docsify/commit/eb5ff3e))
+
+
+
+
+## [2.0.3](https://github.com/QingWei-Li/docsify/compare/v2.0.2...v2.0.3) (2017-02-07)
+
+
+### Bug Fixes
+
+* css var polyfill ([8cd386a](https://github.com/QingWei-Li/docsify/commit/8cd386a))
+* css var polyfill ([cbaee21](https://github.com/QingWei-Li/docsify/commit/cbaee21))
+* rendering emojis ([8c7e4d7](https://github.com/QingWei-Li/docsify/commit/8c7e4d7))
+
+
+
+
+## [2.0.2](https://github.com/QingWei-Li/docsify/compare/v2.0.1...v2.0.2) (2017-02-05)
+
+
+### Bug Fixes
+
+* button style in cover page ([4470855](https://github.com/QingWei-Li/docsify/commit/4470855))
+
+
+
+
+## [2.0.1](https://github.com/QingWei-Li/docsify/compare/v2.0.0...v2.0.1) (2017-02-05)
+
+
+
+
+# [2.0.0](https://github.com/QingWei-Li/docsify/compare/v1.10.5...v2.0.0) (2017-02-05)
+
+
+### Features
+
+* customize the theme color ([5cc9f05](https://github.com/QingWei-Li/docsify/commit/5cc9f05))
+
+
+
+
+## [1.10.5](https://github.com/QingWei-Li/docsify/compare/v1.10.4...v1.10.5) (2017-01-28)
+
+
+
+
+## [1.10.4](https://github.com/QingWei-Li/docsify/compare/v1.10.3...v1.10.4) (2017-01-27)
+
+
+
+
+## [1.10.3](https://github.com/QingWei-Li/docsify/compare/v1.10.2...v1.10.3) (2017-01-27)
+
+
+
+
+## [1.10.2](https://github.com/QingWei-Li/docsify/compare/v1.10.1...v1.10.2) (2017-01-25)
+
+
+
+
+## [1.10.1](https://github.com/QingWei-Li/docsify/compare/v1.10.0...v1.10.1) (2017-01-25)
+
+
+
+
+# [1.10.0](https://github.com/QingWei-Li/docsify/compare/v1.9.0...v1.10.0) (2017-01-25)
+
+
+
+
+# [1.9.0](https://github.com/QingWei-Li/docsify/compare/v1.8.0...v1.9.0) (2017-01-24)
+
+
+
+
+# [1.8.0](https://github.com/QingWei-Li/docsify/compare/v1.7.4...v1.8.0) (2017-01-24)
+
+
+
+
+## [1.7.4](https://github.com/QingWei-Li/docsify/compare/v1.7.3...v1.7.4) (2017-01-13)
+
+
+
+
+## [1.7.3](https://github.com/QingWei-Li/docsify/compare/v1.7.2...v1.7.3) (2017-01-13)
+
+
+
+
+## [1.7.2](https://github.com/QingWei-Li/docsify/compare/v1.7.1...v1.7.2) (2017-01-12)
+
+
+
+
+## [1.7.1](https://github.com/QingWei-Li/docsify/compare/v1.7.0...v1.7.1) (2017-01-12)
+
+
+
+
+# [1.7.0](https://github.com/QingWei-Li/docsify/compare/v1.6.1...v1.7.0) (2017-01-12)
+
+
+
+
+## [1.6.1](https://github.com/QingWei-Li/docsify/compare/v1.6.0...v1.6.1) (2017-01-10)
+
+
+
+
+# [1.6.0](https://github.com/QingWei-Li/docsify/compare/v1.5.2...v1.6.0) (2017-01-10)
+
+
+
+
+## [1.5.2](https://github.com/QingWei-Li/docsify/compare/v1.5.1...v1.5.2) (2017-01-10)
+
+
+
+
+## [1.5.1](https://github.com/QingWei-Li/docsify/compare/v1.5.0...v1.5.1) (2017-01-09)
+
+
+
+
+# [1.5.0](https://github.com/QingWei-Li/docsify/compare/v1.4.3...v1.5.0) (2017-01-04)
+
+
+### Features
+
+* Markdown parser is configurable, [#42](https://github.com/QingWei-Li/docsify/issues/42) ([8b1000a](https://github.com/QingWei-Li/docsify/commit/8b1000a))
+
+
+
+
+## [1.4.3](https://github.com/QingWei-Li/docsify/compare/v1.4.2...v1.4.3) (2017-01-01)
+
+
+
+
+## [1.4.2](https://github.com/QingWei-Li/docsify/compare/v1.4.1...v1.4.2) (2016-12-31)
+
+
+
+
+## [1.4.1](https://github.com/QingWei-Li/docsify/compare/v1.4.0...v1.4.1) (2016-12-31)
+
+
+
+
+# [1.4.0](https://github.com/QingWei-Li/docsify/compare/v1.3.5...v1.4.0) (2016-12-31)
+
+
+
+
+## [1.3.5](https://github.com/QingWei-Li/docsify/compare/v1.3.4...v1.3.5) (2016-12-25)
+
+
+
+
+## [1.3.4](https://github.com/QingWei-Li/docsify/compare/v1.3.3...v1.3.4) (2016-12-25)
+
+
+
+
+## [1.3.3](https://github.com/QingWei-Li/docsify/compare/v1.3.2...v1.3.3) (2016-12-23)
+
+
+
+
+## [1.3.2](https://github.com/QingWei-Li/docsify/compare/v1.3.1...v1.3.2) (2016-12-22)
+
+
+
+
+## [1.3.1](https://github.com/QingWei-Li/docsify/compare/v1.3.0...v1.3.1) (2016-12-22)
+
+
+
+
+# [1.3.0](https://github.com/QingWei-Li/docsify/compare/v1.2.0...v1.3.0) (2016-12-21)
+
+
+
+
+# [1.2.0](https://github.com/QingWei-Li/docsify/compare/v1.1.7...v1.2.0) (2016-12-20)
+
+
+
+
+## [1.1.7](https://github.com/QingWei-Li/docsify/compare/v1.1.6...v1.1.7) (2016-12-19)
+
+
+
+
+## [1.1.6](https://github.com/QingWei-Li/docsify/compare/v1.1.5...v1.1.6) (2016-12-18)
+
+
+
+
+## [1.1.5](https://github.com/QingWei-Li/docsify/compare/v1.1.4...v1.1.5) (2016-12-18)
+
+
+
+
+## [1.1.4](https://github.com/QingWei-Li/docsify/compare/v1.1.3...v1.1.4) (2016-12-17)
+
+
+
+
+## [1.1.3](https://github.com/QingWei-Li/docsify/compare/v1.1.2...v1.1.3) (2016-12-17)
+
+
+
+
+## [1.1.2](https://github.com/QingWei-Li/docsify/compare/v1.1.1...v1.1.2) (2016-12-17)
+
+
+
+
+## [1.1.1](https://github.com/QingWei-Li/docsify/compare/v1.1.0...v1.1.1) (2016-12-17)
+
+
+
+
+# [1.1.0](https://github.com/QingWei-Li/docsify/compare/v1.0.3...v1.1.0) (2016-12-16)
+
+
+
+
+## [1.0.3](https://github.com/QingWei-Li/docsify/compare/v1.0.2...v1.0.3) (2016-12-13)
+
+
+
+
+## [1.0.2](https://github.com/QingWei-Li/docsify/compare/v1.0.1...v1.0.2) (2016-12-13)
+
+
+
+
+## [1.0.1](https://github.com/QingWei-Li/docsify/compare/v1.0.0...v1.0.1) (2016-12-08)
+
+
+
+
+# [1.0.0](https://github.com/QingWei-Li/docsify/compare/v0.7.0...v1.0.0) (2016-12-08)
+
+
+
+
+# [0.7.0](https://github.com/QingWei-Li/docsify/compare/v0.6.1...v0.7.0) (2016-11-30)
+
+
+
+
+## [0.6.1](https://github.com/QingWei-Li/docsify/compare/v0.6.0...v0.6.1) (2016-11-29)
+
+
+
+
+# [0.6.0](https://github.com/QingWei-Li/docsify/compare/v0.5.0...v0.6.0) (2016-11-29)
+
+
+
+
+# [0.5.0](https://github.com/QingWei-Li/docsify/compare/v0.4.2...v0.5.0) (2016-11-28)
+
+
+
+
+## [0.4.2](https://github.com/QingWei-Li/docsify/compare/v0.4.1...v0.4.2) (2016-11-28)
+
+
+
+
+## [0.4.1](https://github.com/QingWei-Li/docsify/compare/v0.4.0...v0.4.1) (2016-11-28)
+
+
+
+
+# [0.4.0](https://github.com/QingWei-Li/docsify/compare/v0.3.1...v0.4.0) (2016-11-27)
+
+
+### Features
+
+* custom sidebar, [#4](https://github.com/QingWei-Li/docsify/issues/4) ([#5](https://github.com/QingWei-Li/docsify/issues/5)) ([37e7984](https://github.com/QingWei-Li/docsify/commit/37e7984))
+
+
+
+
+## [0.3.1](https://github.com/QingWei-Li/docsify/compare/v0.3.0...v0.3.1) (2016-11-27)
+
+
+
+
+# [0.3.0](https://github.com/QingWei-Li/docsify/compare/v0.2.1...v0.3.0) (2016-11-27)
+
+
+
+
+## [0.2.1](https://github.com/QingWei-Li/docsify/compare/v0.2.0...v0.2.1) (2016-11-26)
+
+
+
+
+# [0.2.0](https://github.com/QingWei-Li/docsify/compare/v0.1.0...v0.2.0) (2016-11-26)
+
+
+
+
+# [0.1.0](https://github.com/QingWei-Li/docsify/compare/v0.0.5...v0.1.0) (2016-11-26)
+
+
+
+
+## [0.0.5](https://github.com/QingWei-Li/docsify/compare/v0.0.4...v0.0.5) (2016-11-24)
+
+
+
+
+## [0.0.4](https://github.com/QingWei-Li/docsify/compare/v0.0.3...v0.0.4) (2016-11-22)
+
+
+
+
+## [0.0.3](https://github.com/QingWei-Li/docsify/compare/v0.0.2...v0.0.3) (2016-11-20)
+
+
+
+
+## [0.0.2](https://github.com/QingWei-Li/docsify/compare/v0.0.1...v0.0.2) (2016-11-20)
+
+
+
+
+## 0.0.1 (2016-11-20)
diff --git a/LICENSE b/LICENSE
index 4808f79..37a4ac5 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2016 cinwell.li
+Copyright (c) 2016 - present cinwell.li
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 70c0e1e..b8da0d8 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
@@ -9,52 +9,60 @@
Gold Sponsor via Open Collective
+ +
+
+
+
'
- + (escaped ? code : escape(code, true))
- + '\n';
- }
-
- return ''
- + (escaped ? code : escape(code, true))
- + '\n\n';
-};
-
-Renderer.prototype.blockquote = function(quote) {
- return '\n' + quote + '\n'; -}; - -Renderer.prototype.html = function(html) { - return html; -}; - -Renderer.prototype.heading = function(text, level, raw) { - return '
' + text + '
\n'; -}; - -Renderer.prototype.table = function(header, body) { - return '' + text + '';
-};
-
-Renderer.prototype.br = function() {
- return this.options.xhtml ? 'An error occured:
' - + escape(e.message + '', true) - + ''; - } - throw e; - } -} - -/** - * Options - */ - -marked.options = -marked.setOptions = function(opt) { - merge(marked.defaults, opt); - return marked; -}; - -marked.defaults = { - gfm: true, - tables: true, - breaks: false, - pedantic: false, - sanitize: false, - sanitizer: null, - mangle: true, - smartLists: false, - silent: false, - highlight: null, - langPrefix: 'lang-', - smartypants: false, - headerPrefix: '', - renderer: new Renderer, - xhtml: false -}; - -/** - * Expose - */ - -marked.Parser = Parser; -marked.parser = Parser.parse; - -marked.Renderer = Renderer; - -marked.Lexer = Lexer; -marked.lexer = Lexer.lex; - -marked.InlineLexer = InlineLexer; -marked.inlineLexer = InlineLexer.output; - -marked.parse = marked; - -if (typeof module !== 'undefined' && typeof exports === 'object') { - module.exports = marked; -} else if (typeof define === 'function' && define.amd) { - define(function() { return marked; }); -} else { - this.marked = marked; -} - -}).call(function() { - return this || (typeof window !== 'undefined' ? window : commonjsGlobal); -}()); -}); - -var prism = createCommonjsModule(function (module) { -/* ********************************************** - Begin prism-core.js -********************************************** */ - -var _self = (typeof window !== 'undefined') - ? window // if in browser - : ( - (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) - ? self // if in worker - : {} // if in node js - ); - -/** - * Prism: Lightweight, robust, elegant syntax highlighting - * MIT license http://www.opensource.org/licenses/mit-license.php/ - * @author Lea Verou http://lea.verou.me - */ - -var Prism = (function(){ - -// Private helper vars -var lang = /\blang(?:uage)?-(\w+)\b/i; -var uniqueId = 0; - -var _ = _self.Prism = { - util: { - encode: function (tokens) { - if (tokens instanceof Token) { - return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias); - } else if (_.util.type(tokens) === 'Array') { - return tokens.map(_.util.encode); - } else { - return tokens.replace(/&/g, '&').replace(/ text.length) { - // Something went terribly wrong, ABORT, ABORT! - break tokenloop; - } - - if (str instanceof Token) { - continue; - } - - pattern.lastIndex = 0; - - var match = pattern.exec(str), - delNum = 1; - - // Greedy patterns can override/remove up to two previously matched tokens - if (!match && greedy && i != strarr.length - 1) { - // Reconstruct the original text using the next two tokens - var nextToken = strarr[i + 1].matchedStr || strarr[i + 1], - combStr = str + nextToken; - - if (i < strarr.length - 2) { - combStr += strarr[i + 2].matchedStr || strarr[i + 2]; - } - - // Try the pattern again on the reconstructed text - pattern.lastIndex = 0; - match = pattern.exec(combStr); - if (!match) { - continue; - } - - var from = match.index + (lookbehind ? match[1].length : 0); - // To be a valid candidate, the new match has to start inside of str - if (from >= str.length) { - continue; - } - var to = match.index + match[0].length, - len = str.length + nextToken.length; - - // Number of tokens to delete and replace with the new match - delNum = 3; - - if (to <= len) { - if (strarr[i + 1].greedy) { - continue; - } - delNum = 2; - combStr = combStr.slice(0, len); - } - str = combStr; - } - - if (!match) { - continue; - } - - if(lookbehind) { - lookbehindLength = match[1].length; - } - - var from = match.index + lookbehindLength, - match = match[0].slice(lookbehindLength), - to = from + match.length, - before = str.slice(0, from), - after = str.slice(to); - - var args = [i, delNum]; - - if (before) { - args.push(before); - } - - var wrapped = new Token(token, inside? _.tokenize(match, inside) : match, alias, match, greedy); - - args.push(wrapped); - - if (after) { - args.push(after); - } - - Array.prototype.splice.apply(strarr, args); - } - } - } - - return strarr; - }, - - hooks: { - all: {}, - - add: function (name, callback) { - var hooks = _.hooks.all; - - hooks[name] = hooks[name] || []; - - hooks[name].push(callback); - }, - - run: function (name, env) { - var callbacks = _.hooks.all[name]; - - if (!callbacks || !callbacks.length) { - return; - } - - for (var i=0, callback; callback = callbacks[i++];) { - callback(env); - } - } - } -}; - -var Token = _.Token = function(type, content, alias, matchedStr, greedy) { - this.type = type; - this.content = content; - this.alias = alias; - // Copy of the full string this token was created from - this.matchedStr = matchedStr || null; - this.greedy = !!greedy; -}; - -Token.stringify = function(o, language, parent) { - if (typeof o == 'string') { - return o; - } - - if (_.util.type(o) === 'Array') { - return o.map(function(element) { - return Token.stringify(element, language, o); - }).join(''); - } - - var env = { - type: o.type, - content: Token.stringify(o.content, language, parent), - tag: 'span', - classes: ['token', o.type], - attributes: {}, - language: language, - parent: parent - }; - - if (env.type == 'comment') { - env.attributes['spellcheck'] = 'true'; - } - - if (o.alias) { - var aliases = _.util.type(o.alias) === 'Array' ? o.alias : [o.alias]; - Array.prototype.push.apply(env.classes, aliases); - } - - _.hooks.run('wrap', env); - - var attributes = ''; - - for (var name in env.attributes) { - attributes += (attributes ? ' ' : '') + name + '="' + (env.attributes[name] || '') + '"'; - } - - return '<' + env.tag + ' class="' + env.classes.join(' ') + '" ' + attributes + '>' + env.content + '' + env.tag + '>'; - -}; - -if (!_self.document) { - if (!_self.addEventListener) { - // in Node.js - return _self.Prism; - } - // In worker - _self.addEventListener('message', function(evt) { - var message = JSON.parse(evt.data), - lang = message.language, - code = message.code, - immediateClose = message.immediateClose; - - _self.postMessage(_.highlight(code, _.languages[lang], lang)); - if (immediateClose) { - _self.close(); - } - }, false); - - return _self.Prism; -} - -//Get current script and highlight -var script = document.currentScript || [].slice.call(document.getElementsByTagName("script")).pop(); - -if (script) { - _.filename = script.src; - - if (document.addEventListener && !script.hasAttribute('data-manual')) { - if(document.readyState !== "loading") { - requestAnimationFrame(_.highlightAll, 0); - } - else { - document.addEventListener('DOMContentLoaded', _.highlightAll); - } - } -} - -return _self.Prism; - -})(); - -if (typeof module !== 'undefined' && module.exports) { - module.exports = Prism; -} - -// hack for components to work correctly in node.js -if (typeof commonjsGlobal !== 'undefined') { - commonjsGlobal.Prism = Prism; -} - - -/* ********************************************** - Begin prism-markup.js -********************************************** */ - -Prism.languages.markup = { - 'comment': //, - 'prolog': /<\?[\w\W]+?\?>/, - 'doctype': //, - 'cdata': //i, - 'tag': { - pattern: /<\/?(?!\d)[^\s>\/=.$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i, - inside: { - 'tag': { - pattern: /^<\/?[^\s>\/]+/i, - inside: { - 'punctuation': /^<\/?/, - 'namespace': /^[^\s>\/:]+:/ - } - }, - 'attr-value': { - pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i, - inside: { - 'punctuation': /[=>"']/ - } - }, - 'punctuation': /\/?>/, - 'attr-name': { - pattern: /[^\s>\/]+/, - inside: { - 'namespace': /^[^\s>\/:]+:/ - } - } - - } - }, - 'entity': /?[\da-z]{1,8};/i -}; - -// Plugin to make entity title show the real entity, idea by Roman Komarov -Prism.hooks.add('wrap', function(env) { - - if (env.type === 'entity') { - env.attributes['title'] = env.content.replace(/&/, '&'); - } -}); - -Prism.languages.xml = Prism.languages.markup; -Prism.languages.html = Prism.languages.markup; -Prism.languages.mathml = Prism.languages.markup; -Prism.languages.svg = Prism.languages.markup; - - -/* ********************************************** - Begin prism-css.js -********************************************** */ - -Prism.languages.css = { - 'comment': /\/\*[\w\W]*?\*\//, - 'atrule': { - pattern: /@[\w-]+?.*?(;|(?=\s*\{))/i, - inside: { - 'rule': /@[\w-]+/ - // See rest below - } - }, - 'url': /url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i, - 'selector': /[^\{\}\s][^\{\};]*?(?=\s*\{)/, - 'string': /("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/, - 'property': /(\b|\B)[\w-]+(?=\s*:)/i, - 'important': /\B!important\b/i, - 'function': /[-a-z0-9]+(?=\()/i, - 'punctuation': /[(){};:]/ -}; - -Prism.languages.css['atrule'].inside.rest = Prism.util.clone(Prism.languages.css); - -if (Prism.languages.markup) { - Prism.languages.insertBefore('markup', 'tag', { - 'style': { - pattern: /(` +} diff --git a/src/core/router/history/abstract.js b/src/core/router/history/abstract.js new file mode 100644 index 0000000..2c0bd95 --- /dev/null +++ b/src/core/router/history/abstract.js @@ -0,0 +1,25 @@ +import {History} from './base' +import {parseQuery} from '../util' + +export class AbstractHistory extends History { + constructor(config) { + super(config) + this.mode = 'abstract' + } + + parse(path) { + let query = '' + + const queryIndex = path.indexOf('?') + if (queryIndex >= 0) { + query = path.slice(queryIndex + 1) + path = path.slice(0, queryIndex) + } + + return { + path, + file: this.getFile(path), + query: parseQuery(query) + } + } +} diff --git a/src/core/router/history/base.js b/src/core/router/history/base.js new file mode 100644 index 0000000..7ea763d --- /dev/null +++ b/src/core/router/history/base.js @@ -0,0 +1,86 @@ +import { + getPath, + isAbsolutePath, + stringifyQuery, + cleanPath, + replaceSlug, + resolvePath +} from '../util' +import {noop, merge} from '../../util/core' + +const cached = {} + +function getAlias(path, alias, last) { + const match = Object.keys(alias).filter(key => { + const re = cached[key] || (cached[key] = new RegExp(`^${key}$`)) + return re.test(path) && path !== last + })[0] + + return match ? + getAlias(path.replace(cached[match], alias[match]), alias, path) : + path +} + +function getFileName(path, ext) { + return new RegExp(`\\.(${ext.replace(/^\./, '')}|html)$`, 'g').test(path) ? + path : + /\/$/g.test(path) ? `${path}README${ext}` : `${path}${ext}` +} + +export class History { + constructor(config) { + this.config = config + } + + getBasePath() { + return this.config.basePath + } + + getFile(path = this.getCurrentPath(), isRelative) { + const {config} = this + const base = this.getBasePath() + const ext = typeof config.ext === 'string' ? config.ext : '.md' + + path = config.alias ? getAlias(path, config.alias) : path + path = getFileName(path, ext) + path = path === `/README${ext}` ? config.homepage || path : path + path = isAbsolutePath(path) ? path : getPath(base, path) + + if (isRelative) { + path = path.replace(new RegExp(`^${base}`), '') + } + + return path + } + + onchange(cb = noop) { + cb() + } + + getCurrentPath() {} + + normalize() {} + + parse() {} + + toURL(path, params, currentRoute) { + const local = currentRoute && path[0] === '#' + const route = this.parse(replaceSlug(path)) + + route.query = merge({}, route.query, params) + path = route.path + stringifyQuery(route.query) + path = path.replace(/\.md(\?)|\.md$/, '$1') + + if (local) { + const idIndex = currentRoute.indexOf('?') + path = + (idIndex > 0 ? currentRoute.substring(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) + } +} diff --git a/src/core/router/history/hash.js b/src/core/router/history/hash.js new file mode 100644 index 0000000..2674d5d --- /dev/null +++ b/src/core/router/history/hash.js @@ -0,0 +1,76 @@ +import {History} from './base' +import {noop} from '../../util/core' +import {on} from '../../util/dom' +import {parseQuery, cleanPath, replaceSlug} from '../util' + +function replaceHash(path) { + const i = location.href.indexOf('#') + location.replace(location.href.slice(0, i >= 0 ? i : 0) + '#' + path) +} + +export class HashHistory extends History { + constructor(config) { + super(config) + this.mode = 'hash' + } + + getBasePath() { + const path = window.location.pathname || '' + const base = this.config.basePath + + return /^(\/|https?:)/g.test(base) ? base : cleanPath(path + '/' + base) + } + + getCurrentPath() { + // We can't use location.hash here because it's not + // consistent across browsers - Firefox will pre-decode it! + const href = location.href + const index = href.indexOf('#') + return index === -1 ? '' : href.slice(index + 1) + } + + onchange(cb = noop) { + on('hashchange', cb) + } + + normalize() { + let path = this.getCurrentPath() + + path = replaceSlug(path) + + if (path.charAt(0) === '/') { + return replaceHash(path) + } + replaceHash('/' + path) + } + + /** + * Parse the url + * @param {string} [path=location.herf] + * @return {object} { path, query } + */ + parse(path = location.href) { + let query = '' + + const hashIndex = path.indexOf('#') + if (hashIndex >= 0) { + path = path.slice(hashIndex + 1) + } + + const queryIndex = path.indexOf('?') + if (queryIndex >= 0) { + query = path.slice(queryIndex + 1) + path = path.slice(0, queryIndex) + } + + return { + path, + file: this.getFile(path, true), + query: parseQuery(query) + } + } + + toURL(path, params, currentRoute) { + return '#' + super.toURL(path, params, currentRoute) + } +} diff --git a/src/core/router/history/html5.js b/src/core/router/history/html5.js new file mode 100644 index 0000000..04c5391 --- /dev/null +++ b/src/core/router/history/html5.js @@ -0,0 +1,65 @@ +import {History} from './base' +import {noop} from '../../util/core' +import {on} from '../../util/dom' +import {parseQuery, getPath} from '../util' + +export class HTML5History extends History { + constructor(config) { + super(config) + this.mode = 'history' + } + + getCurrentPath() { + const base = this.getBasePath() + let path = window.location.pathname + + if (base && path.indexOf(base) === 0) { + path = path.slice(base.length) + } + + return (path || '/') + window.location.search + window.location.hash + } + + onchange(cb = noop) { + on('click', e => { + const el = e.target.tagName === 'A' ? e.target : e.target.parentNode + + if (el.tagName === 'A' && !/_blank/.test(el.target)) { + e.preventDefault() + const url = el.href + window.history.pushState({key: url}, '', url) + cb() + } + }) + + on('popstate', cb) + } + + /** + * Parse the url + * @param {string} [path=location.href] + * @return {object} { path, query } + */ + parse(path = location.href) { + let query = '' + + const queryIndex = path.indexOf('?') + if (queryIndex >= 0) { + query = path.slice(queryIndex + 1) + path = path.slice(0, queryIndex) + } + + const base = getPath(location.origin) + const baseIndex = path.indexOf(base) + + if (baseIndex > -1) { + path = path.slice(baseIndex + base.length) + } + + return { + path, + file: this.getFile(path), + query: parseQuery(query) + } + } +} diff --git a/src/core/router/index.js b/src/core/router/index.js new file mode 100644 index 0000000..943fe6c --- /dev/null +++ b/src/core/router/index.js @@ -0,0 +1,45 @@ +import {HashHistory} from './history/hash' +import {HTML5History} from './history/html5' +import {supportsPushState} from '../util/env' +import * as dom from '../util/dom' + +export function routerMixin(proto) { + proto.route = {} +} + +let lastRoute = {} + +function updateRender(vm) { + vm.router.normalize() + vm.route = vm.router.parse() + dom.body.setAttribute('data-page', vm.route.file) +} + +export function initRouter(vm) { + const config = vm.config + const mode = config.routerMode || 'hash' + let router + + if (mode === 'history' && supportsPushState) { + router = new HTML5History(config) + } else { + router = new HashHistory(config) + } + + vm.router = router + updateRender(vm) + lastRoute = vm.route + + router.onchange(_ => { + updateRender(vm) + vm._updateRender() + + if (lastRoute.path === vm.route.path) { + vm.$resetEvents() + return + } + + vm.$fetch() + lastRoute = vm.route + }) +} diff --git a/src/core/router/util.js b/src/core/router/util.js new file mode 100644 index 0000000..2ed88c5 --- /dev/null +++ b/src/core/router/util.js @@ -0,0 +1,76 @@ +import {cached} from '../util/core' + +const decode = decodeURIComponent +const encode = encodeURIComponent + +export function parseQuery(query) { + const res = {} + + query = query.trim().replace(/^(\?|#|&)/, '') + + if (!query) { + return res + } + + // Simple parse + query.split('&').forEach(function (param) { + const parts = param.replace(/\+/g, ' ').split('=') + + res[parts[0]] = parts[1] && decode(parts[1]) + }) + + return res +} + +export function stringifyQuery(obj, ignores = []) { + const qs = [] + + for (const key in obj) { + if (ignores.indexOf(key) > -1) { + continue + } + qs.push( + obj[key] ? + `${encode(key)}=${encode(obj[key])}`.toLowerCase() : + encode(key) + ) + } + + return qs.length ? `?${qs.join('&')}` : '' +} + +export const isAbsolutePath = cached(path => { + return /(:|(\/{2}))/g.test(path) +}) + +export const getParentPath = cached(path => { + return /\/$/g.test(path) ? + path : + (path = path.match(/(\S*\/)[^/]+$/)) ? path[1] : '' +}) + +export const cleanPath = cached(path => { + 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) { + return cleanPath(args.join('/')) +} + +export const replaceSlug = cached(path => { + return path.replace('#', '?id=') +}) diff --git a/src/core/util/core.js b/src/core/util/core.js new file mode 100644 index 0000000..a94472d --- /dev/null +++ b/src/core/util/core.js @@ -0,0 +1,58 @@ +/** + * Create a cached version of a pure function. + */ +export function cached(fn) { + const cache = Object.create(null) + return function (str) { + const key = isPrimitive(str) ? str : JSON.stringify(str) + const hit = cache[key] + return hit || (cache[key] = fn(str)) + } +} + +/** + * Hyphenate a camelCase string. + */ +export const hyphenate = cached(str => { + return str.replace(/([A-Z])/g, m => '-' + m.toLowerCase()) +}) + +export const hasOwn = Object.prototype.hasOwnProperty + +/** + * Simple Object.assign polyfill + */ +export const merge = + Object.assign || + function (to) { + for (let i = 1; i < arguments.length; i++) { + const from = Object(arguments[i]) + + for (const key in from) { + if (hasOwn.call(from, key)) { + to[key] = from[key] + } + } + } + + return to + } + +/** + * Check if value is primitive + */ +export function isPrimitive(value) { + return typeof value === 'string' || typeof value === 'number' +} + +/** + * Perform no operation. + */ +export function noop() {} + +/** + * Check if value is function + */ +export function isFn(obj) { + return typeof obj === 'function' +} diff --git a/src/core/util/dom.js b/src/core/util/dom.js new file mode 100644 index 0000000..388927d --- /dev/null +++ b/src/core/util/dom.js @@ -0,0 +1,92 @@ +import {isFn} from '../util/core' +import {inBrowser} from './env' + +const cacheNode = {} + +/** + * Get Node + * @param {String|Element} el + * @param {Boolean} noCache + * @return {Element} + */ +export function getNode(el, noCache = false) { + if (typeof el === 'string') { + if (typeof window.Vue !== 'undefined') { + return find(el) + } + el = noCache ? find(el) : cacheNode[el] || (cacheNode[el] = find(el)) + } + + return el +} + +export const $ = inBrowser && document + +export const body = inBrowser && $.body + +export const head = inBrowser && $.head + +/** + * Find element + * @example + * find('nav') => document.querySelector('nav') + * find(nav, 'a') => nav.querySelector('a') + */ +export function find(el, node) { + return node ? el.querySelector(node) : $.querySelector(el) +} + +/** + * Find all elements + * @example + * findAll('a') => [].slice.call(document.querySelectorAll('a')) + * findAll(nav, 'a') => [].slice.call(nav.querySelectorAll('a')) + */ +export function findAll(el, node) { + return [].slice.call( + node ? el.querySelectorAll(node) : $.querySelectorAll(el) + ) +} + +export function create(node, tpl) { + node = $.createElement(node) + if (tpl) { + node.innerHTML = tpl + } + return node +} + +export function appendTo(target, el) { + return target.appendChild(el) +} + +export function before(target, el) { + return target.insertBefore(el, target.children[0]) +} + +export function on(el, type, handler) { + isFn(type) ? + window.addEventListener(el, type) : + el.addEventListener(type, handler) +} + +export function off(el, type, handler) { + isFn(type) ? + window.removeEventListener(el, type) : + el.removeEventListener(type, handler) +} + +/** + * Toggle class + * + * @example + * toggleClass(el, 'active') => el.classList.toggle('active') + * toggleClass(el, 'add', 'active') => el.classList.add('active') + */ +export function toggleClass(el, type, val) { + el && el.classList[val ? type : 'toggle'](val || type) +} + +export function style(content) { + appendTo(head, create('style', content)) +} diff --git a/src/core/util/env.js b/src/core/util/env.js new file mode 100644 index 0000000..cd51635 --- /dev/null +++ b/src/core/util/env.js @@ -0,0 +1,21 @@ +export const inBrowser = !process.env.SSR + +export const isMobile = inBrowser && document.body.clientWidth <= 600 + +/** + * @see https://github.com/MoOx/pjax/blob/master/lib/is-supported.js + */ +export const supportsPushState = + inBrowser && + (function () { + // Borrowed wholesale from https://github.com/defunkt/jquery-pjax + return ( + window.history && + window.history.pushState && + window.history.replaceState && + // PushState isn’t reliable on iOS until 5. + !navigator.userAgent.match( + /((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/ + ) + ) + })() diff --git a/src/core/util/index.js b/src/core/util/index.js new file mode 100644 index 0000000..eba6598 --- /dev/null +++ b/src/core/util/index.js @@ -0,0 +1,3 @@ +export * from './core' +export * from './env' +export * from '../router/util' diff --git a/src/core/util/polyfill/css-vars.js b/src/core/util/polyfill/css-vars.js new file mode 100644 index 0000000..fb3a80a --- /dev/null +++ b/src/core/util/polyfill/css-vars.js @@ -0,0 +1,36 @@ +import * as dom from '../dom' +import {get} from '../../fetch/ajax' + +function replaceVar(block, color) { + block.innerHTML = block.innerHTML.replace( + /var\(\s*--theme-color.*?\)/g, + color + ) +} + +export default function (color) { + // Variable support + if (window.CSS && window.CSS.supports && window.CSS.supports('(--v:red)')) { + return + } + + const styleBlocks = dom.findAll('style:not(.inserted),link'); + [].forEach.call(styleBlocks, block => { + if (block.nodeName === 'STYLE') { + replaceVar(block, color) + } else if (block.nodeName === 'LINK') { + const href = block.getAttribute('href') + + if (!/\.css$/.test(href)) { + return + } + + get(href).then(res => { + const style = dom.create('style', res) + + dom.head.appendChild(style) + replaceVar(style, color) + }) + } + }) +} diff --git a/src/event.js b/src/event.js deleted file mode 100644 index 45f558a..0000000 --- a/src/event.js +++ /dev/null @@ -1,123 +0,0 @@ -import { isMobile } from './util' - -/** - * Active sidebar when scroll - * @link https://buble.surge.sh/ - */ -export function scrollActiveSidebar () { - if (isMobile()) return - - const anchors = document.querySelectorAll('.anchor') - const nav = {} - const lis = document.querySelectorAll('.sidebar li') - let active = null - - for (let i = 0, len = lis.length; i < len; i += 1) { - const li = lis[i] - let href = li.querySelector('a').getAttribute('href') - - if (href !== '/') { - const match = href.match('#([^#]+)$') - if (match && match.length) href = match[0].slice(1) - } - - nav[decodeURIComponent(href)] = li - } - - function highlight () { - for (let i = 0, len = anchors.length; i < len; i += 1) { - const node = anchors[i] - const bcr = node.getBoundingClientRect() - - if (bcr.top < 10 && bcr.bottom > 10) { - const li = nav[node.getAttribute('data-id')] - - if (!li || li === active) return - if (active) active.setAttribute('class', '') - - li.setAttribute('class', 'active') - active = li - - return - } - } - } - - window.removeEventListener('scroll', highlight) - window.addEventListener('scroll', highlight) - highlight() -} - -export function scrollIntoView () { - const id = window.location.hash.match(/#[^#\/]+$/g) - if (!id || !id.length) return - const section = document.querySelector(decodeURIComponent(id[0])) - - if (section) section.scrollIntoView() -} - -/** - * Acitve link - */ -export function activeLink (dom, activeParent) { - const host = window.location.href - - dom = typeof dom === 'object' ? dom : document.querySelector(dom) - if (!dom) return - let target - - ;[].slice.call(dom.querySelectorAll('a')) - .sort((a, b) => b.href.length - a.href.length) - .forEach(node => { - if (host.indexOf(node.href) === 0 && !target) { - activeParent - ? node.parentNode.setAttribute('class', 'active') - : node.setAttribute('class', 'active') - target = node - } else { - activeParent - ? node.parentNode.removeAttribute('class') - : node.removeAttribute('class') - } - }) - - return target -} - -/** - * sidebar toggle - */ -export function bindToggle (dom) { - dom = typeof dom === 'object' ? dom : document.querySelector(dom) - if (!dom) return - const body = document.body - - dom.addEventListener('click', () => body.classList.toggle('close')) - - if (!/mobile/i.test(navigator.userAgent)) return - document.querySelector('aside').addEventListener('click', event => { - body.classList.toggle('close') - }) -} - -let cacheContentDOM -export function scroll2Top () { - if (!cacheContentDOM) { - const dom = isMobile() ? 'body' : 'section.content' - cacheContentDOM = document.querySelector(dom) - } - cacheContentDOM.scrollTop = 0 -} - -export function sticky () { - const dom = document.querySelector('section.cover') - const coverHeight = dom.getBoundingClientRect().height - - return (function () { - if (window.pageYOffset >= coverHeight || dom.classList.contains('hidden')) { - document.body.classList.add('sticky') - } else { - document.body.classList.remove('sticky') - } - })() -} diff --git a/src/index.js b/src/index.js deleted file mode 100644 index e61c644..0000000 --- a/src/index.js +++ /dev/null @@ -1,107 +0,0 @@ -import { load, camel2kebab, isNil, getRoute } from './util' -import { scrollIntoView } from './event' -import * as render from './render' - -const OPTIONS = { - el: '#app', - repo: '', - maxLevel: 6, - subMaxLevel: 0, - sidebar: '', - sidebarToggle: false, - loadSidebar: null, - loadNavbar: null, - router: false, - homepage: 'README.md', - coverpage: '', - basePath: '', - auto2top: false -} -const script = document.currentScript || [].slice.call(document.getElementsByTagName('script')).pop() - -// load configuration for script attribute -if (script) { - for (const prop in OPTIONS) { - const val = script.getAttribute('data-' + camel2kebab(prop)) - OPTIONS[prop] = isNil(val) ? OPTIONS[prop] : (val || true) - } - if (OPTIONS.loadSidebar === true) OPTIONS.loadSidebar = '_sidebar.md' - if (OPTIONS.loadNavbar === true) OPTIONS.loadNavbar = '_navbar.md' - if (OPTIONS.coverpage === true) OPTIONS.coverpage = '_coverpage.md' - if (OPTIONS.sidebar) OPTIONS.sidebar = window[OPTIONS.sidebar] -} - -// load options -render.config(OPTIONS) - -let cacheRoute = null -let cacheXhr = null - -const mainRender = function (cb) { - const route = OPTIONS.basePath + getRoute() - if (cacheRoute === route) return cb() - - let basePath = cacheRoute = route - - if (!/\//.test(basePath)) { - basePath = '' - } else if (basePath && !/\/$/.test(basePath)) { - basePath = basePath.match(/(\S*\/)[^\/]+$/)[1] - } - - let page - if (!route) { - page = OPTIONS.homepage || 'README.md' - } else if (/\/$/.test(route)) { - page = `${route}README.md` - } else { - page = `${route}.md` - } - - // Render Cover page - if (OPTIONS.coverpage && page === OPTIONS.homepage) { - load(OPTIONS.coverpage).then(render.renderCover) - } - - cacheXhr && cacheXhr.abort && cacheXhr.abort() - // Render markdown file - cacheXhr = load(page, 'GET', render.renderLoading) - cacheXhr.then(result => { - render.renderArticle(result) - // clear cover - if (OPTIONS.coverpage && page !== OPTIONS.homepage) render.renderCover() - // render sidebar - if (OPTIONS.loadSidebar) { - load(basePath + OPTIONS.loadSidebar) - .then(result => { - render.renderSidebar(result) - cb() - }) - } else { - cb() - } - }, _ => render.renderArticle(null)) - - // Render navbar - if (OPTIONS.loadNavbar) { - load(basePath + OPTIONS.loadNavbar).then(render.renderNavbar) - } -} - -const Docsify = function () { - const dom = document.querySelector(OPTIONS.el) || document.body - const replace = dom !== document.body - const main = function () { - mainRender(_ => scrollIntoView()) - } - - // Render app - render.renderApp(dom, replace) - main() - if (OPTIONS.router) { - if (!/^#\//.test(window.location.hash)) window.location.hash = '#/' - window.addEventListener('hashchange', main) - } -} - -export default Docsify() diff --git a/src/plugins/disqus.js b/src/plugins/disqus.js new file mode 100644 index 0000000..dba7aef --- /dev/null +++ b/src/plugins/disqus.js @@ -0,0 +1,51 @@ +const fixedPath = location.href.replace('/-/', '/#/') +if (fixedPath !== location.href) { + location.href = fixedPath +} + +function install(hook, vm) { + const dom = Docsify.dom + const disqus = vm.config.disqus + if (!disqus) { + throw Error('$docsify.disqus is required') + } + + hook.init(_ => { + const script = dom.create('script') + + script.async = true + script.src = `https://${disqus}.disqus.com/embed.js` + script.setAttribute('data-timestamp', Number(new Date())) + dom.appendTo(dom.body, script) + }) + + hook.mounted(_ => { + const div = dom.create('div') + div.id = 'disqus_thread' + const main = dom.getNode('#main') + div.style = `width: ${main.clientWidth}px; margin: 0 auto 20px;` + dom.appendTo(dom.find('.content'), div) + + // eslint-disable-next-line + window.disqus_config = function() { + this.page.url = location.origin + '/-' + vm.route.path + this.page.identifier = vm.route.path + this.page.title = document.title + } + }) + + hook.doneEach(_ => { + if (typeof window.DISQUS !== 'undefined') { + window.DISQUS.reset({ + reload: true, + config: function () { + this.page.url = location.origin + '/-' + vm.route.path + this.page.identifier = vm.route.path + this.page.title = document.title + } + }) + } + }) +} + +$docsify.plugins = [].concat(install, $docsify.plugins) diff --git a/src/plugins/emoji.js b/src/plugins/emoji.js new file mode 100644 index 0000000..31f1059 --- /dev/null +++ b/src/plugins/emoji.js @@ -0,0 +1,900 @@ +const AllGithubEmoji = [ + '+1', + '100', + '1234', + '8ball', + 'a', + 'ab', + 'abc', + 'abcd', + 'accept', + 'aerial_tramway', + 'airplane', + 'alarm_clock', + 'alien', + 'ambulance', + 'anchor', + 'angel', + 'anger', + 'angry', + 'anguished', + 'ant', + 'apple', + 'aquarius', + 'aries', + 'arrow_backward', + 'arrow_double_down', + 'arrow_double_up', + 'arrow_down', + 'arrow_down_small', + 'arrow_forward', + 'arrow_heading_down', + 'arrow_heading_up', + 'arrow_left', + 'arrow_lower_left', + 'arrow_lower_right', + 'arrow_right', + 'arrow_right_hook', + 'arrow_up', + 'arrow_up_down', + 'arrow_up_small', + 'arrow_upper_left', + 'arrow_upper_right', + 'arrows_clockwise', + 'arrows_counterclockwise', + 'art', + 'articulated_lorry', + 'astonished', + 'athletic_shoe', + 'atm', + 'b', + 'baby', + 'baby_bottle', + 'baby_chick', + 'baby_symbol', + 'back', + 'baggage_claim', + 'balloon', + 'ballot_box_with_check', + 'bamboo', + 'banana', + 'bangbang', + 'bank', + 'bar_chart', + 'barber', + 'baseball', + 'basketball', + 'bath', + 'bathtub', + 'battery', + 'bear', + 'bee', + 'beer', + 'beers', + 'beetle', + 'beginner', + 'bell', + 'bento', + 'bicyclist', + 'bike', + 'bikini', + 'bird', + 'birthday', + 'black_circle', + 'black_joker', + 'black_large_square', + 'black_medium_small_square', + 'black_medium_square', + 'black_nib', + 'black_small_square', + 'black_square_button', + 'blossom', + 'blowfish', + 'blue_book', + 'blue_car', + 'blue_heart', + 'blush', + 'boar', + 'boat', + 'bomb', + 'book', + 'bookmark', + 'bookmark_tabs', + 'books', + 'boom', + 'boot', + 'bouquet', + 'bow', + 'bowling', + 'bowtie', + 'boy', + 'bread', + 'bride_with_veil', + 'bridge_at_night', + 'briefcase', + 'broken_heart', + 'bug', + 'bulb', + 'bullettrain_front', + 'bullettrain_side', + 'bus', + 'busstop', + 'bust_in_silhouette', + 'busts_in_silhouette', + 'cactus', + 'cake', + 'calendar', + 'calling', + 'camel', + 'camera', + 'cancer', + 'candy', + 'capital_abcd', + 'capricorn', + 'car', + 'card_index', + 'carousel_horse', + 'cat', + 'cat2', + 'cd', + 'chart', + 'chart_with_downwards_trend', + 'chart_with_upwards_trend', + 'checkered_flag', + 'cherries', + 'cherry_blossom', + 'chestnut', + 'chicken', + 'children_crossing', + 'chocolate_bar', + 'christmas_tree', + 'church', + 'cinema', + 'circus_tent', + 'city_sunrise', + 'city_sunset', + 'cl', + 'clap', + 'clapper', + 'clipboard', + 'clock1', + 'clock10', + 'clock1030', + 'clock11', + 'clock1130', + 'clock12', + 'clock1230', + 'clock130', + 'clock2', + 'clock230', + 'clock3', + 'clock330', + 'clock4', + 'clock430', + 'clock5', + 'clock530', + 'clock6', + 'clock630', + 'clock7', + 'clock730', + 'clock8', + 'clock830', + 'clock9', + 'clock930', + 'closed_book', + 'closed_lock_with_key', + 'closed_umbrella', + 'cloud', + 'clubs', + 'cn', + 'cocktail', + 'coffee', + 'cold_sweat', + 'collision', + 'computer', + 'confetti_ball', + 'confounded', + 'confused', + 'congratulations', + 'construction', + 'construction_worker', + 'convenience_store', + 'cookie', + 'cool', + 'cop', + 'copyright', + 'corn', + 'couple', + 'couple_with_heart', + 'couplekiss', + 'cow', + 'cow2', + 'credit_card', + 'crescent_moon', + 'crocodile', + 'crossed_flags', + 'crown', + 'cry', + 'crying_cat_face', + 'crystal_ball', + 'cupid', + 'curly_loop', + 'currency_exchange', + 'curry', + 'custard', + 'customs', + 'cyclone', + 'dancer', + 'dancers', + 'dango', + 'dart', + 'dash', + 'date', + 'de', + 'deciduous_tree', + 'department_store', + 'diamond_shape_with_a_dot_inside', + 'diamonds', + 'disappointed', + 'disappointed_relieved', + 'dizzy', + 'dizzy_face', + 'do_not_litter', + 'dog', + 'dog2', + 'dollar', + 'dolls', + 'dolphin', + 'door', + 'doughnut', + 'dragon', + 'dragon_face', + 'dress', + 'dromedary_camel', + 'droplet', + 'dvd', + 'e-mail', + 'ear', + 'ear_of_rice', + 'earth_africa', + 'earth_americas', + 'earth_asia', + 'egg', + 'eggplant', + 'eight', + 'eight_pointed_black_star', + 'eight_spoked_asterisk', + 'electric_plug', + 'elephant', + 'email', + 'end', + 'envelope', + 'envelope_with_arrow', + 'es', + 'euro', + 'european_castle', + 'european_post_office', + 'evergreen_tree', + 'exclamation', + 'expressionless', + 'eyeglasses', + 'eyes', + 'facepunch', + 'factory', + 'fallen_leaf', + 'family', + 'fast_forward', + 'fax', + 'fearful', + 'feelsgood', + 'feet', + 'ferris_wheel', + 'file_folder', + 'finnadie', + 'fire', + 'fire_engine', + 'fireworks', + 'first_quarter_moon', + 'first_quarter_moon_with_face', + 'fish', + 'fish_cake', + 'fishing_pole_and_fish', + 'fist', + 'five', + 'flags', + 'flashlight', + 'flipper', + 'floppy_disk', + 'flower_playing_cards', + 'flushed', + 'foggy', + 'football', + 'footprints', + 'fork_and_knife', + 'fountain', + 'four', + 'four_leaf_clover', + 'fr', + 'free', + 'fried_shrimp', + 'fries', + 'frog', + 'frowning', + 'fu', + 'fuelpump', + 'full_moon', + 'full_moon_with_face', + 'game_die', + 'gb', + 'gem', + 'gemini', + 'ghost', + 'gift', + 'gift_heart', + 'girl', + 'globe_with_meridians', + 'goat', + 'goberserk', + 'godmode', + 'golf', + 'grapes', + 'green_apple', + 'green_book', + 'green_heart', + 'grey_exclamation', + 'grey_question', + 'grimacing', + 'grin', + 'grinning', + 'guardsman', + 'guitar', + 'gun', + 'haircut', + 'hamburger', + 'hammer', + 'hamster', + 'hand', + 'handbag', + 'hankey', + 'hash', + 'hatched_chick', + 'hatching_chick', + 'headphones', + 'hear_no_evil', + 'heart', + 'heart_decoration', + 'heart_eyes', + 'heart_eyes_cat', + 'heartbeat', + 'heartpulse', + 'hearts', + 'heavy_check_mark', + 'heavy_division_sign', + 'heavy_dollar_sign', + 'heavy_exclamation_mark', + 'heavy_minus_sign', + 'heavy_multiplication_x', + 'heavy_plus_sign', + 'helicopter', + 'herb', + 'hibiscus', + 'high_brightness', + 'high_heel', + 'hocho', + 'honey_pot', + 'honeybee', + 'horse', + 'horse_racing', + 'hospital', + 'hotel', + 'hotsprings', + 'hourglass', + 'hourglass_flowing_sand', + 'house', + 'house_with_garden', + 'hurtrealbad', + 'hushed', + 'ice_cream', + 'icecream', + 'id', + 'ideograph_advantage', + 'imp', + 'inbox_tray', + 'incoming_envelope', + 'information_desk_person', + 'information_source', + 'innocent', + 'interrobang', + 'iphone', + 'it', + 'izakaya_lantern', + 'jack_o_lantern', + 'japan', + 'japanese_castle', + 'japanese_goblin', + 'japanese_ogre', + 'jeans', + 'joy', + 'joy_cat', + 'jp', + 'key', + 'keycap_ten', + 'kimono', + 'kiss', + 'kissing', + 'kissing_cat', + 'kissing_closed_eyes', + 'kissing_heart', + 'kissing_smiling_eyes', + 'koala', + 'koko', + 'kr', + 'lantern', + 'large_blue_circle', + 'large_blue_diamond', + 'large_orange_diamond', + 'last_quarter_moon', + 'last_quarter_moon_with_face', + 'laughing', + 'leaves', + 'ledger', + 'left_luggage', + 'left_right_arrow', + 'leftwards_arrow_with_hook', + 'lemon', + 'leo', + 'leopard', + 'libra', + 'light_rail', + 'link', + 'lips', + 'lipstick', + 'lock', + 'lock_with_ink_pen', + 'lollipop', + 'loop', + 'loud_sound', + 'loudspeaker', + 'love_hotel', + 'love_letter', + 'low_brightness', + 'm', + 'mag', + 'mag_right', + 'mahjong', + 'mailbox', + 'mailbox_closed', + 'mailbox_with_mail', + 'mailbox_with_no_mail', + 'man', + 'man_with_gua_pi_mao', + 'man_with_turban', + 'mans_shoe', + 'maple_leaf', + 'mask', + 'massage', + 'meat_on_bone', + 'mega', + 'melon', + 'memo', + 'mens', + 'metal', + 'metro', + 'microphone', + 'microscope', + 'milky_way', + 'minibus', + 'minidisc', + 'mobile_phone_off', + 'money_with_wings', + 'moneybag', + 'monkey', + 'monkey_face', + 'monorail', + 'moon', + 'mortar_board', + 'mount_fuji', + 'mountain_bicyclist', + 'mountain_cableway', + 'mountain_railway', + 'mouse', + 'mouse2', + 'movie_camera', + 'moyai', + 'muscle', + 'mushroom', + 'musical_keyboard', + 'musical_note', + 'musical_score', + 'mute', + 'nail_care', + 'name_badge', + 'neckbeard', + 'necktie', + 'negative_squared_cross_mark', + 'neutral_face', + 'new', + 'new_moon', + 'new_moon_with_face', + 'newspaper', + 'ng', + 'night_with_stars', + 'nine', + 'no_bell', + 'no_bicycles', + 'no_entry', + 'no_entry_sign', + 'no_good', + 'no_mobile_phones', + 'no_mouth', + 'no_pedestrians', + 'no_smoking', + 'non-potable_water', + 'nose', + 'notebook', + 'notebook_with_decorative_cover', + 'notes', + 'nut_and_bolt', + 'o', + 'o2', + 'ocean', + 'octocat', + 'octopus', + 'oden', + 'office', + 'ok', + 'ok_hand', + 'ok_woman', + 'older_man', + 'older_woman', + 'on', + 'oncoming_automobile', + 'oncoming_bus', + 'oncoming_police_car', + 'oncoming_taxi', + 'one', + 'open_book', + 'open_file_folder', + 'open_hands', + 'open_mouth', + 'ophiuchus', + 'orange_book', + 'outbox_tray', + 'ox', + 'package', + 'page_facing_up', + 'page_with_curl', + 'pager', + 'palm_tree', + 'panda_face', + 'paperclip', + 'parking', + 'part_alternation_mark', + 'partly_sunny', + 'passport_control', + 'paw_prints', + 'peach', + 'pear', + 'pencil', + 'pencil2', + 'penguin', + 'pensive', + 'performing_arts', + 'persevere', + 'person_frowning', + 'person_with_blond_hair', + 'person_with_pouting_face', + 'phone', + 'pig', + 'pig2', + 'pig_nose', + 'pill', + 'pineapple', + 'pisces', + 'pizza', + 'point_down', + 'point_left', + 'point_right', + 'point_up', + 'point_up_2', + 'police_car', + 'poodle', + 'poop', + 'post_office', + 'postal_horn', + 'postbox', + 'potable_water', + 'pouch', + 'poultry_leg', + 'pound', + 'pouting_cat', + 'pray', + 'princess', + 'punch', + 'purple_heart', + 'purse', + 'pushpin', + 'put_litter_in_its_place', + 'question', + 'rabbit', + 'rabbit2', + 'racehorse', + 'radio', + 'radio_button', + 'rage', + 'rage1', + 'rage2', + 'rage3', + 'rage4', + 'railway_car', + 'rainbow', + 'raised_hand', + 'raised_hands', + 'raising_hand', + 'ram', + 'ramen', + 'rat', + 'recycle', + 'red_car', + 'red_circle', + 'registered', + 'relaxed', + 'relieved', + 'repeat', + 'repeat_one', + 'restroom', + 'revolving_hearts', + 'rewind', + 'ribbon', + 'rice', + 'rice_ball', + 'rice_cracker', + 'rice_scene', + 'ring', + 'rocket', + 'roller_coaster', + 'rooster', + 'rose', + 'rotating_light', + 'round_pushpin', + 'rowboat', + 'ru', + 'rugby_football', + 'runner', + 'running', + 'running_shirt_with_sash', + 'sa', + 'sagittarius', + 'sailboat', + 'sake', + 'sandal', + 'santa', + 'satellite', + 'satisfied', + 'saxophone', + 'school', + 'school_satchel', + 'scissors', + 'scorpius', + 'scream', + 'scream_cat', + 'scroll', + 'seat', + 'secret', + 'see_no_evil', + 'seedling', + 'seven', + 'shaved_ice', + 'sheep', + 'shell', + 'ship', + 'shipit', + 'shirt', + 'shit', + 'shoe', + 'shower', + 'signal_strength', + 'six', + 'six_pointed_star', + 'ski', + 'skull', + 'sleeping', + 'sleepy', + 'slot_machine', + 'small_blue_diamond', + 'small_orange_diamond', + 'small_red_triangle', + 'small_red_triangle_down', + 'smile', + 'smile_cat', + 'smiley', + 'smiley_cat', + 'smiling_imp', + 'smirk', + 'smirk_cat', + 'smoking', + 'snail', + 'snake', + 'snowboarder', + 'snowflake', + 'snowman', + 'sob', + 'soccer', + 'soon', + 'sos', + 'sound', + 'space_invader', + 'spades', + 'spaghetti', + 'sparkle', + 'sparkler', + 'sparkles', + 'sparkling_heart', + 'speak_no_evil', + 'speaker', + 'speech_balloon', + 'speedboat', + 'squirrel', + 'star', + 'star2', + 'stars', + 'station', + 'statue_of_liberty', + 'steam_locomotive', + 'stew', + 'straight_ruler', + 'strawberry', + 'stuck_out_tongue', + 'stuck_out_tongue_closed_eyes', + 'stuck_out_tongue_winking_eye', + 'sun_with_face', + 'sunflower', + 'sunglasses', + 'sunny', + 'sunrise', + 'sunrise_over_mountains', + 'surfer', + 'sushi', + 'suspect', + 'suspension_railway', + 'sweat', + 'sweat_drops', + 'sweat_smile', + 'sweet_potato', + 'swimmer', + 'symbols', + 'syringe', + 'tada', + 'tanabata_tree', + 'tangerine', + 'taurus', + 'taxi', + 'tea', + 'telephone', + 'telephone_receiver', + 'telescope', + 'tennis', + 'tent', + 'thought_balloon', + 'three', + 'thumbsdown', + 'thumbsup', + 'ticket', + 'tiger', + 'tiger2', + 'tired_face', + 'tm', + 'toilet', + 'tokyo_tower', + 'tomato', + 'tongue', + 'top', + 'tophat', + 'tractor', + 'traffic_light', + 'train', + 'train2', + 'tram', + 'triangular_flag_on_post', + 'triangular_ruler', + 'trident', + 'triumph', + 'trolleybus', + 'trollface', + 'trophy', + 'tropical_drink', + 'tropical_fish', + 'truck', + 'trumpet', + 'tshirt', + 'tulip', + 'turtle', + 'tv', + 'twisted_rightwards_arrows', + 'two', + 'two_hearts', + 'two_men_holding_hands', + 'two_women_holding_hands', + 'u5272', + 'u5408', + 'u55b6', + 'u6307', + 'u6708', + 'u6709', + 'u6e80', + 'u7121', + 'u7533', + 'u7981', + 'u7a7a', + 'uk', + 'umbrella', + 'unamused', + 'underage', + 'unlock', + 'up', + 'us', + 'v', + 'vertical_traffic_light', + 'vhs', + 'vibration_mode', + 'video_camera', + 'video_game', + 'violin', + 'virgo', + 'volcano', + 'vs', + 'walking', + 'waning_crescent_moon', + 'waning_gibbous_moon', + 'warning', + 'watch', + 'water_buffalo', + 'watermelon', + 'wave', + 'wavy_dash', + 'waxing_crescent_moon', + 'waxing_gibbous_moon', + 'wc', + 'weary', + 'wedding', + 'whale', + 'whale2', + 'wheelchair', + 'white_check_mark', + 'white_circle', + 'white_flower', + 'white_large_square', + 'white_medium_small_square', + 'white_medium_square', + 'white_small_square', + 'white_square_button', + 'wind_chime', + 'wine_glass', + 'wink', + 'wolf', + 'woman', + 'womans_clothes', + 'womans_hat', + 'womens', + 'worried', + 'wrench', + 'x', + 'yellow_heart', + 'yen', + 'yum', + 'zap', + 'zero', + 'zzz' +] + +// Emoji from All-Github-Emoji-Icons +// https://github.com/scotch-io/All-Github-Emoji-Icons +window.emojify = function (match, $1) { + return AllGithubEmoji.indexOf($1) === -1 ? + match : + '
${NO_DATA_TEXT}
` + if (options.hideOtherSidebarContent) { + $sidebarNav.classList.add('hide') + $appName.classList.add('hide') + } +} + +function bindEvents() { + const $search = Docsify.dom.find('div.search') + const $input = Docsify.dom.find($search, 'input') + const $inputWrap = Docsify.dom.find($search, '.input-wrap') + + let timeId + // Prevent to Fold sidebar + Docsify.dom.on( + $search, + 'click', + e => e.target.tagName !== 'A' && e.stopPropagation() + ) + Docsify.dom.on($input, 'input', e => { + clearTimeout(timeId) + timeId = setTimeout(_ => doSearch(e.target.value.trim()), 100) + }) + Docsify.dom.on($inputWrap, 'click', e => { + // Click input outside + if (e.target.tagName !== 'INPUT') { + $input.value = '' + doSearch() + } + }) +} + +function updatePlaceholder(text, path) { + const $input = Docsify.dom.getNode('.search input[type="search"]') + + if (!$input) { + return + } + if (typeof text === 'string') { + $input.placeholder = text + } else { + const match = Object.keys(text).filter(key => path.indexOf(key) > -1)[0] + $input.placeholder = text[match] + } +} + +function updateNoData(text, path) { + if (typeof text === 'string') { + NO_DATA_TEXT = text + } else { + const match = Object.keys(text).filter(key => path.indexOf(key) > -1)[0] + NO_DATA_TEXT = text[match] + } +} + +function updateOptions(opts) { + options = opts +} + +export function init(opts, vm) { + const keywords = vm.router.parse().query.s + + updateOptions(opts) + style() + tpl(keywords) + bindEvents() + keywords && setTimeout(_ => doSearch(keywords), 500) +} + +export function update(opts, vm) { + updateOptions(opts) + updatePlaceholder(opts.placeholder, vm.route.path) + updateNoData(opts.noData, vm.route.path) +} diff --git a/src/plugins/search/index.js b/src/plugins/search/index.js new file mode 100644 index 0000000..bbd3af6 --- /dev/null +++ b/src/plugins/search/index.js @@ -0,0 +1,42 @@ +import {init as initComponet, update as updateComponent} from './component' +import {init as initSearch} from './search' + +const CONFIG = { + placeholder: 'Type to search', + noData: 'No Results!', + paths: 'auto', + depth: 2, + maxAge: 86400000, // 1 day + hideOtherSidebarContent: false, + namespace: undefined +} + +const install = function (hook, vm) { + const {util} = Docsify + const opts = vm.config.search || CONFIG + + if (Array.isArray(opts)) { + CONFIG.paths = opts + } else if (typeof opts === 'object') { + CONFIG.paths = Array.isArray(opts.paths) ? opts.paths : 'auto' + CONFIG.maxAge = util.isPrimitive(opts.maxAge) ? opts.maxAge : CONFIG.maxAge + CONFIG.placeholder = opts.placeholder || CONFIG.placeholder + CONFIG.noData = opts.noData || CONFIG.noData + CONFIG.depth = opts.depth || CONFIG.depth + CONFIG.hideOtherSidebarContent = opts.hideOtherSidebarContent || CONFIG.hideOtherSidebarContent + CONFIG.namespace = opts.namespace || CONFIG.namespace + } + + const isAuto = CONFIG.paths === 'auto' + + hook.mounted(_ => { + initComponet(CONFIG, vm) + !isAuto && initSearch(CONFIG, vm) + }) + hook.doneEach(_ => { + updateComponent(CONFIG, vm) + isAuto && initSearch(CONFIG, vm) + }) +} + +$docsify.plugins = [].concat(install, $docsify.plugins) diff --git a/src/plugins/search/search.js b/src/plugins/search/search.js new file mode 100644 index 0000000..2c9febf --- /dev/null +++ b/src/plugins/search/search.js @@ -0,0 +1,193 @@ +let INDEXS = {} + +const 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) { + const entityMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''', + '/': '/' + } + + return String(string).replace(/[&<>"'/]/g, s => entityMap[s]) +} + +function getAllPaths(router) { + const paths = [] + + Docsify.dom.findAll('.sidebar-nav a:not(.section-link):not([data-nosearch])').forEach(node => { + const href = node.href + const originHref = node.getAttribute('href') + const path = router.parse(href).path + + if ( + path && + paths.indexOf(path) === -1 && + !Docsify.util.isAbsolutePath(originHref) + ) { + paths.push(path) + } + }) + + return paths +} + +function saveData(maxAge, expireKey, indexKey) { + localStorage.setItem(expireKey, Date.now() + maxAge) + localStorage.setItem(indexKey, JSON.stringify(INDEXS)) +} + +export function genIndex(path, content = '', router, depth) { + const tokens = window.marked.lexer(content) + const slugify = window.Docsify.slugify + const index = {} + let slug + + 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: ''} + } else { + if (!slug) { + return + } + if (!index[slug]) { + index[slug] = {slug, title: '', body: ''} + } else if (index[slug].body) { + index[slug].body += '\n' + (token.text || '') + } else { + index[slug].body = token.text + } + } + }) + slugify.clear() + return index +} + +/** + * @param {String} query + * @returns {Array} + */ +export function search(query) { + const matchingResults = [] + let data = [] + Object.keys(INDEXS).forEach(key => { + data = data.concat(Object.keys(INDEXS[key]).map(page => INDEXS[key][page])) + }) + + query = query.trim() + let keywords = query.split(/[\s\-,\\/]+/) + if (keywords.length !== 1) { + keywords = [].concat(query, keywords) + } + + for (let i = 0; i < data.length; i++) { + const post = data[i] + let matchesScore = 0 + let resultStr = '' + const postTitle = post.title && post.title.trim() + const postContent = post.body && post.body.trim() + const postUrl = post.slug || '' + + if (postTitle) { + keywords.forEach( keyword => { + // From https://github.com/sindresorhus/escape-string-regexp + const regEx = new RegExp( + keyword.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'), + 'gi' + ); + let indexTitle = -1 + let indexContent = -1 + + indexTitle = postTitle ? postTitle.search(regEx) : -1 + indexContent = postContent ? postContent.search(regEx) : -1 + + if (indexTitle >= 0 || indexContent >= 0) { + matchesScore += indexTitle >= 0 ? 3 : indexContent >= 0 ? 2 : 0; + if (indexContent < 0) { + indexContent = 0 + } + + let start = 0 + let end = 0 + + start = indexContent < 11 ? 0 : indexContent - 10 + end = start === 0 ? 70 : indexContent + keyword.length + 60 + + if (end > postContent.length) { + end = postContent.length + } + + const matchContent = + '...' + + escapeHtml(postContent) + .substring(start, end) + .replace(regEx, `${keyword}`) + + '...' + + resultStr += matchContent + } + }) + + if (matchesScore > 0) { + const matchingPost = { + title: escapeHtml(postTitle), + content: postContent ? resultStr : '', + url: postUrl, + score: matchesScore + } + + matchingResults.push(matchingPost) + } + } + } + + return matchingResults.sort((r1, r2) => r2.score - r1.score); +} + +export function init(config, vm) { + const isAuto = config.paths === 'auto' + + const expireKey = resolveExpireKey(config.namespace) + const indexKey = resolveIndexKey(config.namespace) + + const isExpired = localStorage.getItem(expireKey) < Date.now() + + INDEXS = JSON.parse(localStorage.getItem(indexKey)) + + if (isExpired) { + INDEXS = {} + } else if (!isAuto) { + return + } + + const paths = isAuto ? getAllPaths(vm.router) : config.paths + const len = paths.length + let count = 0 + + paths.forEach(path => { + if (INDEXS[path]) { + return count++ + } + + Docsify + .get(vm.router.getFile(path), false, vm.config.requestHeaders) + .then(result => { + INDEXS[path] = genIndex(path, result, vm.router, config.depth) + len === ++count && saveData(config.maxAge, expireKey, indexKey) + }) + }) +} diff --git a/src/plugins/zoom-image.js b/src/plugins/zoom-image.js new file mode 100644 index 0000000..faf92e1 --- /dev/null +++ b/src/plugins/zoom-image.js @@ -0,0 +1,21 @@ +import mediumZoom from 'medium-zoom' + +const matchesSelector = Element.prototype.matches || Element.prototype.webkitMatchesSelector || Element.prototype.msMatchesSelector + +function install(hook) { + let zoom + + hook.doneEach(_ => { + let elms = Array.apply(null, document.querySelectorAll('.markdown-section img:not(.emoji):not([data-no-zoom])')) + + elms = elms.filter(elm => matchesSelector.call(elm, 'a img') === false) + + if (zoom) { + zoom.detach() + } + + zoom = mediumZoom(elms) + }) +} + +$docsify.plugins = [].concat(install, $docsify.plugins) diff --git a/src/render.js b/src/render.js deleted file mode 100644 index 75bed94..0000000 --- a/src/render.js +++ /dev/null @@ -1,203 +0,0 @@ -import marked from 'marked' -import Prism from 'prismjs' -import * as tpl from './tpl' -import { activeLink, scrollActiveSidebar, bindToggle, scroll2Top, sticky } from './event' -import { genTree, getRoute, isMobile } from './util' - -let OPTIONS = {} -const CACHE = {} - -const renderTo = function (dom, content) { - dom = typeof dom === 'object' ? dom : document.querySelector(dom) - dom.innerHTML = content - - return dom -} -let toc = [] -const renderer = new marked.Renderer() - -/** - * render anchor tag - * @link https://github.com/chjj/marked#overriding-renderer-methods - */ -renderer.heading = function (text, level) { - const slug = text.toLowerCase() - .replace(/<(?:.|\n)*?>/gm, '') - .replace(/[^\w|\u4e00-\u9fa5]+/g, '-') - let route = '' - - if (OPTIONS.router) { - route = `#/${getRoute()}` - } - - toc.push({ level, slug: `${route}#${encodeURIComponent(slug)}`, title: text }) - - return `${hl}`
-}
-renderer.link = function (href, title, text) {
- if (OPTIONS.router && !/^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/.test(href)) {
- href = `#/${href}`.replace(/\/\//g, '/')
- }
-
- return `${text}`
-}
-marked.setOptions({ renderer })
-
-/**
- * App
- */
-export function renderApp (dom, replace) {
- const nav = document.querySelector('nav') || document.createElement('nav')
-
- if (!OPTIONS.repo) nav.classList.add('no-badge')
-
- dom[replace ? 'outerHTML' : 'innerHTML'] = tpl.corner(OPTIONS.repo) +
- (OPTIONS.coverpage ? tpl.cover() : '') +
- tpl.main(OPTIONS.sidebarToggle ? tpl.toggle() : '')
- document.body.insertBefore(nav, document.body.children[0])
-
- // bind toggle
- bindToggle('button.sidebar-toggle')
- // bind sticky effect
- if (OPTIONS.coverpage) {
- !isMobile() && window.addEventListener('scroll', sticky)
- } else {
- document.body.classList.add('sticky')
- }
-}
-
-/**
- * article
- */
-export function renderArticle (content) {
- renderTo('article', content ? marked(content) : 'not found')
- if (!OPTIONS.sidebar && !OPTIONS.loadSidebar) renderSidebar()
-
- if (content && typeof Vue !== 'undefined' && typeof Vuep !== 'undefined') {
- const vm = new Vue({ el: 'main' }) // eslint-disable-line
- vm.$nextTick(_ => scrollActiveSidebar())
- }
- if (OPTIONS.auto2top) scroll2Top()
-}
-
-/**
- * navbar
- */
-export function renderNavbar (content) {
- if (CACHE.navbar && CACHE.navbar === content) return
- CACHE.navbar = content
-
- if (content) renderTo('nav', marked(content))
- activeLink('nav')
-}
-
-/**
- * sidebar
- */
-export function renderSidebar (content) {
- let html
-
- if (content) {
- html = marked(content)
- } else if (OPTIONS.sidebar) {
- html = tpl.tree(OPTIONS.sidebar, 'Time is money, my friend!
') + }) + + 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, `text
+