mirror of
https://github.com/wahyd4/docsify.git
synced 2026-08-09 13:26:34 +10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f859d2d0b2 | ||
|
|
9735f4036e | ||
|
|
b8a96b867b | ||
|
|
b7b589b1bf | ||
|
|
761e38f6ad | ||
|
|
78899a0251 | ||
|
|
357631c8b7 | ||
|
|
17ff3d1506 | ||
|
|
f59aac478a | ||
|
|
0dd2497467 | ||
|
|
306136f6a3 | ||
|
|
4aba9d0a25 | ||
|
|
3d2f23bcdc | ||
|
|
b85eb0ff4b | ||
|
|
efa8d25912 | ||
|
|
437737cc5a | ||
|
|
992ff77808 | ||
|
|
4cf13db685 | ||
|
|
e54062f80d | ||
|
|
cee8ac6698 | ||
|
|
d057f66fce | ||
|
|
9b0f1978a4 | ||
|
|
d9848c3384 | ||
|
|
4dabae3bf2 | ||
|
|
b430993f4f | ||
|
|
2e00f4c993 | ||
|
|
7fb5ce6c84 | ||
|
|
c4aa22c56d | ||
|
|
9af855921e | ||
|
|
4492c3e19f | ||
|
|
f598e53098 | ||
|
|
4bde6d685c | ||
|
|
ce0e9acd50 | ||
|
|
e8117e515d | ||
|
|
25e09dfe07 | ||
|
|
a6b46a3e26 | ||
|
|
d469442eae | ||
|
|
9f310bbd7d | ||
|
|
cc8a7c97b6 | ||
|
|
19da658ba2 | ||
|
|
97db30a0b9 | ||
|
|
3a0765e11e | ||
|
|
aaf71b1ac0 | ||
|
|
b37781e949 | ||
|
|
54a48dd3ff | ||
|
|
1aabc41db7 | ||
|
|
d087d5753b | ||
|
|
bb793ec08e | ||
|
|
6a78ae7ddc | ||
|
|
ac28040bd7 | ||
|
|
b12f74b159 | ||
|
|
1304d2ea1a | ||
|
|
ccf4c7c5cc | ||
|
|
9b15d8d577 | ||
|
|
642e7da7ee | ||
|
|
75381cf046 | ||
|
|
7e2e5a7c90 | ||
|
|
6d48ce1266 | ||
|
|
d286963da0 | ||
|
|
8a4cedd962 | ||
|
|
a3b7b66a76 | ||
|
|
5a0d4b7897 | ||
|
|
fcfdb17b8d | ||
|
|
e4d2e7ec12 | ||
|
|
ece00e6b3a | ||
|
|
841829427b | ||
|
|
56c7b9ae2d | ||
|
|
db8400a6ac | ||
|
|
955d3d5988 | ||
|
|
d9b487e67b | ||
|
|
91b66a5cac | ||
|
|
90bba60367 | ||
|
|
d05c4f65a8 | ||
|
|
3380a62142 | ||
|
|
8e418a1681 | ||
|
|
20d60c401f | ||
|
|
1938fd5146 | ||
|
|
3b74c49f00 | ||
|
|
22b50f07c3 | ||
|
|
ec887c1b5f | ||
|
|
036fdac131 | ||
|
|
a64cee1236 | ||
|
|
f943fede99 | ||
|
|
e296439df3 | ||
|
|
0014895c19 | ||
|
|
23590fa7e7 | ||
|
|
8689a37121 | ||
|
|
05a0211861 | ||
|
|
318189a13f | ||
|
|
42795a0483 | ||
|
|
6b9e0922cf | ||
|
|
8cb4189b96 | ||
|
|
7eb6346075 | ||
|
|
238e9633f9 | ||
|
|
6db8c9e6c9 | ||
|
|
e160bcaded | ||
|
|
8cf69754b5 | ||
|
|
79a83bc17d | ||
|
|
81c87f7926 | ||
|
|
67ec128315 | ||
|
|
77657e3b64 | ||
|
|
9825db47af | ||
|
|
1a5593889e | ||
|
|
fc9cdf37c5 | ||
|
|
80dba191d3 | ||
|
|
5a0c37fcd3 | ||
|
|
1462efedcd | ||
|
|
4cb20a5f9d | ||
|
|
490c8a19d3 | ||
|
|
4b838247ea | ||
|
|
b091f3f10d | ||
|
|
0e74e6c15e | ||
|
|
be8358fcdc | ||
|
|
1ae0a9a845 | ||
|
|
7e169ad154 | ||
|
|
8595c99c0b | ||
|
|
43fc8b8ab1 | ||
|
|
ccec23df7f | ||
|
|
fc1cd3f11d | ||
|
|
3f38810774 | ||
|
|
3db4841da3 | ||
|
|
b764b6e32c | ||
|
|
46261572e3 | ||
|
|
d53b8dadb3 | ||
|
|
b9b9d87681 | ||
|
|
d4f6072d10 | ||
|
|
891475e132 | ||
|
|
1acfdd335c | ||
|
|
1f4514dcad | ||
|
|
eba1c987a8 | ||
|
|
3444884905 | ||
|
|
6dea685fee | ||
|
|
f095eb888f | ||
|
|
8741c746df | ||
|
|
2c7041c8fb | ||
|
|
2a21c40f17 | ||
|
|
000194c8da | ||
|
|
fce1e47131 | ||
|
|
6d244139dd | ||
|
|
eca3368152 | ||
|
|
bab76e004d | ||
|
|
eb9dc4671a | ||
|
|
bb815cb2d4 | ||
|
|
26db33dc31 | ||
|
|
6cbed4b4d8 | ||
|
|
b948cb06d7 | ||
|
|
b2b474264f | ||
|
|
a8c73ee2b9 | ||
|
|
eda9bb8343 | ||
|
|
50e771e6a8 | ||
|
|
2d73285de5 | ||
|
|
d2be5aecf8 |
@@ -1 +1,3 @@
|
||||
.git/
|
||||
packages/docsify-server-renderer/build.js
|
||||
node_modules
|
||||
@@ -2,6 +2,9 @@
|
||||
"extends": [
|
||||
"vue"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 8
|
||||
},
|
||||
"env": {
|
||||
"browser": true
|
||||
},
|
||||
|
||||
+171
-85
@@ -1,140 +1,226 @@
|
||||
# Changelog
|
||||
<a name="4.2.2"></a>
|
||||
## [4.2.2](https://github.com/QingWei-Li/docsify/compare/v4.2.1...v4.2.2) (2017-07-24)
|
||||
|
||||
## 3.6.6 / 2017-05-06
|
||||
|
||||
* feat: support query string for the search, likes `https://docsify.js.org/#/?s=navbar`, fixed ([#156](https://github.com/QingWei-Li/docsify/issues/156)
|
||||
### Bug Fixes
|
||||
|
||||
## 3.6.5 / 2017-04-28
|
||||
* style rerender due to setting themeColor ([17ff3d1](https://github.com/QingWei-Li/docsify/commit/17ff3d1))
|
||||
|
||||
* fix(util): fix crash, fixed ([#154](https://github.com/QingWei-Li/docsify/issues/154)
|
||||
|
||||
## 3.6.4 / 2017-04-28
|
||||
|
||||
* fix(util): correctly clean up duplicate slashes, fixed ([#153](https://github.com/QingWei-Li/docsify/issues/153)
|
||||
<a name="4.2.1"></a>
|
||||
## [4.2.1](https://github.com/QingWei-Li/docsify/compare/v4.2.0...v4.2.1) (2017-07-19)
|
||||
|
||||
## 3.6.3 / 2017-04-25
|
||||
- give the navbar some line-height (#216)
|
||||
- Remove unnecessary moduleName option from rollup config for plugins (#209)
|
||||
|
||||
* fix(external-script): script attrs
|
||||
<a name="4.2.0"></a>
|
||||
# [4.2.0](https://github.com/QingWei-Li/docsify/compare/v4.1.14...v4.2.0) (2017-07-10)
|
||||
|
||||
## 3.6.2/ 2017-04-12
|
||||
|
||||
* feat(external-script): detect more than one script dom, fixed ([#146](https://github.com/QingWei-Li/docsify/issues/146)
|
||||
* GA: Send hash instead of complete href (#147)
|
||||
### Bug Fixes
|
||||
|
||||
## 3.6.1 / 2017-04-09
|
||||
* not found page ([9af8559](https://github.com/QingWei-Li/docsify/commit/9af8559))
|
||||
|
||||
* feat(event): Collapse the sidebar when click outside element in the small screen
|
||||
|
||||
## 3.6.0 / 2017-04-09
|
||||
### Features
|
||||
|
||||
* feat(render): add mergeNavbar option, close ([#125](https://github.com/QingWei-Li/docsify/issues/125)
|
||||
* 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))
|
||||
|
||||
## 3.5.2/ 2017-04-05
|
||||
|
||||
* add optional current route param to toURL and use it to properly compose local anchor links
|
||||
* fix code style by removing semicolons
|
||||
* in toURL test for anchor links and if so prepend the currentPath to the generated path. fixes ([#142](https://github.com/QingWei-Li/docsify/issues/142))
|
||||
|
||||
## 3.5.1 / 2017-03-25
|
||||
<a name="4.1.14"></a>
|
||||
## [4.1.14](https://github.com/QingWei-Li/docsify/compare/v4.1.13...v4.1.14) (2017-06-24)
|
||||
|
||||
* fix: .md file extension regex
|
||||
|
||||
## 3.5.0 / 2017-03-25
|
||||
### Bug Fixes
|
||||
|
||||
* feat(route): auto remove .md extension
|
||||
* fix: adjust display on small screens [@jrappen](https://github.com/jrappen)
|
||||
* fix: navbar labels for German [@jrappen](https://github.com/jrappen)
|
||||
* 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)
|
||||
|
||||
## 3.4.4 / 2017-03-17
|
||||
|
||||
* fix(search): fix input style
|
||||
* fix search plugin match bug
|
||||
### Features
|
||||
|
||||
## 3.4.3 / 2017-03-16
|
||||
* add context attribute, fixed [#191](https://github.com/QingWei-Li/docsify/issues/191) ([ce0e9ac](https://github.com/QingWei-Li/docsify/commit/ce0e9ac))
|
||||
|
||||
* Add ability to ignore headers when generating toc ([#127](https://github.com/QingWei-Li/docsify/issues/127) [@christopherwk210](https://github.com/christopherwk210))
|
||||
* fix external-script not inserting script at right place [@Leopoldthecoder](https://github.com/Leopoldthecoder)
|
||||
* add German docs [@jrappen](https://github.com/jrappen)
|
||||
|
||||
## 3.4.2 / 2017-03-11
|
||||
|
||||
* feat(emojify): add no-emoji option
|
||||
<a name="4.1.13"></a>
|
||||
## [4.1.13](https://github.com/QingWei-Li/docsify/compare/v4.1.12...v4.1.13) (2017-06-11)
|
||||
|
||||
## 3.4.1 / 2017-03-10
|
||||
|
||||
* fix(dom): Disable the dom cache when vue is present, fixed [#119](https://github.com/QingWei-Li/docsify/issues/119)
|
||||
* update english docs, [@jrappen](https://github.com/jrappen)
|
||||
|
||||
## 3.4.0 / 2017-03-09
|
||||
<a name="4.1.12"></a>
|
||||
## [4.1.12](https://github.com/QingWei-Li/docsify/compare/v4.1.11...v4.1.12) (2017-06-03)
|
||||
|
||||
* feat(zoom-image): add plugin
|
||||
|
||||
## 3.3.0 / 2017-03-07
|
||||
### Bug Fixes
|
||||
|
||||
* add front-matter plugin
|
||||
* add external-script plugin, [@Leopoldthecoder](https://github.com/Leopoldthecoder)
|
||||
* Fix nav showing while loading ([#112](https://github.com/QingWei-Li/docsify/issues/112))
|
||||
* **render:** ubtitle in side bar shows undefined, fixed [#182](https://github.com/QingWei-Li/docsify/issues/182) ([d087d57](https://github.com/QingWei-Li/docsify/commit/d087d57))
|
||||
|
||||
## 3.2.0 / 2017-02-28
|
||||
|
||||
* fix(render): Toc rendering error, fixed [#106](https://github.com/QingWei-Li/docsify/issues/106)
|
||||
* feat(search): Localization for no data tip, close [#103](https://github.com/QingWei-Li/docsify/issues/103)
|
||||
* fix(fetch): load sidebar and navbar for parent path, fixed [#100](https://github.com/QingWei-Li/docsify/issues/100)
|
||||
* feat(render) nameLink for each route, fixed [#99](https://github.com/QingWei-Li/docsify/issues/99)
|
||||
|
||||
## 3.1.2 / 2017-02-27
|
||||
<a name="4.1.11"></a>
|
||||
## [4.1.11](https://github.com/QingWei-Li/docsify/compare/v4.1.10...v4.1.11) (2017-06-02)
|
||||
|
||||
* fix(search): dont search nameLink, fixed [#102](https://github.com/QingWei-Li/docsify/issues/102)
|
||||
|
||||
## 3.1.1 / 2017-02-24
|
||||
### Bug Fixes
|
||||
|
||||
* fix(search): dont search nameLink, fixed [#102](https://github.com/QingWei-Li/docsify/issues/102)
|
||||
* fix(render): custom cover background image
|
||||
* fix(tpl): extra character, fixed [#101](https://github.com/QingWei-Li/docsify/issues/101)
|
||||
* **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))
|
||||
|
||||
## 3.1.0 / 2017-02-22
|
||||
|
||||
* fix(search): incorrect anchor link, fixed [#90](https://github.com/QingWei-Li/docsify/issues/90)
|
||||
* feat(emoji): add emoji plugin
|
||||
|
||||
## 3.0.5 / 2017-02-21
|
||||
<a name="4.1.10"></a>
|
||||
## [4.1.10](https://github.com/QingWei-Li/docsify/compare/v4.1.9...v4.1.10) (2017-06-02)
|
||||
|
||||
* feat(pwa): add sw.js
|
||||
* fix(layout.css): loading style
|
||||
* fix(event): highlight sidebar when clicked, fixed [#86](https://github.com/QingWei-Li/docsify/issues/86)
|
||||
* fix(gen-tree): cache toc list, fixed [#88](https://github.com/QingWei-Li/docsify/issues/88)
|
||||
|
||||
## 3.0.4 / 2017-02-20
|
||||
### Bug Fixes
|
||||
|
||||
* fix(render): execute script
|
||||
* fix(render): disable rendering sub list when loadSidebar is false
|
||||
* **hash:** hash routing crashes when url has querystring ([6d48ce1](https://github.com/QingWei-Li/docsify/commit/6d48ce1))
|
||||
|
||||
## 3.0.3 / 2017-02-19
|
||||
|
||||
* fixed look of links in blockquote
|
||||
* fix(scroll) highlight bug
|
||||
|
||||
## 3.0.2 / 2017-02-19
|
||||
<a name="4.1.9"></a>
|
||||
## [4.1.9](https://github.com/QingWei-Li/docsify/compare/v4.1.8...v4.1.9) (2017-05-31)
|
||||
|
||||
* fix(search): add lazy input
|
||||
* fix(compiler): link
|
||||
|
||||
## 3.0.1 / 2017-02-19
|
||||
### Bug Fixes
|
||||
|
||||
* fix(route): empty alias
|
||||
* 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))
|
||||
|
||||
## 3.0.0 / 2017-02-19
|
||||
|
||||
##### Breaking change
|
||||
|
||||
* Not support IE9
|
||||
* The route becomes: `/#/page?id=slug`. The previous route will be redirected
|
||||
<a name="4.1.8"></a>
|
||||
## [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))
|
||||
|
||||
|
||||
|
||||
<a name="4.1.7"></a>
|
||||
## [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))
|
||||
|
||||
|
||||
|
||||
<a name="4.1.6"></a>
|
||||
## [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))
|
||||
|
||||
|
||||
|
||||
<a name="4.1.5"></a>
|
||||
## [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))
|
||||
|
||||
|
||||
|
||||
<a name="4.1.4"></a>
|
||||
## [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))
|
||||
|
||||
|
||||
|
||||
<a name="4.1.3"></a>
|
||||
## [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))
|
||||
|
||||
|
||||
|
||||
<a name="4.1.2"></a>
|
||||
## [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))
|
||||
|
||||
|
||||
|
||||
<a name="4.1.1"></a>
|
||||
## [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))
|
||||
|
||||
|
||||
|
||||
<a name="4.1.0"></a>
|
||||
# [4.1.0](https://github.com/QingWei-Li/docsify/compare/v4.0.2...v4.1.0) (2017-05-30)
|
||||
|
||||
|
||||
|
||||
<a name="4.0.2"></a>
|
||||
## [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))
|
||||
|
||||
|
||||
|
||||
<a name="4.0.1"></a>
|
||||
## [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))
|
||||
|
||||
|
||||
|
||||
<a name="4.0.0"></a>
|
||||
# [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))
|
||||
|
||||
##### Features
|
||||
|
||||
* Faster rendering
|
||||
* Clearer source code
|
||||
* More powerful API
|
||||
* Auto header for each page [#78](https://github.com/QingWei-Li/docsify/issues/78)
|
||||
* Localization for search plugin [#80](https://github.com/QingWei-Li/docsify/issues/80)
|
||||
* Execute the script in markdown (see `executeScript`)
|
||||
|
||||
+568
-344
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,9 @@
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/QingWei-Li/docsify"><img alt="Travis Status" src="https://img.shields.io/travis/QingWei-Li/docsify/master.svg?style=flat-square"></a>
|
||||
<a href="https://www.npmjs.com/package/docsify"><img alt="npm" src="https://img.shields.io/npm/v/docsify.svg?style=flat-square"></a>
|
||||
<a href="https://cdnjs.com/libraries/docsify"><img alt="cdnjs" src="https://img.shields.io/cdnjs/v/docsify.svg?style=flat-square"></a>
|
||||
<a href="https://github.com/QingWei-Li/donate"><img alt="donate" src="https://img.shields.io/badge/%24-donate-ff69b4.svg?style=flat-square"></a>
|
||||
<a href="https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FQingWei-Li%2Fdocsify?ref=badge_shield" alt="FOSSA Status"><img src="https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FQingWei-Li%2Fdocsify.svg?type=shield"/></a>
|
||||
</p>
|
||||
|
||||
## Links
|
||||
@@ -22,11 +24,12 @@
|
||||
## Features
|
||||
|
||||
- No statically built html files
|
||||
- Simple and lightweight (~16kB gzipped)
|
||||
- Simple and lightweight (~18kB gzipped)
|
||||
- Smart full-text search plugin
|
||||
- Multiple themes
|
||||
- Useful plugin API
|
||||
- Compatible with IE10+
|
||||
- Support SSR ([example](https://github.com/QingWei-Li/docsify-ssr-demo))
|
||||
|
||||
## Quick start
|
||||
|
||||
@@ -39,12 +42,12 @@ Create an `index.html`.
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/vue.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
|
||||
</body>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
@@ -54,7 +57,7 @@ Modern browsers and Internet Explorer 10+.
|
||||
|
||||
## Showcase
|
||||
|
||||
These open-source projects are using docsify to generate their sites. Pull requests welcome :blush:
|
||||
These projects are using docsify to generate their sites. Pull requests welcome :blush:
|
||||
|
||||
| Project | Description |
|
||||
|---|---|
|
||||
@@ -66,6 +69,11 @@ These open-source projects are using docsify to generate their sites. Pull reque
|
||||
| [Mybatis-Plus](http://mp.baomidou.com/) | An enhanced toolkit of Mybatis to simplify development |
|
||||
| [JS MythBusters](https://mythbusters.js.org) | An optimization handbook from a high level point of view. |
|
||||
| [hire-me](https://fvcproductions.github.io/hire-me) | A path to getting an awesome tech gig. |
|
||||
| [vue-amap](https://elemefe.github.io/vue-amap/) | A Map Component Library Base on Vue 2.x and Gaode Map. |
|
||||
| [samlify](https://samlify.js.org) | Node.js SAML2 library |
|
||||
| [palettify](https://dobromir-hristov.github.io/palettify/) | A color palette effects assistant |
|
||||
| [commitlint](https://marionebl.github.io/commitlint/) | Lint commit messages |
|
||||
| [vue-data-tables](https://github.com/njleonzhang/vue-data-tables/) | A simple and customizable data table,based on vue2 and element-ui. |
|
||||
|
||||
## Similar projects
|
||||
|
||||
@@ -86,10 +94,12 @@ These open-source projects are using docsify to generate their sites. Pull reque
|
||||
## Development
|
||||
|
||||
```bash
|
||||
npm i && npm run dev
|
||||
npm run bootstrap && npm run dev
|
||||
open http://localhost:3000
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FQingWei-Li%2Fdocsify?ref=badge_large)
|
||||
|
||||
@@ -1,12 +1,51 @@
|
||||
var serveStatic = require('serve-static')
|
||||
var http = require('http')
|
||||
var fs = require('fs')
|
||||
var Renderer = require('./packages/docsify-server-renderer/build.js')
|
||||
|
||||
var renderer = new Renderer({
|
||||
template: `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>docsify</title>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="/themes/vue.css" title="vue">
|
||||
</head>
|
||||
<body>
|
||||
<!--inject-app-->
|
||||
<!--inject-config-->
|
||||
<script src="/lib/docsify.js"></script>
|
||||
</body>
|
||||
</html>`,
|
||||
config: {
|
||||
name: 'docsify',
|
||||
repo: 'qingwei-li/docsify',
|
||||
basePath: 'https://docsify.js.org/',
|
||||
loadNavbar: true,
|
||||
loadSidebar: true,
|
||||
subMaxLevel: 3,
|
||||
auto2top: true,
|
||||
alias: {
|
||||
'/de-de/changelog': '/changelog',
|
||||
'/zh-cn/changelog': '/changelog',
|
||||
'/changelog': 'https://raw.githubusercontent.com/QingWei-Li/docsify/master/CHANGELOG'
|
||||
}
|
||||
},
|
||||
path: './'
|
||||
})
|
||||
|
||||
http.createServer(function (req, res) {
|
||||
serveStatic('.')(req, res, function () {
|
||||
// TEST SSR
|
||||
// renderer.renderToString(req.url)
|
||||
// .then(html => res.end(html))
|
||||
|
||||
res.writeHead(404, { 'Content-Type': 'text/html' })
|
||||
res.end(fs.readFileSync('dev.html'))
|
||||
})
|
||||
}).listen(3000, '0.0.0.0')
|
||||
|
||||
console.log(`\nListening at http://0.0.0.0:3000\n`)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
var fs = require('fs')
|
||||
var read = fs.readFileSync
|
||||
var write = fs.writeFileSync
|
||||
var version = process.env.VERSION || require('../package.json').version
|
||||
|
||||
var file = __dirname + '/../docs/_coverpage.md'
|
||||
var cover = read(file, 'utf8').toString()
|
||||
|
||||
console.log('Replace version number in cover page...')
|
||||
cover = cover.replace(/<small>(\S+)?<\/small>/g, '<small>' + version + '</small>')
|
||||
write(file, cover)
|
||||
@@ -0,0 +1,33 @@
|
||||
var rollup = require('rollup')
|
||||
var buble = require('rollup-plugin-buble')
|
||||
var async = require('rollup-plugin-async')
|
||||
var replace = require('rollup-plugin-replace')
|
||||
|
||||
rollup
|
||||
.rollup({
|
||||
entry: 'packages/docsify-server-renderer/index.js',
|
||||
plugins: [
|
||||
async(),
|
||||
replace({
|
||||
__VERSION__: process.env.VERSION || require('../package.json').version
|
||||
}),
|
||||
buble({
|
||||
transforms: {
|
||||
generator: false
|
||||
}
|
||||
})
|
||||
],
|
||||
onwarn: function() {}
|
||||
})
|
||||
.then(function (bundle) {
|
||||
var dest = 'packages/docsify-server-renderer/build.js'
|
||||
|
||||
console.log(dest)
|
||||
bundle.write({
|
||||
format: 'cjs',
|
||||
dest: dest
|
||||
})
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err)
|
||||
})
|
||||
+13
-11
@@ -4,7 +4,9 @@ var commonjs = require('rollup-plugin-commonjs')
|
||||
var nodeResolve = require('rollup-plugin-node-resolve')
|
||||
var string = require('rollup-plugin-string')
|
||||
var uglify = require('rollup-plugin-uglify')
|
||||
var replace = require('rollup-plugin-replace')
|
||||
var isProd = process.argv[process.argv.length - 1] !== '--dev'
|
||||
var version = process.env.VERSION || require('../package.json').version
|
||||
|
||||
var build = function (opts) {
|
||||
rollup
|
||||
@@ -14,7 +16,10 @@ var build = function (opts) {
|
||||
string({ include: '**/*.css' }),
|
||||
buble(),
|
||||
commonjs(),
|
||||
nodeResolve()
|
||||
nodeResolve(),
|
||||
replace({
|
||||
__VERSION__: version
|
||||
})
|
||||
])
|
||||
})
|
||||
.then(function (bundle) {
|
||||
@@ -23,7 +28,6 @@ var build = function (opts) {
|
||||
console.log(dest)
|
||||
bundle.write({
|
||||
format: 'iife',
|
||||
moduleName: opts.moduleName || 'D',
|
||||
dest: dest
|
||||
})
|
||||
})
|
||||
@@ -38,19 +42,18 @@ build({
|
||||
})
|
||||
|
||||
var plugins = [
|
||||
{ name: 'search', entry: 'search/index.js', moduleName: 'Search' },
|
||||
{ name: 'ga', entry: 'ga.js', moduleName: 'GA' },
|
||||
{ name: 'emoji', entry: 'emoji.js', moduleName: 'Emoji' },
|
||||
{ name: 'external-script', entry: 'external-script.js', moduleName: 'ExternalScript' },
|
||||
{ name: 'front-matter', entry: 'front-matter/index.js', moduleName: 'FrontMatter' },
|
||||
{ name: 'zoom-image', entry: 'zoom-image.js', moduleName: 'ZoomImage' }
|
||||
{ name: 'search', entry: 'search/index.js' },
|
||||
{ name: 'ga', entry: 'ga.js' },
|
||||
{ name: 'emoji', entry: 'emoji.js' },
|
||||
{ name: 'external-script', entry: 'external-script.js' },
|
||||
{ name: 'front-matter', entry: 'front-matter/index.js' },
|
||||
{ name: 'zoom-image', entry: 'zoom-image.js' }
|
||||
]
|
||||
|
||||
plugins.forEach(item => {
|
||||
build({
|
||||
entry: 'plugins/' + item.entry,
|
||||
output: 'plugins/' + item.name + '.js',
|
||||
moduleName: 'D.' + item.moduleName
|
||||
output: 'plugins/' + item.name + '.js'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -64,7 +67,6 @@ if (isProd) {
|
||||
build({
|
||||
entry: 'plugins/' + item.entry,
|
||||
output: 'plugins/' + item.name + '.min.js',
|
||||
moduleName: 'D.' + item.moduleName,
|
||||
plugins: [uglify()]
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
set -e
|
||||
|
||||
if [[ -z $1 ]]; then
|
||||
echo "Enter new version: "
|
||||
read VERSION
|
||||
else
|
||||
VERSION=$1
|
||||
fi
|
||||
|
||||
read -p "Releasing $VERSION $RELEASE_TAG - are you sure? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Releasing $VERSION ..."
|
||||
|
||||
npm run test
|
||||
|
||||
# build
|
||||
VERSION=$VERSION npm run build
|
||||
|
||||
# update packages
|
||||
cd packages/docsify-server-renderer
|
||||
npm version $VERSION
|
||||
if [[ -z $RELEASE_TAG ]]; then
|
||||
npm publish
|
||||
else
|
||||
npm publish --tag $RELEASE_TAG
|
||||
fi
|
||||
cd -
|
||||
|
||||
# commit
|
||||
git add -A
|
||||
git commit -m "[build] $VERSION $RELEASE_TAG"
|
||||
npm version $VERSION --message "[release] $VERSION $RELEASE_TAG"
|
||||
|
||||
# changelog
|
||||
node_modules/.bin/conventional-changelog -p angular -i CHANGELOG.md -s -r 2
|
||||
|
||||
git add .
|
||||
git commit -m "chore: add changelog $VERSION"
|
||||
|
||||
# publish
|
||||
git push origin refs/tags/v$VERSION
|
||||
git push
|
||||
if [[ -z $RELEASE_TAG ]]; then
|
||||
npm publish
|
||||
else
|
||||
npm publish --tag $RELEASE_TAG
|
||||
fi
|
||||
fi
|
||||
@@ -19,18 +19,33 @@
|
||||
<script>
|
||||
window.$docsify = {
|
||||
alias: {
|
||||
'/de-de/changelog': '/changelog',
|
||||
'/zh-cn/changelog': '/changelog',
|
||||
'/changelog': 'https://raw.githubusercontent.com/QingWei-Li/docsify/master/CHANGELOG'
|
||||
'.*?/changelog': 'https://raw.githubusercontent.com/QingWei-Li/docsify/master/CHANGELOG',
|
||||
'/.*/_navbar.md': '/_navbar.md'
|
||||
},
|
||||
auto2top: true,
|
||||
basePath: '/docs/',
|
||||
executeScript: true,
|
||||
loadNavbar: true,
|
||||
loadSidebar: true,
|
||||
coverpage: true,
|
||||
name: 'docsify',
|
||||
subMaxLevel: 2,
|
||||
mergeNavbar: true
|
||||
subMaxLevel: 0,
|
||||
mergeNavbar: true,
|
||||
formatUpdated: '{MM}/{DD} {HH}:{mm}',
|
||||
plugins: [
|
||||
function(hook, vm) {
|
||||
hook.beforeEach(function (html) {
|
||||
var url = 'https://github.com/QingWei-Li/docsify/blob/master/' + vm.route.file
|
||||
var editHtml = '[:memo: Edit Document](' + url + ')\n'
|
||||
|
||||
return editHtml
|
||||
+ html
|
||||
+ '\n----\n'
|
||||
+ 'Last modified {docsify-updated} '
|
||||
+ editHtml
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<script src="/lib/docsify.js"></script>
|
||||
|
||||
+2
-1
@@ -11,12 +11,13 @@ See the [Quick start](quickstart.md) for more details.
|
||||
## Features
|
||||
|
||||
* No statically built html files
|
||||
* Simple and lightweight (~16kB gzipped)
|
||||
* Simple and lightweight (~18kB gzipped)
|
||||
* Smart full-text search plugin
|
||||
* Multiple themes
|
||||
* Useful plugin API
|
||||
* Emoji support
|
||||
* Compatible with IE10+
|
||||
- Support SSR ([example](https://github.com/QingWei-Li/docsify-ssr-demo))
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||

|
||||
|
||||
# docsify <small>3.6</small>
|
||||
# docsify <small>4.2.3</small>
|
||||
|
||||
> A magical documentation site generator.
|
||||
|
||||
- Simple and lightweight (~16kB gzipped)
|
||||
- Simple and lightweight (~18kB gzipped)
|
||||
- No statically built html files
|
||||
- Multiple themes
|
||||
|
||||
|
||||
@@ -18,5 +18,6 @@
|
||||
- [Vue compatibility](vue.md)
|
||||
- [CDN](cdn.md)
|
||||
- [Offline Mode(PWA)](pwa.md)
|
||||
- [Server-client renderer(SSR)](ssr.md)
|
||||
|
||||
- [Changelog](changelog.md)
|
||||
|
||||
+1
-1
@@ -45,6 +45,6 @@ Alternatively, use [compressed files](#compressed-files).
|
||||
## Other CDN
|
||||
|
||||
- http://www.bootcdn.cn/docsify
|
||||
- http://www.jsdelivr.com/projects/docsify
|
||||
- https://cdn.jsdelivr.net/npm/docsify/
|
||||
- https://cdnjs.com/libraries/docsify
|
||||
|
||||
|
||||
+66
-1
@@ -250,11 +250,12 @@ window.$docsify = {
|
||||
|
||||
- Type: `Object`
|
||||
|
||||
Set the route alias. You can freely manage routing rules.
|
||||
Set the route alias. You can freely manage routing rules. Supports RegExp.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
alias: {
|
||||
'/foo/(+*)': '/bar/$1', // supports regexp
|
||||
'/zh-cn/changelog': '/changelog',
|
||||
'/changelog': 'https://raw.githubusercontent.com/QingWei-Li/docsify/master/CHANGELOG'
|
||||
}
|
||||
@@ -298,6 +299,8 @@ Note that if you are running an external script, e.g. an embedded jsfiddle demo,
|
||||
|
||||
## no-emoji
|
||||
|
||||
- type: `Boolean`
|
||||
|
||||
Disabled emoji parse.
|
||||
|
||||
```js
|
||||
@@ -308,6 +311,8 @@ window.$docsify = {
|
||||
|
||||
## merge-navbar
|
||||
|
||||
- type: `Boolean`
|
||||
|
||||
Navbar will be merged with the sidebar on smaller screens.
|
||||
|
||||
```js
|
||||
@@ -315,3 +320,63 @@ window.$docsify = {
|
||||
mergeNavbar: true
|
||||
}
|
||||
```
|
||||
|
||||
## format-updated
|
||||
|
||||
- type: `String|Function`
|
||||
|
||||
We can display the file update date through **{docsify-updated<span>}</span>** variable. And format it by `formatUpdated`.
|
||||
See https://github.com/lukeed/tinydate#patterns
|
||||
```js
|
||||
window.$docsify = {
|
||||
formatUpdated: '{MM}/{DD} {HH}:{mm}',
|
||||
|
||||
formatUpdated: function (time) {
|
||||
// ...
|
||||
|
||||
return time
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## external-link-target
|
||||
|
||||
- type: `String`
|
||||
- default: `_self`
|
||||
|
||||
Target to open external links. Default `'_blank'` (new window/tab)
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
externalLinkTarget: '_self' // default: '_blank'
|
||||
}
|
||||
```
|
||||
|
||||
## router-mode
|
||||
|
||||
- type: `String`
|
||||
- default: `history`
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
routerMode: 'history' // default: 'hash'
|
||||
}
|
||||
```
|
||||
|
||||
## noCompileLinks
|
||||
|
||||
- type: `Array`
|
||||
|
||||
|
||||
Sometimes we do not want docsify to handle our links. See [#203](https://github.com/QingWei-Li/docsify/issues/203)
|
||||
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
noCompileLinks: [
|
||||
'/foo',
|
||||
'/bar/.*'
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ Set `coverpage` to **true**, and create a `_coverpage.md`:
|
||||
|
||||
> A magical documentation site generator.
|
||||
|
||||
- Simple and lightweight (~16kB gzipped)
|
||||
- Simple and lightweight (~18kB gzipped)
|
||||
- No statically built html files
|
||||
- Multiple themes
|
||||
|
||||
|
||||
@@ -11,12 +11,13 @@ Siehe [Schnellstart](de-de/quickstart.md) für weitere Informationen.
|
||||
## Features
|
||||
|
||||
* keine generierten, statischen HTML Dateien
|
||||
* einfach und klein (~16kB gzipped)
|
||||
* einfach und klein (~18kB gzipped)
|
||||
* smarte Erweiterung mit Volltextsuche
|
||||
* mehrere Themes
|
||||
* praktische API für Erweiterungen
|
||||
* Unterstützung für Emoji
|
||||
* Kompatibel mit IE10+
|
||||
- Support SSR ([example](https://github.com/QingWei-Li/docsify-ssr-demo))
|
||||
|
||||
## Beispiele
|
||||
|
||||
|
||||
@@ -18,5 +18,6 @@
|
||||
- [Vue Kompatibilität](de-de/vue.md)
|
||||
- [CDN](de-de/cdn.md)
|
||||
- [Offline Modus (PWA)](de-de/pwa.md)
|
||||
- [Server-client renderer (SSR)](de-de/ssr.md)
|
||||
|
||||
- [Changelog](de-de/changelog.md)
|
||||
|
||||
+1
-1
@@ -45,5 +45,5 @@ Alternativ kannst du auch die [komprimierten Dateien](#komprimierte-dateien) ver
|
||||
## Andere CDN
|
||||
|
||||
- http://www.bootcdn.cn/docsify
|
||||
- http://www.jsdelivr.com/projects/docsify
|
||||
- https://cdn.jsdelivr.net/npm/docsify/
|
||||
- https://cdnjs.com/libraries/docsify
|
||||
|
||||
@@ -250,11 +250,12 @@ window.$docsify = {
|
||||
|
||||
- Typ: `Object`
|
||||
|
||||
Verwende alternative Routen. Du kannst sie ungehindert anpassen.
|
||||
Verwende alternative Routen. Du kannst sie ungehindert anpassen. Supports RegExp.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
alias: {
|
||||
'/foo/(+*)': '/bar/$1', // supports regexp
|
||||
'/zh-cn/changelog': '/changelog',
|
||||
'/changelog': 'https://raw.githubusercontent.com/QingWei-Li/docsify/master/CHANGELOG'
|
||||
}
|
||||
@@ -314,4 +315,47 @@ Navbar will be merged with the sidebar on smaller screens.
|
||||
window.$docsify = {
|
||||
mergeNavbar: true
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
## format-updated
|
||||
We can display the file update date through **{docsify-updated<span>}</span>** variable. And format it by `formatUpdated`.
|
||||
See https://github.com/lukeed/tinydate#patterns
|
||||
```js
|
||||
window.$docsify = {
|
||||
formatUpdated: '{MM}/{DD} {HH}:{mm}',
|
||||
|
||||
formatUpdated: function (time) {
|
||||
// ...
|
||||
|
||||
return time
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## external-link-target
|
||||
|
||||
Currently it defaults to _blank, would be nice if configurable:
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
externalLinkTarget: '_self' // default: '_blank'
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## noCompileLinks
|
||||
|
||||
- type: `Array`
|
||||
|
||||
|
||||
Sometimes we do not want docsify to handle our links. See [#203](https://github.com/QingWei-Li/docsify/issues/203)
|
||||
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
noCompileLinks: [
|
||||
'/foo',
|
||||
'/bar/.*'
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ Setze `coverpage` auf **true**, und erstelle `_coverpage.md`:
|
||||
|
||||
> Ein magischer Generator für Dokumentationsseiten.
|
||||
|
||||
- Einfach und wenig Speicherbedarf (~16kB gzipped)
|
||||
- Einfach und wenig Speicherbedarf (~18kB gzipped)
|
||||
- Keine statischen HTML Dateien
|
||||
- Mehrere Themes
|
||||
|
||||
|
||||
@@ -25,3 +25,27 @@ Generelle Tipps wie:
|
||||
wird wie folgt gerendert:
|
||||
|
||||
?> *TODO* unit test
|
||||
|
||||
## Ignore to compile link
|
||||
|
||||
Some time we will put some other relative path to the link, you have to need to tell docsify you don't need to compile this link. For example
|
||||
|
||||
```md
|
||||
[link](/demo/)
|
||||
```
|
||||
|
||||
|
||||
It will be compiled to `<a href="/#/demo/">link</a>` and will be loaded `/demo/README.md`. Maybe you want to jump to `/demo/index.html`.
|
||||
|
||||
Now you can do that
|
||||
|
||||
```md
|
||||
[link](/demo/ ":ignore")
|
||||
```
|
||||
You will get `<a href="/demo/">link</a>`html. Do not worry, you can still set title for link.
|
||||
|
||||
```md
|
||||
[link](/demo/ ":ignore title")
|
||||
|
||||
<a href="/demo/" title="title">link</a>
|
||||
```
|
||||
|
||||
@@ -35,7 +35,10 @@ Als Standardeinstellung werden Hyperlinks auf der aktuellen Seite erkannt und de
|
||||
noData: {
|
||||
'/de-de/': 'Keine Ergebnisse',
|
||||
'/': 'No Results'
|
||||
}
|
||||
},
|
||||
|
||||
// Headline depth, 1 - 6
|
||||
depth: 2
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# Server client renderer
|
||||
|
||||
See https://docsify.now.sh
|
||||
|
||||
Repo in https://github.com/QingWei-Li/docsify-ssr-demo
|
||||
|
||||
## Why SSR?
|
||||
- Better SEO
|
||||
- Feeling cool
|
||||
|
||||
## Quick start
|
||||
|
||||
Install `now` and `docsify-cli` in your project.
|
||||
|
||||
```bash
|
||||
npm i now docsify-cli -D
|
||||
```
|
||||
|
||||
Edit `package.json`. If the documentation in `./docs` subdirectory.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-project",
|
||||
"scripts": {
|
||||
"start": "docsify start . -c ssr.config.js",
|
||||
"deploy": "now -p"
|
||||
},
|
||||
"files": [
|
||||
"docs"
|
||||
],
|
||||
"docsify": {
|
||||
"config": {
|
||||
"basePath": 'https://docsify.js.org/',
|
||||
"loadSidebar": true,
|
||||
"loadNavbar": true,
|
||||
"coverpage": true,
|
||||
"name": "docsify"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!> The `basePath` just like webpack `publicPath`. We can use local or remote files.
|
||||
|
||||
We can preview in the local to see if it works.
|
||||
|
||||
```bash
|
||||
npm start
|
||||
|
||||
# open http://localhost:4000
|
||||
```
|
||||
|
||||
Publish it!
|
||||
|
||||
```bash
|
||||
now -p
|
||||
```
|
||||
|
||||
Now, You have a support for SSR the docs site.
|
||||
|
||||
## Custom template
|
||||
|
||||
You can provide a templte for entire page's HTML. such as
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>docsify</title>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/themes/vue.css" title="vue">
|
||||
</head>
|
||||
<body>
|
||||
<!--inject-app-->
|
||||
<!--inject-config-->
|
||||
</body>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-markdown.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-nginx.min.js"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
The template should contain these comments for rendered app content.
|
||||
- `<!--inject-app-->`
|
||||
- `<!--inject-config-->`
|
||||
|
||||
## Configuration
|
||||
|
||||
You can configure it in a special config file, or `package.json`.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
template: './ssr.html',
|
||||
config: {
|
||||
// docsify config
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Deploy for your VPS
|
||||
|
||||
You can run `docsify start` directly on your Node server, or write your own server app with `docsify-server-renderer`.
|
||||
|
||||
```js
|
||||
var Renderer = require('docsify-server-renderer')
|
||||
var readFileSync = require('fs').readFileSync
|
||||
|
||||
// init
|
||||
var renderer = new Renderer({
|
||||
template: readFileSync('./docs/index.template.html', 'utf-8').,
|
||||
config: {
|
||||
name: 'docsify',
|
||||
repo: 'qingwei-li/docsify'
|
||||
}
|
||||
})
|
||||
|
||||
renderer.renderToString(url)
|
||||
.then(html => {})
|
||||
.catch(err => {})
|
||||
```
|
||||
@@ -47,6 +47,8 @@ window.$docsify = {
|
||||
|
||||
## Beispiel
|
||||
|
||||
### footer
|
||||
|
||||
Füge jeder Seite eine footer Komponente hinzu:
|
||||
|
||||
```js
|
||||
@@ -68,3 +70,25 @@ window.$docsify = {
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Edit Button
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
plugins: [
|
||||
function(hook, vm) {
|
||||
hook.beforeEach(function (html) {
|
||||
var url = 'https://github.com/QingWei-Li/docsify/blob/master/docs' + vm.route.file
|
||||
var editHtml = '[📝 EDIT DOCUMENT](' + url + ')\n'
|
||||
|
||||
return editHtml
|
||||
+ html
|
||||
+ '\n----\n'
|
||||
+ 'Last modified {docsify-updated} '
|
||||
+ editHtml
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -25,3 +25,28 @@ General tips like:
|
||||
are rendered as:
|
||||
|
||||
?> *TODO* unit test
|
||||
|
||||
## Ignore to compile link
|
||||
|
||||
Some time we will put some other relative path to the link, you have to need to tell docsify you don't need to compile this link. For example
|
||||
|
||||
```md
|
||||
[link](/demo/)
|
||||
```
|
||||
|
||||
|
||||
It will be compiled to `<a href="/#/demo/">link</a>` and will be loaded `/demo/README.md`. Maybe you want to jump to `/demo/index.html`.
|
||||
|
||||
Now you can do that
|
||||
|
||||
```md
|
||||
[link](/demo/ ":ignore")
|
||||
```
|
||||
You will get `<a href="/demo/">link</a>`html. Do not worry, you can still set title for link.
|
||||
|
||||
```md
|
||||
[link](/demo/ ":ignore title")
|
||||
|
||||
<a href="/demo/" title="title">link</a>
|
||||
```
|
||||
|
||||
|
||||
+27
-13
@@ -7,10 +7,10 @@
|
||||
<meta name="keywords" content="doc,docs,documentation,gitbook,creator,generator,github,jekyll,github-pages">
|
||||
<meta name="description" content="A magical documentation generator.">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css" title="vue">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/dark.css" title="dark" disabled>
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/buble.css" title="buble" disabled>
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/pure.css" title="pure" disabled>
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@latest/lib/themes/vue.css" title="vue">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@latest/lib/themes/dark.css" title="dark" disabled>
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@latest/lib/themes/buble.css" title="buble" disabled>
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@latest/lib/themes/pure.css" title="pure" disabled>
|
||||
<style>
|
||||
nav.app-nav li ul {
|
||||
min-width: 100px;
|
||||
@@ -23,9 +23,8 @@
|
||||
<script>
|
||||
window.$docsify = {
|
||||
alias: {
|
||||
'/de-de/changelog': '/changelog',
|
||||
'/zh-cn/changelog': '/changelog',
|
||||
'/changelog': 'https://raw.githubusercontent.com/QingWei-Li/docsify/master/CHANGELOG'
|
||||
'.*?/changelog': 'https://raw.githubusercontent.com/QingWei-Li/docsify/master/CHANGELOG',
|
||||
'/.*/_navbar.md': '/_navbar.md'
|
||||
},
|
||||
auto2top: true,
|
||||
coverpage: true,
|
||||
@@ -34,6 +33,7 @@
|
||||
loadNavbar: true,
|
||||
mergeNavbar: true,
|
||||
maxLevel: 4,
|
||||
subMaxLevel: 2,
|
||||
name: 'docsify',
|
||||
search: {
|
||||
noData: {
|
||||
@@ -48,12 +48,26 @@
|
||||
'/': 'Search'
|
||||
}
|
||||
},
|
||||
subMaxLevel: 2
|
||||
formatUpdated: '{MM}/{DD} {HH}:{mm}',
|
||||
plugins: [
|
||||
function(hook, vm) {
|
||||
hook.beforeEach(function (html) {
|
||||
var url = 'https://github.com/QingWei-Li/docsify/blob/master/docs/' + vm.route.file
|
||||
var editHtml = '[:memo: Edit Document](' + url + ')\n'
|
||||
|
||||
return editHtml
|
||||
+ html
|
||||
+ '\n----\n'
|
||||
+ 'Last modified {docsify-updated} '
|
||||
+ editHtml
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-markdown.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-nginx.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify@latest/lib/docsify.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify@latest/lib/plugins/search.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-markdown.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-nginx.min.js"></script>
|
||||
</html>
|
||||
|
||||
+6
-6
@@ -6,12 +6,12 @@ For example, the directory structure is as follows:
|
||||
|
||||
```text
|
||||
.
|
||||
├── docs
|
||||
| └── README.md
|
||||
| └── guide.md
|
||||
| └── zh-cn
|
||||
| └──README.md
|
||||
| └──guide.md
|
||||
└── docs
|
||||
├── README.md
|
||||
├── guide.md
|
||||
└── zh-cn
|
||||
├── README.md
|
||||
└── guide.md
|
||||
```
|
||||
|
||||
Matching routes
|
||||
|
||||
+4
-1
@@ -35,7 +35,10 @@ By default, the hyperlink on the current page is recognized and the content is s
|
||||
noData: {
|
||||
'/zh-cn/': '找不到结果',
|
||||
'/': 'No Results'
|
||||
}
|
||||
},
|
||||
|
||||
// Headline depth, 1 - 6
|
||||
depth: 2
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
# Server client renderer
|
||||
|
||||
See https://docsify.now.sh
|
||||
|
||||
Repo in https://github.com/QingWei-Li/docsify-ssr-demo
|
||||
|
||||
## Why SSR?
|
||||
- Better SEO
|
||||
- Feeling cool
|
||||
|
||||
## Quick start
|
||||
|
||||
Install `now` and `docsify-cli` in your project.
|
||||
|
||||
```bash
|
||||
npm i now docsify-cli -D
|
||||
```
|
||||
|
||||
Edit `package.json`. If the documentation in `./docs` subdirectory.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-project",
|
||||
"scripts": {
|
||||
"start": "docsify start . -c ssr.config.js",
|
||||
"deploy": "now -p"
|
||||
},
|
||||
"files": [
|
||||
"docs"
|
||||
],
|
||||
"docsify": {
|
||||
"config": {
|
||||
"basePath": 'https://docsify.js.org/',
|
||||
"loadSidebar": true,
|
||||
"loadNavbar": true,
|
||||
"coverpage": true,
|
||||
"name": "docsify"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!> The `basePath` just like webpack `publicPath`. We can use local or remote files.
|
||||
|
||||
We can preview in the local to see if it works.
|
||||
|
||||
```bash
|
||||
npm start
|
||||
|
||||
# open http://localhost:4000
|
||||
```
|
||||
|
||||
Publish it!
|
||||
|
||||
```bash
|
||||
now -p
|
||||
```
|
||||
|
||||
Now, You have a support for SSR the docs site.
|
||||
|
||||
## Custom template
|
||||
|
||||
You can provide a templte for entire page's HTML. such as
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>docsify</title>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/themes/vue.css" title="vue">
|
||||
</head>
|
||||
<body>
|
||||
<!--inject-app-->
|
||||
<!--inject-config-->
|
||||
</body>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-markdown.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-nginx.min.js"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
The template should contain these comments for rendered app content.
|
||||
- `<!--inject-app-->`
|
||||
- `<!--inject-config-->`
|
||||
|
||||
## Configuration
|
||||
|
||||
You can configure it in a special config file, or `package.json`.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
template: './ssr.html',
|
||||
config: {
|
||||
// docsify config
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Deploy for your VPS
|
||||
|
||||
You can run `docsify start` directly on your Node server, or write your own server app with `docsify-server-renderer`.
|
||||
|
||||
```js
|
||||
var Renderer = require('docsify-server-renderer')
|
||||
var readFileSync = require('fs').readFileSync
|
||||
|
||||
// init
|
||||
var renderer = new Renderer({
|
||||
template: readFileSync('./docs/index.template.html', 'utf-8').,
|
||||
config: {
|
||||
name: 'docsify',
|
||||
repo: 'qingwei-li/docsify'
|
||||
}
|
||||
})
|
||||
|
||||
renderer.renderToString(url)
|
||||
.then(html => {})
|
||||
.catch(err => {})
|
||||
```
|
||||
@@ -47,6 +47,8 @@ window.$docsify = {
|
||||
|
||||
## Example
|
||||
|
||||
#### footer
|
||||
|
||||
Add footer component in each pages.
|
||||
|
||||
```js
|
||||
@@ -68,3 +70,24 @@ window.$docsify = {
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Edit Button
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
plugins: [
|
||||
function(hook, vm) {
|
||||
hook.beforeEach(function (html) {
|
||||
var url = 'https://github.com/QingWei-Li/docsify/blob/master/docs' + vm.route.file
|
||||
var editHtml = '[📝 EDIT DOCUMENT](' + url + ')\n'
|
||||
|
||||
return editHtml
|
||||
+ html
|
||||
+ '\n----\n'
|
||||
+ 'Last modified {docsify-updated} '
|
||||
+ editHtml
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -12,12 +12,13 @@ docsify 是一个动态生成文档网站的工具。不同于 GitBook、Hexo
|
||||
|
||||
## 特性
|
||||
- 无需构建,写完文档直接发布
|
||||
- 容易使用并且轻量 (~16kB gzipped)
|
||||
- 容易使用并且轻量 (~18kB gzipped)
|
||||
- 智能的全文搜索
|
||||
- 提供多套主题
|
||||
- 丰富的 API
|
||||
- 支持 Emoji
|
||||
- 兼容 IE10+
|
||||
- 支持 SSR ([example](https://github.com/QingWei-Li/docsify-ssr-demo))
|
||||
|
||||
## 例子
|
||||
|
||||
|
||||
@@ -18,5 +18,6 @@
|
||||
- [兼容 Vue](zh-cn/vue.md)
|
||||
- [CDN](zh-cn/cdn.md)
|
||||
- [离线模式(PWA)](zh-cn/pwa.md)
|
||||
- [服务端渲染 (SSR)](zh-cn/ssr.md)
|
||||
|
||||
- [Changelog](zh-cn/changelog.md)
|
||||
|
||||
+2
-2
@@ -44,6 +44,6 @@ JS 的压缩文件是原有文件路径的基础上加 `.min`后缀
|
||||
|
||||
## 其他 CDN
|
||||
|
||||
- http://www.bootcdn.cn/docsify
|
||||
- http://www.jsdelivr.com/projects/docsify
|
||||
- http://www.bootcdn.cn/docsify (支持国内)
|
||||
- https://cdn.jsdelivr.net/npm/docsify/ (国内外都支持)
|
||||
- https://cdnjs.com/libraries/docsify
|
||||
|
||||
@@ -258,12 +258,13 @@ window.$docsify = {
|
||||
|
||||
- 类型:`Object`
|
||||
|
||||
定义路由别名,可以更自由的定义路由规则。
|
||||
定义路由别名,可以更自由的定义路由规则。 支持正则。
|
||||
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
alias: {
|
||||
'/foo/(+*)': '/bar/$1', // supports regexp
|
||||
'/zh-cn/changelog': '/changelog',
|
||||
'/changelog': 'https://raw.githubusercontent.com/QingWei-Li/docsify/master/CHANGELOG'
|
||||
}
|
||||
@@ -326,3 +327,46 @@ window.$docsify = {
|
||||
}
|
||||
```
|
||||
|
||||
## format-updated
|
||||
|
||||
我们可以显示文档更新日期通过 **{docsify-updated<span>}</span>** 变量. 并且格式化日期通过 `formatUpdated`.
|
||||
参考 https://github.com/lukeed/tinydate#patterns
|
||||
```js
|
||||
window.$docsify = {
|
||||
formatUpdated: '{MM}/{DD} {HH}:{mm}',
|
||||
|
||||
formatUpdated: function (time) {
|
||||
// ...
|
||||
|
||||
return time
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## external-link-target
|
||||
|
||||
Currently it defaults to _blank, would be nice if configurable:
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
externalLinkTarget: '_self' // default: '_blank'
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## noCompileLinks
|
||||
|
||||
- type: `Array`
|
||||
|
||||
|
||||
Sometimes we do not want docsify to handle our links. See [#203](https://github.com/QingWei-Li/docsify/issues/203)
|
||||
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
noCompileLinks: [
|
||||
'/foo',
|
||||
'/bar/.*'
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -24,3 +24,28 @@ docsify 扩展了一些 Markdown 语法,可以让文档更易读。
|
||||
|
||||
?> *TODO* 完善示例
|
||||
|
||||
|
||||
## Ignore to compile link
|
||||
|
||||
Some time we will put some other relative path to the link, you have to need to tell docsify you don't need to compile this link. For example
|
||||
|
||||
```md
|
||||
[link](/demo/)
|
||||
```
|
||||
|
||||
|
||||
It will be compiled to `<a href="/#/demo/">link</a>` and will be loaded `/demo/README.md`. Maybe you want to jump to `/demo/index.html`.
|
||||
|
||||
Now you can do that
|
||||
|
||||
```md
|
||||
[link](/demo/ ":ignore")
|
||||
```
|
||||
You will get `<a href="/demo/">link</a>`html. Do not worry, you can still set title for link.
|
||||
|
||||
```md
|
||||
[link](/demo/ ":ignore title")
|
||||
|
||||
<a href="/demo/" title="title">link</a>
|
||||
```
|
||||
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
<script src="//unpkg.com/prismjs/components/prism-php.js"></script>
|
||||
```
|
||||
|
||||
?> 其他的语言高亮插件可以查看[Prims 仓库](https://github.com/PrismJS/prism/tree/gh-pages/components)。
|
||||
?> 其他的语言高亮插件可以查看[Prims 仓库](https://github.com/PrismJS/prism/tree/gh-pages/components)。
|
||||
|
||||
@@ -35,7 +35,10 @@
|
||||
noData: {
|
||||
'/zh-cn/': '找不到结果',
|
||||
'/': 'No Results'
|
||||
}
|
||||
},
|
||||
|
||||
// 搜索标题的最大程级, 1 - 6
|
||||
depth: 2
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
# 服务端渲染(SSR)
|
||||
|
||||
先看例子 https://docsify.now.sh
|
||||
|
||||
项目地址在 https://github.com/QingWei-Li/docsify-ssr-demo
|
||||
|
||||

|
||||
|
||||
文档依旧是部署在 GitHub Pages 上,Node 服务部署在 now.sh 里,渲染的内容是从 GitHub Pages 上同步过来的。所以静态部署文档的服务器和服务端渲染的 Node 服务器是分开的,也就是说你还是可以用之前的方式更新文档,并不需要每次都部署。
|
||||
|
||||
|
||||
|
||||
## 快速开始
|
||||
|
||||
如果你熟悉 `now` 的使用,接下来的介绍就很简单了。先创建一个新项目,并安装 `now` 和 `docsify-cli`。
|
||||
|
||||
```bash
|
||||
mkdir my-ssr-demo && cd my-ssr-demo
|
||||
npm init -y
|
||||
npm i now docsify-cli -D
|
||||
```
|
||||
|
||||
配置 `package.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"start": "docsify start .",
|
||||
"deploy": "now -p"
|
||||
},
|
||||
"docsify": {
|
||||
"config": {
|
||||
"basePath": "https://docsify.js.org/",
|
||||
"loadSidebar": true,
|
||||
"loadNavbar": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果你还没有创建文档,可以参考[之前的文章](https://zhuanlan.zhihu.com/p/24540753)。其中 `basePath` 为文档所在的路径,可以填你的 docsify 文档网站。
|
||||
|
||||
配置可以单独写在配置文件内,然后通过 `--config config.js` 加载。
|
||||
|
||||
渲染的基础模版也可以自定义,配置在 `template` 属性上,例如
|
||||
|
||||
```js
|
||||
"docsify": {
|
||||
"template": "./ssr.html",
|
||||
"config": {
|
||||
"basePath": "https://docsify.js.org/",
|
||||
"loadSidebar": true,
|
||||
"loadNavbar": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
*ssr.html*
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>docsify</title>
|
||||
<link rel="icon" href="_media/favicon.ico">
|
||||
<meta name="keywords" content="doc,docs,documentation,gitbook,creator,generator,github,jekyll,github-pages">
|
||||
<meta name="description" content="A magical documentation generator.">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css" title="vue">
|
||||
</head>
|
||||
<body>
|
||||
<!--inject-app-->
|
||||
<!--inject-config-->
|
||||
</body>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
其中 `<!--inject-app-->` 和 `<!--inject-config-->` 为占位符,会自动将渲染后的 html 和配置内容注入到页面上。
|
||||
|
||||
现在,你可以运行 `npm start` 预览效果,如果没有问题就通过 `npm run deploy` 部署服务。
|
||||
|
||||
```bash
|
||||
npm start
|
||||
# open http://localhost:4000
|
||||
|
||||
npm run deploy
|
||||
# now ...
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 更多玩法
|
||||
|
||||
`docsify start` 其实是依赖了 [`docsify-server-renderer`](https://npmarket.surge.sh/?name=docsify-server-renderer) 模块,如果你感兴趣,你完全可以用它自己实现一个 server,可以加入缓存等功能。
|
||||
|
||||
```js
|
||||
var Renderer = require('docsify-server-renderer')
|
||||
var readFileSync = require('fs').readFileSync
|
||||
|
||||
// init
|
||||
var renderer = new Renderer({
|
||||
template: readFileSync('./docs/index.template.html', 'utf-8').,
|
||||
config: {
|
||||
name: 'docsify',
|
||||
repo: 'qingwei-li/docsify'
|
||||
}
|
||||
})
|
||||
|
||||
renderer.renderToString(url)
|
||||
.then(html => {})
|
||||
.catch(err => {})
|
||||
```
|
||||
|
||||
当然文档文件和 server 也是可以部署在一起的,`basePath` 不是一个 URL 的话就会当做文件路径处理,也就是从服务器上加载资源。
|
||||
@@ -46,6 +46,9 @@ window.$docsify = {
|
||||
|
||||
## 例子
|
||||
|
||||
|
||||
### footer
|
||||
|
||||
给每个页面的末尾加上 `footer`
|
||||
|
||||
```js
|
||||
@@ -66,4 +69,26 @@ window.$docsify = {
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Edit Button
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
plugins: [
|
||||
function(hook, vm) {
|
||||
hook.beforeEach(function (html) {
|
||||
var url = 'https://github.com/QingWei-Li/docsify/blob/master/docs' + vm.route.file
|
||||
var editHtml = '[📝 EDIT DOCUMENT](' + url + ')\n'
|
||||
|
||||
return editHtml
|
||||
+ html
|
||||
+ '\n----\n'
|
||||
+ 'Last modified {docsify-updated} '
|
||||
+ editHtml
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"lerna": "2.0.0-rc.5",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "0.0.0"
|
||||
}
|
||||
+855
-565
File diff suppressed because it is too large
Load Diff
Vendored
+2
-2
File diff suppressed because one or more lines are too long
@@ -1,4 +1,3 @@
|
||||
this.D = this.D || {};
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,4 +1,3 @@
|
||||
this.D = this.D || {};
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
this.D=this.D||{},function(){"use strict";function e(){for(var e=Docsify.dom.getNode("#main"),i=Docsify.dom.findAll(e,"script"),o=i.length;o--;){var t=i[o];if(t&&t.src){var n=document.createElement("script");Array.prototype.slice.call(t.attributes).forEach(function(e){n[e.name]=e.value}),t.parentNode.insertBefore(n,t),t.parentNode.removeChild(t)}}}var i=function(i){i.doneEach(e)};window.$docsify.plugins=[].concat(i,window.$docsify.plugins)}();
|
||||
!function(){"use strict";function e(){for(var e=Docsify.dom.getNode("#main"),o=Docsify.dom.findAll(e,"script"),n=o.length;n--;){var i=o[n];if(i&&i.src){var t=document.createElement("script");Array.prototype.slice.call(i.attributes).forEach(function(e){t[e.name]=e.value}),i.parentNode.insertBefore(t,i),i.parentNode.removeChild(i)}}}var o=function(o){o.doneEach(e)};window.$docsify.plugins=[].concat(o,window.$docsify.plugins)}();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
this.D = this.D || {};
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
@@ -498,6 +497,6 @@ var install = function (hook, vm) {
|
||||
});
|
||||
};
|
||||
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins);
|
||||
$docsify.plugins = [].concat(install, $docsify.plugins);
|
||||
|
||||
}());
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+12
-12
@@ -1,4 +1,3 @@
|
||||
this.D = this.D || {};
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
@@ -11,24 +10,25 @@ function appendScript () {
|
||||
}
|
||||
|
||||
function init (id) {
|
||||
if (!window.ga) {
|
||||
appendScript();
|
||||
window.ga = window.ga || function () {
|
||||
(window.ga.q = window.ga.q || []).push(arguments);
|
||||
};
|
||||
window.ga.l = Number(new Date());
|
||||
window.ga('create', id, 'auto');
|
||||
}
|
||||
appendScript();
|
||||
window.ga = window.ga || function () {
|
||||
(window.ga.q = window.ga.q || []).push(arguments);
|
||||
};
|
||||
window.ga.l = Number(new Date());
|
||||
window.ga('create', id, 'auto');
|
||||
}
|
||||
|
||||
function collect () {
|
||||
init(window.$docsify.ga);
|
||||
if (!window.ga) {
|
||||
init($docsify.ga);
|
||||
}
|
||||
|
||||
window.ga('set', 'page', location.hash);
|
||||
window.ga('send', 'pageview');
|
||||
}
|
||||
|
||||
var install = function (hook) {
|
||||
if (!window.$docsify.ga) {
|
||||
if (!$docsify.ga) {
|
||||
console.error('[Docsify] ga is required.');
|
||||
return
|
||||
}
|
||||
@@ -36,6 +36,6 @@ var install = function (hook) {
|
||||
hook.beforeEach(collect);
|
||||
};
|
||||
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins);
|
||||
$docsify.plugins = [].concat(install, $docsify.plugins);
|
||||
|
||||
}());
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
this.D=this.D||{},function(){"use strict";function n(){var n=document.createElement("script");n.async=!0,n.src="https://www.google-analytics.com/analytics.js",document.body.appendChild(n)}function o(o){window.ga||(n(),window.ga=window.ga||function(){(window.ga.q=window.ga.q||[]).push(arguments)},window.ga.l=Number(new Date),window.ga("create",o,"auto"))}function i(){o(window.$docsify.ga),window.ga("set","page",location.hash),window.ga("send","pageview")}var w=function(n){return window.$docsify.ga?void n.beforeEach(i):void console.error("[Docsify] ga is required.")};window.$docsify.plugins=[].concat(w,window.$docsify.plugins)}();
|
||||
!function(){"use strict";function n(){var n=document.createElement("script");n.async=!0,n.src="https://www.google-analytics.com/analytics.js",document.body.appendChild(n)}function o(o){n(),window.ga=window.ga||function(){(window.ga.q=window.ga.q||[]).push(arguments)},window.ga.l=Number(new Date),window.ga("create",o,"auto")}function i(){window.ga||o($docsify.ga),window.ga("set","page",location.hash),window.ga("send","pageview")}var a=function(n){if(!$docsify.ga)return void console.error("[Docsify] ga is required.");n.beforeEach(i)};$docsify.plugins=[].concat(a,$docsify.plugins)}();
|
||||
|
||||
+31
-32
@@ -1,4 +1,3 @@
|
||||
this.D = this.D || {};
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
@@ -18,18 +17,18 @@ function escapeHtml (string) {
|
||||
return String(string).replace(/[&<>"'\/]/g, function (s) { return entityMap[s]; })
|
||||
}
|
||||
|
||||
function getAllPaths () {
|
||||
function getAllPaths (router) {
|
||||
var paths = [];
|
||||
|
||||
helper.dom.findAll('a:not([data-nosearch])')
|
||||
.map(function (node) {
|
||||
var href = node.href;
|
||||
var originHref = node.getAttribute('href');
|
||||
var path = helper.route.parse(href).path;
|
||||
var path = router.parse(href).path;
|
||||
|
||||
if (path &&
|
||||
paths.indexOf(path) === -1 &&
|
||||
!helper.route.isAbsolutePath(originHref)) {
|
||||
!Docsify.util.isAbsolutePath(originHref)) {
|
||||
paths.push(path);
|
||||
}
|
||||
});
|
||||
@@ -42,18 +41,17 @@ function saveData (maxAge) {
|
||||
localStorage.setItem('docsify.search.index', JSON.stringify(INDEXS));
|
||||
}
|
||||
|
||||
function genIndex (path, content) {
|
||||
function genIndex (path, content, router, depth) {
|
||||
if ( content === void 0 ) content = '';
|
||||
|
||||
var tokens = window.marked.lexer(content);
|
||||
var slugify = window.Docsify.slugify;
|
||||
var toURL = Docsify.route.toURL;
|
||||
var index = {};
|
||||
var slug;
|
||||
|
||||
tokens.forEach(function (token) {
|
||||
if (token.type === 'heading' && token.depth <= 2) {
|
||||
slug = toURL(path, { id: slugify(token.text) });
|
||||
if (token.type === 'heading' && token.depth <= depth) {
|
||||
slug = router.toURL(path, { id: slugify(token.text) });
|
||||
index[slug] = { slug: slug, title: token.text, body: '' };
|
||||
} else {
|
||||
if (!slug) { return }
|
||||
@@ -153,7 +151,7 @@ function init$1 (config, vm) {
|
||||
return
|
||||
}
|
||||
|
||||
var paths = isAuto ? getAllPaths() : config.paths;
|
||||
var paths = isAuto ? getAllPaths(vm.router) : config.paths;
|
||||
var len = paths.length;
|
||||
var count = 0;
|
||||
|
||||
@@ -161,21 +159,20 @@ function init$1 (config, vm) {
|
||||
if (INDEXS[path]) { return count++ }
|
||||
|
||||
helper
|
||||
.get(vm.$getFile(path))
|
||||
.get(vm.router.getFile(path))
|
||||
.then(function (result) {
|
||||
INDEXS[path] = genIndex(path, result);
|
||||
INDEXS[path] = genIndex(path, result, vm.router, config.depth);
|
||||
len === ++count && saveData(config.maxAge);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var dom;
|
||||
var NO_DATA_TEXT = '';
|
||||
|
||||
function style () {
|
||||
var code = "\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 7px;\n line-height: 22px;\n font-size: 14px;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}";
|
||||
var style = dom.create('style', code);
|
||||
dom.appendTo(dom.head, style);
|
||||
var style = Docsify.dom.create('style', code);
|
||||
Docsify.dom.appendTo(Docsify.dom.head, style);
|
||||
}
|
||||
|
||||
function tpl (opts, defaultValue) {
|
||||
@@ -185,16 +182,16 @@ function tpl (opts, defaultValue) {
|
||||
"<input type=\"search\" value=\"" + defaultValue + "\" />" +
|
||||
'<div class="results-panel"></div>' +
|
||||
'</div>';
|
||||
var el = dom.create('div', html);
|
||||
var aside = dom.find('aside');
|
||||
var el = Docsify.dom.create('div', html);
|
||||
var aside = Docsify.dom.find('aside');
|
||||
|
||||
dom.toggleClass(el, 'search');
|
||||
dom.before(aside, el);
|
||||
Docsify.dom.toggleClass(el, 'search');
|
||||
Docsify.dom.before(aside, el);
|
||||
}
|
||||
|
||||
function doSearch (value) {
|
||||
var $search = dom.find('div.search');
|
||||
var $panel = dom.find($search, '.results-panel');
|
||||
var $search = Docsify.dom.find('div.search');
|
||||
var $panel = Docsify.dom.find($search, '.results-panel');
|
||||
|
||||
if (!value) {
|
||||
$panel.classList.remove('show');
|
||||
@@ -213,26 +210,27 @@ function doSearch (value) {
|
||||
}
|
||||
|
||||
function bindEvents () {
|
||||
var $search = dom.find('div.search');
|
||||
var $input = dom.find($search, 'input');
|
||||
var $search = Docsify.dom.find('div.search');
|
||||
var $input = Docsify.dom.find($search, 'input');
|
||||
|
||||
var timeId;
|
||||
// Prevent to Fold sidebar
|
||||
dom.on($search, 'click',
|
||||
Docsify.dom.on($search, 'click',
|
||||
function (e) { return e.target.tagName !== 'A' && e.stopPropagation(); });
|
||||
dom.on($input, 'input', function (e) {
|
||||
Docsify.dom.on($input, 'input', function (e) {
|
||||
clearTimeout(timeId);
|
||||
timeId = setTimeout(function (_) { return doSearch(e.target.value.trim()); }, 100);
|
||||
});
|
||||
}
|
||||
|
||||
function updatePlaceholder (text, path) {
|
||||
var $input = dom.getNode('.search input[type="search"]');
|
||||
var $input = Docsify.dom.getNode('.search input[type="search"]');
|
||||
|
||||
if (!$input) { return }
|
||||
if (typeof text === 'string') {
|
||||
$input.placeholder = text;
|
||||
} else {
|
||||
var match = Object.keys(text).find(function (key) { return path.indexOf(key) > -1; });
|
||||
var match = Object.keys(text).filter(function (key) { return path.indexOf(key) > -1; })[0];
|
||||
$input.placeholder = text[match];
|
||||
}
|
||||
}
|
||||
@@ -241,14 +239,13 @@ function updateNoData (text, path) {
|
||||
if (typeof text === 'string') {
|
||||
NO_DATA_TEXT = text;
|
||||
} else {
|
||||
var match = Object.keys(text).find(function (key) { return path.indexOf(key) > -1; });
|
||||
var match = Object.keys(text).filter(function (key) { return path.indexOf(key) > -1; })[0];
|
||||
NO_DATA_TEXT = text[match];
|
||||
}
|
||||
}
|
||||
|
||||
function init$$1 (opts) {
|
||||
dom = Docsify.dom;
|
||||
var keywords = Docsify.route.parse().query.s;
|
||||
function init$$1 (opts, vm) {
|
||||
var keywords = vm.router.parse().query.s;
|
||||
|
||||
style();
|
||||
tpl(opts, keywords);
|
||||
@@ -265,6 +262,7 @@ var CONFIG = {
|
||||
placeholder: 'Type to search',
|
||||
noData: 'No Results!',
|
||||
paths: 'auto',
|
||||
depth: 2,
|
||||
maxAge: 86400000 // 1 day
|
||||
};
|
||||
|
||||
@@ -279,12 +277,13 @@ var install = function (hook, vm) {
|
||||
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;
|
||||
}
|
||||
|
||||
var isAuto = CONFIG.paths === 'auto';
|
||||
|
||||
hook.mounted(function (_) {
|
||||
init$$1(CONFIG);
|
||||
init$$1(CONFIG, vm);
|
||||
!isAuto && init$1(CONFIG, vm);
|
||||
});
|
||||
hook.doneEach(function (_) {
|
||||
@@ -293,6 +292,6 @@ var install = function (hook, vm) {
|
||||
});
|
||||
};
|
||||
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins);
|
||||
$docsify.plugins = [].concat(install, $docsify.plugins);
|
||||
|
||||
}());
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
this.D=this.D||{},function(){"use strict";function e(e){var n={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};return String(e).replace(/[&<>"'\/]/g,function(e){return n[e]})}function n(){var e=[];return h.dom.findAll("a:not([data-nosearch])").map(function(n){var t=n.href,a=n.getAttribute("href"),o=h.route.parse(t).path;o&&e.indexOf(o)===-1&&!h.route.isAbsolutePath(a)&&e.push(o)}),e}function t(e){localStorage.setItem("docsify.search.expires",Date.now()+e),localStorage.setItem("docsify.search.index",JSON.stringify(v))}function a(e,n){void 0===n&&(n="");var t,a=window.marked.lexer(n),o=window.Docsify.slugify,r=Docsify.route.toURL,i={};return a.forEach(function(n){if("heading"===n.type&&n.depth<=2)t=r(e,{id:o(n.text)}),i[t]={slug:t,title:n.text,body:""};else{if(!t)return;i[t]?i[t].body?i[t].body+="\n"+(n.text||""):i[t].body=n.text:i[t]={slug:t,title:"",body:""}}}),o.clear(),i}function o(n){var t=[],a=[];Object.keys(v).forEach(function(e){a=a.concat(Object.keys(v[e]).map(function(n){return v[e][n]}))}),n=[].concat(n,n.trim().split(/[\s\-\,\\\/]+/));for(var o=function(o){var r=a[o],i=!1,s="",c=r.title&&r.title.trim(),l=r.body&&r.body.trim(),u=r.slug||"";if(c&&l&&(n.forEach(function(n,t){var a=new RegExp(n,"gi"),o=-1,r=-1;if(o=c&&c.search(a),r=l&&l.search(a),o<0&&r<0)i=!1;else{i=!0,r<0&&(r=0);var u=0,p=0;u=r<11?0:r-10,p=0===u?70:r+n.length+60,p>l.length&&(p=l.length);var f="..."+e(l).substring(u,p).replace(a,'<em class="search-keyword">'+n+"</em>")+"...";s+=f}}),i)){var p={title:e(c),content:s,url:u};t.push(p)}},r=0;r<a.length;r++)o(r);return t}function r(e,o){h=Docsify;var r="auto"===e.paths,i=localStorage.getItem("docsify.search.expires")<Date.now();if(v=JSON.parse(localStorage.getItem("docsify.search.index")),i)v={};else if(!r)return;var s=r?n():e.paths,c=s.length,l=0;s.forEach(function(n){return v[n]?l++:void h.get(o.$getFile(n)).then(function(o){v[n]=a(n,o),c===++l&&t(e.maxAge)})})}function i(){var e="\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 7px;\n line-height: 22px;\n font-size: 14px;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}",n=g.create("style",e);g.appendTo(g.head,n)}function s(e,n){void 0===n&&(n="");var t='<input type="search" value="'+n+'" /><div class="results-panel"></div></div>',a=g.create("div",t),o=g.find("aside");g.toggleClass(a,"search"),g.before(o,a)}function c(e){var n=g.find("div.search"),t=g.find(n,".results-panel");if(!e)return t.classList.remove("show"),void(t.innerHTML="");var a=o(e),r="";a.forEach(function(e){r+='<div class="matching-post">\n<h2><a href="'+e.url+'">'+e.title+"</a></h2>\n<p>"+e.content+"</p>\n</div>"}),t.classList.add("show"),t.innerHTML=r||'<p class="empty">'+y+"</p>"}function l(){var e,n=g.find("div.search"),t=g.find(n,"input");g.on(n,"click",function(e){return"A"!==e.target.tagName&&e.stopPropagation()}),g.on(t,"input",function(n){clearTimeout(e),e=setTimeout(function(e){return c(n.target.value.trim())},100)})}function u(e,n){var t=g.getNode('.search input[type="search"]');if("string"==typeof e)t.placeholder=e;else{var a=Object.keys(e).find(function(e){return n.indexOf(e)>-1});t.placeholder=e[a]}}function p(e,n){if("string"==typeof e)y=e;else{var t=Object.keys(e).find(function(e){return n.indexOf(e)>-1});y=e[t]}}function f(e){g=Docsify.dom;var n=Docsify.route.parse().query.s;i(),s(e,n),l(),n&&setTimeout(function(e){return c(n)},500)}function d(e,n){u(e.placeholder,n.route.path),p(e.noData,n.route.path)}var h,g,v={},y="",m={placeholder:"Type to search",noData:"No Results!",paths:"auto",maxAge:864e5},x=function(e,n){var t=Docsify.util,a=n.config.search||m;Array.isArray(a)?m.paths=a:"object"==typeof a&&(m.paths=Array.isArray(a.paths)?a.paths:"auto",m.maxAge=t.isPrimitive(a.maxAge)?a.maxAge:m.maxAge,m.placeholder=a.placeholder||m.placeholder,m.noData=a.noData||m.noData);var o="auto"===m.paths;e.mounted(function(e){f(m),!o&&r(m,n)}),e.doneEach(function(e){d(m,n),o&&r(m,n)})};window.$docsify.plugins=[].concat(x,window.$docsify.plugins)}();
|
||||
!function(){"use strict";function e(e){var n={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};return String(e).replace(/[&<>"'\/]/g,function(e){return n[e]})}function n(e){var n=[];return h.dom.findAll("a:not([data-nosearch])").map(function(t){var o=t.href,i=t.getAttribute("href"),r=e.parse(o).path;r&&-1===n.indexOf(r)&&!Docsify.util.isAbsolutePath(i)&&n.push(r)}),n}function t(e){localStorage.setItem("docsify.search.expires",Date.now()+e),localStorage.setItem("docsify.search.index",JSON.stringify(y))}function o(e,n,t,o){void 0===n&&(n="");var i,r=window.marked.lexer(n),a=window.Docsify.slugify,s={};return r.forEach(function(n){if("heading"===n.type&&n.depth<=o)i=t.toURL(e,{id:a(n.text)}),s[i]={slug:i,title:n.text,body:""};else{if(!i)return;s[i]?s[i].body?s[i].body+="\n"+(n.text||""):s[i].body=n.text:s[i]={slug:i,title:"",body:""}}}),a.clear(),s}function i(n){var t=[],o=[];Object.keys(y).forEach(function(e){o=o.concat(Object.keys(y[e]).map(function(n){return y[e][n]}))}),n=[].concat(n,n.trim().split(/[\s\-\,\\\/]+/));for(var i=0;i<o.length;i++)!function(i){var r=o[i],a=!1,s="",c=r.title&&r.title.trim(),f=r.body&&r.body.trim(),l=r.slug||"";if(c&&f&&(n.forEach(function(n,t){var o=new RegExp(n,"gi"),i=-1,r=-1;if(i=c&&c.search(o),r=f&&f.search(o),i<0&&r<0)a=!1;else{a=!0,r<0&&(r=0);var l=0,d=0;l=r<11?0:r-10,d=0===l?70:r+n.length+60,d>f.length&&(d=f.length);var p="..."+e(f).substring(l,d).replace(o,'<em class="search-keyword">'+n+"</em>")+"...";s+=p}}),a)){var d={title:e(c),content:s,url:l};t.push(d)}}(i);return t}function r(e,i){h=Docsify;var r="auto"===e.paths,a=localStorage.getItem("docsify.search.expires")<Date.now();if(y=JSON.parse(localStorage.getItem("docsify.search.index")),a)y={};else if(!r)return;var s=r?n(i.router):e.paths,c=s.length,f=0;s.forEach(function(n){if(y[n])return f++;h.get(i.router.getFile(n)).then(function(r){y[n]=o(n,r,i.router,e.depth),c===++f&&t(e.maxAge)})})}function a(){var e=Docsify.dom.create("style","\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 7px;\n line-height: 22px;\n font-size: 14px;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}");Docsify.dom.appendTo(Docsify.dom.head,e)}function s(e,n){void 0===n&&(n="");var t='<input type="search" value="'+n+'" /><div class="results-panel"></div></div>',o=Docsify.dom.create("div",t),i=Docsify.dom.find("aside");Docsify.dom.toggleClass(o,"search"),Docsify.dom.before(i,o)}function c(e){var n=Docsify.dom.find("div.search"),t=Docsify.dom.find(n,".results-panel");if(!e)return t.classList.remove("show"),void(t.innerHTML="");var o=i(e),r="";o.forEach(function(e){r+='<div class="matching-post">\n<h2><a href="'+e.url+'">'+e.title+"</a></h2>\n<p>"+e.content+"</p>\n</div>"}),t.classList.add("show"),t.innerHTML=r||'<p class="empty">'+m+"</p>"}function f(){var e,n=Docsify.dom.find("div.search"),t=Docsify.dom.find(n,"input");Docsify.dom.on(n,"click",function(e){return"A"!==e.target.tagName&&e.stopPropagation()}),Docsify.dom.on(t,"input",function(n){clearTimeout(e),e=setTimeout(function(e){return c(n.target.value.trim())},100)})}function l(e,n){var t=Docsify.dom.getNode('.search input[type="search"]');if(t)if("string"==typeof e)t.placeholder=e;else{var o=Object.keys(e).filter(function(e){return n.indexOf(e)>-1})[0];t.placeholder=e[o]}}function d(e,n){if("string"==typeof e)m=e;else{var t=Object.keys(e).filter(function(e){return n.indexOf(e)>-1})[0];m=e[t]}}function p(e,n){var t=n.router.parse().query.s;a(),s(e,t),f(),t&&setTimeout(function(e){return c(t)},500)}function u(e,n){l(e.placeholder,n.route.path),d(e.noData,n.route.path)}var h,y={},m="",g={placeholder:"Type to search",noData:"No Results!",paths:"auto",depth:2,maxAge:864e5},v=function(e,n){var t=Docsify.util,o=n.config.search||g;Array.isArray(o)?g.paths=o:"object"==typeof o&&(g.paths=Array.isArray(o.paths)?o.paths:"auto",g.maxAge=t.isPrimitive(o.maxAge)?o.maxAge:g.maxAge,g.placeholder=o.placeholder||g.placeholder,g.noData=o.noData||g.noData,g.depth=o.depth||g.depth);var i="auto"===g.paths;e.mounted(function(e){p(g,n),!i&&r(g,n)}),e.doneEach(function(e){u(g,n),i&&r(g,n)})};$docsify.plugins=[].concat(v,$docsify.plugins)}();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
this.D = this.D || {};
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
this.D=this.D||{},function(){"use strict";function t(t,e){return e={exports:{}},t(e,e.exports),e.exports}function e(t){var e,n=Docsify.dom;n.appendTo(n.head,n.create("style",i)),t.doneEach(function(t){var i=n.findAll("img:not(.emoji)");Array.isArray(e)&&e.length&&(e.forEach(function(t){return t()}),e=[]),e=i.map(o)})}var n="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},o=t(function(t,e){!function(e,n){t.exports=n()}(n,function(){function t(){g===-1&&(g=window.pageYOffset);var t=Math.abs(g-window.pageYOffset);t>=40&&a()}function e(t){27===t.keyCode&&a()}function n(t){var e=t.touches[0];null!==e&&(y=e.pageY,t.target.addEventListener("touchmove",o))}function o(t){var e=t.touches[0];null!==e&&Math.abs(e.pageY-y)>10&&(a(),t.target.removeEventListener("touchmove",o))}function i(){a()}function r(){document.addEventListener("scroll",t),document.addEventListener("keyup",e),document.addEventListener("touchstart",n),document.addEventListener("click",i,!0)}function s(){document.removeEventListener("scroll",t),document.removeEventListener("keyup",e),document.removeEventListener("touchstart",n),document.removeEventListener("click",i,!0)}function a(t){null!==h&&(t?h.dispose():h.close(),s(),h=null)}function c(t){if(!document.body.classList.contains("zoom-overlay-open"))return t.metaKey||t.ctrlKey?void window.open(t.target.getAttribute("data-original")||t.target.src,"_blank"):void(t.target.width>=m()-v||(a(!0),h=new p(t.target,v),h.zoom(),r()))}var m=function(){return document.documentElement.clientWidth},u=function(){return document.documentElement.clientHeight},d=function(t){var e=t.getBoundingClientRect(),n=document.documentElement,o=window;return{top:e.top+o.pageYOffset-n.clientTop,left:e.left+o.pageXOffset-n.clientLeft}},l=function(t,e,n){var o=function(t){t.target.removeEventListener(e,o),n()};t.addEventListener(e,o)},f=function(t,e){this.w=t,this.h=e},p=function(t,e){this.img=t,this.preservedTransform=t.style.transform,this.wrap=null,this.overlay=null,this.offset=e};p.prototype.forceRepaint=function(){this.img.offsetWidth},p.prototype.zoom=function(){var t=new f(this.img.naturalWidth,this.img.naturalHeight);this.wrap=document.createElement("div"),this.wrap.classList.add("zoom-img-wrap"),this.img.parentNode.insertBefore(this.wrap,this.img),this.wrap.appendChild(this.img),this.img.classList.add("zoom-img"),this.img.setAttribute("data-action","zoom-out"),this.overlay=document.createElement("div"),this.overlay.classList.add("zoom-overlay"),document.body.appendChild(this.overlay),this.forceRepaint();var e=this.calculateScale(t);this.forceRepaint(),this.animate(e),document.body.classList.add("zoom-overlay-open")},p.prototype.calculateScale=function(t){var e=t.w/this.img.width,n=m()-this.offset,o=u()-this.offset,i=t.w/t.h,r=n/o;return t.w<n&&t.h<o?e:i<r?o/t.h*e:n/t.w*e},p.prototype.animate=function(t){var e=d(this.img),n=window.pageYOffset,o=m()/2,i=n+u()/2,r=e.left+this.img.width/2,s=e.top+this.img.height/2,a=o-r,c=i-s,l=0,f="scale("+t+")",p="translate3d("+a+"px, "+c+"px, "+l+"px)";this.img.style.transform=f,this.wrap.style.transform=p},p.prototype.dispose=function(){null!==this.wrap&&null!==this.wrap.parentNode&&(this.img.classList.remove("zoom-img"),this.img.setAttribute("data-action","zoom"),this.wrap.parentNode.insertBefore(this.img,this.wrap),this.wrap.parentNode.removeChild(this.wrap),document.body.removeChild(this.overlay),document.body.classList.remove("zoom-overlay-transitioning"))},p.prototype.close=function(){var t=this;document.body.classList.add("zoom-overlay-transitioning"),this.img.style.transform=this.preservedTransform,0===this.img.style.length&&this.img.removeAttribute("style"),this.wrap.style.transform="none",l(this.img,"transitionend",function(){t.dispose(),document.body.classList.remove("zoom-overlay-open")})};var h=null,v=80,g=-1,y=-1,w=function(t){return t.setAttribute("data-action","zoom"),t.addEventListener("click",c),function(){return t.removeEventListener("click",c)}};return w})}),i='img[data-action="zoom"] {\n cursor: pointer;\n cursor: -webkit-zoom-in;\n cursor: zoom-in;\n}\n.zoom-img,\n.zoom-img-wrap {\n position: relative;\n z-index: 666;\n transition: -webkit-transform 300ms cubic-bezier(.2,0,.2,1);\n transition: transform 300ms cubic-bezier(.2,0,.2,1);\n transition: transform 300ms cubic-bezier(.2,0,.2,1), -webkit-transform 300ms cubic-bezier(.2,0,.2,1);\n}\n.zoom-overlay {\n z-index: 420;\n background: #fff;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n pointer-events: none;\n opacity: 0;\n transition: opacity 300ms;\n}\n.zoom-overlay-open .zoom-overlay {\n opacity: 1;\n}\n.zoom-overlay-open {\n cursor: pointer;\n cursor: -webkit-zoom-out;\n cursor: zoom-out;\n}\n.zoom-overlay-transitioning {\n cursor: default;\n}\n.zoom-overlay-open.zoom-overlay-transitioning .zoom-overlay{\n opacity: 0;\n}\n';$docsify.plugins=[].concat(e,$docsify.plugins)}();
|
||||
!function(){"use strict";function t(t){var o,i=Docsify.dom;i.appendTo(i.head,i.create("style",n)),t.doneEach(function(t){var n=i.findAll("img:not(.emoji)");Array.isArray(o)&&o.length&&(o.forEach(function(t){return t()}),o=[]),o=n.map(e)})}var e=("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self,function(t,e){return e={exports:{}},t(e,e.exports),e.exports}(function(t,e){!function(e,n){t.exports=function(){function t(){-1===g&&(g=window.pageYOffset),Math.abs(g-window.pageYOffset)>=40&&a()}function e(t){27===t.keyCode&&a()}function n(t){var e=t.touches[0];null!==e&&(y=e.pageY,t.target.addEventListener("touchmove",o))}function o(t){var e=t.touches[0];null!==e&&Math.abs(e.pageY-y)>10&&(a(),t.target.removeEventListener("touchmove",o))}function i(){a()}function r(){document.addEventListener("scroll",t),document.addEventListener("keyup",e),document.addEventListener("touchstart",n),document.addEventListener("click",i,!0)}function s(){document.removeEventListener("scroll",t),document.removeEventListener("keyup",e),document.removeEventListener("touchstart",n),document.removeEventListener("click",i,!0)}function a(t){null!==h&&(t?h.dispose():h.close(),s(),h=null)}function c(t){if(!document.body.classList.contains("zoom-overlay-open"))return t.metaKey||t.ctrlKey?void window.open(t.target.getAttribute("data-original")||t.target.src,"_blank"):void(t.target.width>=m()-v||(a(!0),h=new p(t.target,v),h.zoom(),r()))}var m=function(){return document.documentElement.clientWidth},u=function(){return document.documentElement.clientHeight},d=function(t){var e=t.getBoundingClientRect(),n=document.documentElement,o=window;return{top:e.top+o.pageYOffset-n.clientTop,left:e.left+o.pageXOffset-n.clientLeft}},l=function(t,e,n){var o=function(t){t.target.removeEventListener(e,o),n()};t.addEventListener(e,o)},f=function(t,e){this.w=t,this.h=e},p=function(t,e){this.img=t,this.preservedTransform=t.style.transform,this.wrap=null,this.overlay=null,this.offset=e};p.prototype.forceRepaint=function(){this.img.offsetWidth},p.prototype.zoom=function(){var t=new f(this.img.naturalWidth,this.img.naturalHeight);this.wrap=document.createElement("div"),this.wrap.classList.add("zoom-img-wrap"),this.img.parentNode.insertBefore(this.wrap,this.img),this.wrap.appendChild(this.img),this.img.classList.add("zoom-img"),this.img.setAttribute("data-action","zoom-out"),this.overlay=document.createElement("div"),this.overlay.classList.add("zoom-overlay"),document.body.appendChild(this.overlay),this.forceRepaint();var e=this.calculateScale(t);this.forceRepaint(),this.animate(e),document.body.classList.add("zoom-overlay-open")},p.prototype.calculateScale=function(t){var e=t.w/this.img.width,n=m()-this.offset,o=u()-this.offset,i=t.w/t.h,r=n/o;return t.w<n&&t.h<o?e:i<r?o/t.h*e:n/t.w*e},p.prototype.animate=function(t){var e=d(this.img),n=window.pageYOffset,o=m()/2,i=n+u()/2,r=e.left+this.img.width/2,s=e.top+this.img.height/2,a=o-r,c=i-s,l="scale("+t+")",f="translate3d("+a+"px, "+c+"px, 0px)";this.img.style.transform=l,this.wrap.style.transform=f},p.prototype.dispose=function(){null!==this.wrap&&null!==this.wrap.parentNode&&(this.img.classList.remove("zoom-img"),this.img.setAttribute("data-action","zoom"),this.wrap.parentNode.insertBefore(this.img,this.wrap),this.wrap.parentNode.removeChild(this.wrap),document.body.removeChild(this.overlay),document.body.classList.remove("zoom-overlay-transitioning"))},p.prototype.close=function(){var t=this;document.body.classList.add("zoom-overlay-transitioning"),this.img.style.transform=this.preservedTransform,0===this.img.style.length&&this.img.removeAttribute("style"),this.wrap.style.transform="none",l(this.img,"transitionend",function(){t.dispose(),document.body.classList.remove("zoom-overlay-open")})};var h=null,v=80,g=-1,y=-1;return function(t){return t.setAttribute("data-action","zoom"),t.addEventListener("click",c),function(){return t.removeEventListener("click",c)}}}()}()})),n='img[data-action="zoom"] {\n cursor: pointer;\n cursor: -webkit-zoom-in;\n cursor: zoom-in;\n}\n.zoom-img,\n.zoom-img-wrap {\n position: relative;\n z-index: 666;\n transition: -webkit-transform 300ms cubic-bezier(.2,0,.2,1);\n transition: transform 300ms cubic-bezier(.2,0,.2,1);\n transition: transform 300ms cubic-bezier(.2,0,.2,1), -webkit-transform 300ms cubic-bezier(.2,0,.2,1);\n}\n.zoom-overlay {\n z-index: 420;\n background: #fff;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n pointer-events: none;\n opacity: 0;\n transition: opacity 300ms;\n}\n.zoom-overlay-open .zoom-overlay {\n opacity: 1;\n}\n.zoom-overlay-open {\n cursor: pointer;\n cursor: -webkit-zoom-out;\n cursor: zoom-out;\n}\n.zoom-overlay-transitioning {\n cursor: default;\n}\n.zoom-overlay-open.zoom-overlay-transitioning .zoom-overlay{\n opacity: 0;\n}\n';$docsify.plugins=[].concat(t,$docsify.plugins)}();
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Generated
+4959
File diff suppressed because it is too large
Load Diff
+14
-5
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docsify",
|
||||
"version": "3.6.6",
|
||||
"version": "4.2.3",
|
||||
"description": "A magical documentation generator.",
|
||||
"author": {
|
||||
"name": "qingwei-li",
|
||||
@@ -20,28 +20,37 @@
|
||||
"themes"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "rm -rf lib themes && node build/build.js && mkdir lib/themes && mkdir themes && node build/build-css.js",
|
||||
"dev:build": "rm -rf lib themes && mkdir themes && node build/build.js --dev && node build/build-css.js --dev",
|
||||
"dev": "node app.js & nodemon -w src -e js,css --exec 'npm run dev:build'",
|
||||
"test": "eslint src"
|
||||
"bootstrap": "npm i && lerna bootstrap",
|
||||
"build": "rm -rf lib themes && node build/build && mkdir lib/themes && mkdir themes && node build/build-css && npm run build:ssr && node build/build-cover",
|
||||
"dev:build": "rm -rf lib themes && mkdir themes && node build/build --dev && node build/build-css --dev",
|
||||
"dev": "node app & nodemon -w src -e js,css --exec 'npm run dev:build'",
|
||||
"build:ssr": "node build/build-ssr",
|
||||
"test": "eslint {src,packages} --fix",
|
||||
"pub:next": "RELEASE_TAG=next sh build/release.sh",
|
||||
"pub": "sh build/release.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"marked": "^0.3.6",
|
||||
"prismjs": "^1.6.0",
|
||||
"tinydate": "^1.0.0",
|
||||
"zoom-image": "^0.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"conventional-changelog-cli": "^1.3.2",
|
||||
"cssnano": "^3.10.0",
|
||||
"eslint": "^3.18.0",
|
||||
"eslint-config-vue": "^2.0.2",
|
||||
"eslint-plugin-vue": "^2.0.1",
|
||||
"lerna": "^2.0.0-rc.5",
|
||||
"nodemon": "^1.11.0",
|
||||
"postcss": "^5.2.16",
|
||||
"postcss-salad": "^1.0.8",
|
||||
"rollup": "^0.41.6",
|
||||
"rollup-plugin-async": "^1.2.0",
|
||||
"rollup-plugin-buble": "^0.15.0",
|
||||
"rollup-plugin-commonjs": "^8.0.2",
|
||||
"rollup-plugin-node-resolve": "^2.0.0",
|
||||
"rollup-plugin-replace": "^1.1.1",
|
||||
"rollup-plugin-string": "^2.0.2",
|
||||
"rollup-plugin-uglify": "^1.0.1",
|
||||
"serve-static": "^1.12.1"
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
build.js
|
||||
node_modules
|
||||
*.log
|
||||
.git
|
||||
@@ -0,0 +1,46 @@
|
||||
# docsify-server-renderer
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
yarn add docsify-server-render
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
var Renderer = require('docsify-server-renderer')
|
||||
var readFileSync = require('fs').readFileSync
|
||||
|
||||
// init
|
||||
var renderer = new Renderer({
|
||||
template: readFileSync('./docs/index.template.html', 'utf-8').,
|
||||
config: {
|
||||
name: 'docsify',
|
||||
repo: 'qingwei-li/docsify'
|
||||
}
|
||||
})
|
||||
|
||||
renderer.renderToString(url)
|
||||
.then(html => {})
|
||||
.catch(err => {})
|
||||
```
|
||||
|
||||
*index.template.html*
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>docsify</title>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/themes/buble.css" title="buble" disabled>
|
||||
</head>
|
||||
<body>
|
||||
<!--inject-app-->
|
||||
<!--inject-config-->
|
||||
<script src="//unpkg.com/docsify/lib/docsify.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
@@ -0,0 +1,143 @@
|
||||
import * as tpl from '../../src/core/render/tpl'
|
||||
import fetch from 'node-fetch'
|
||||
import { AbstractHistory } from '../../src/core/router/history/abstract'
|
||||
import { Compiler } from '../../src/core/render/compiler'
|
||||
import { isAbsolutePath } from '../../src/core/router/util'
|
||||
import { readFileSync } from 'fs'
|
||||
import { resolve, basename } from 'path'
|
||||
import resolvePathname from 'resolve-pathname'
|
||||
import debug from 'debug'
|
||||
|
||||
function cwd (...args) {
|
||||
return resolve(process.cwd(), ...args)
|
||||
}
|
||||
|
||||
function mainTpl (config) {
|
||||
let html = `<nav class="app-nav${config.repo ? '' : ' no-badge'}"><!--navbar--></nav>`
|
||||
|
||||
if (config.repo) {
|
||||
html += tpl.corner(config.repo)
|
||||
}
|
||||
if (config.coverpage) {
|
||||
html += tpl.cover()
|
||||
}
|
||||
|
||||
html += tpl.main(config)
|
||||
|
||||
return html
|
||||
}
|
||||
|
||||
export default class Renderer {
|
||||
constructor ({
|
||||
template,
|
||||
config,
|
||||
cache
|
||||
}) {
|
||||
this.html = template
|
||||
this.config = config = Object.assign({}, config, {
|
||||
routerMode: 'history'
|
||||
})
|
||||
this.cache = cache
|
||||
|
||||
this.router = new AbstractHistory(config)
|
||||
this.compiler = new Compiler(config, this.router)
|
||||
|
||||
this.router.getCurrentPath = () => this.url
|
||||
this._renderHtml('inject-config', `<script>window.$docsify = ${JSON.stringify(config)}</script>`)
|
||||
this._renderHtml('inject-app', mainTpl(config))
|
||||
|
||||
this.template = this.html
|
||||
}
|
||||
|
||||
_getPath (url) {
|
||||
const file = this.router.getFile(url)
|
||||
|
||||
return isAbsolutePath(file)
|
||||
? file
|
||||
: cwd(`./${file}`)
|
||||
}
|
||||
|
||||
async renderToString (url) {
|
||||
this.url = url = this.router.parse(url).path
|
||||
const { loadSidebar, loadNavbar } = this.config
|
||||
|
||||
const mainFile = this._getPath(url)
|
||||
this._renderHtml('main', await this._render(mainFile))
|
||||
|
||||
if (loadSidebar) {
|
||||
const name = loadSidebar === true ? '_sidebar.md' : loadSidebar
|
||||
const sidebarFile = this._getPath(resolve(url, `./${name}`))
|
||||
this._renderHtml('sidebar', await this._render(sidebarFile, 'sidebar'))
|
||||
}
|
||||
|
||||
if (loadNavbar) {
|
||||
const name = loadNavbar === true ? '_navbar.md' : loadNavbar
|
||||
const navbarFile = this._getPath(resolve(url, `./${name}`))
|
||||
this._renderHtml('navbar', await this._render(navbarFile, 'navbar'))
|
||||
}
|
||||
|
||||
const html = this.html
|
||||
this.html = this.template
|
||||
|
||||
return html
|
||||
}
|
||||
|
||||
_renderHtml (match, content) {
|
||||
this.html = this.html.replace(new RegExp(`<!--${match}-->`, 'g'), content)
|
||||
|
||||
return this.html
|
||||
}
|
||||
|
||||
async _render (path, type) {
|
||||
let html = await this._loadFile(path)
|
||||
const { subMaxLevel, maxLevel } = this.config
|
||||
|
||||
switch (type) {
|
||||
case 'sidebar':
|
||||
html = this.compiler.sidebar(html, maxLevel) +
|
||||
`<script>window.__SUB_SIDEBAR__ = ${JSON.stringify(
|
||||
this.compiler.subSidebar(subMaxLevel)
|
||||
)}</script>`
|
||||
break
|
||||
case 'cover':
|
||||
html = this.compiler.cover(html)
|
||||
break
|
||||
case 'navbar':
|
||||
case 'article':
|
||||
default:
|
||||
html = this.compiler.compile(html)
|
||||
break
|
||||
}
|
||||
|
||||
return html
|
||||
}
|
||||
|
||||
async _loadFile (filePath) {
|
||||
debug('docsify')(`load > ${filePath}`)
|
||||
let content
|
||||
try {
|
||||
if (isAbsolutePath(filePath)) {
|
||||
const res = await fetch(filePath)
|
||||
if (!res.ok) throw Error()
|
||||
content = await res.text()
|
||||
this.lock = 0
|
||||
} else {
|
||||
content = await readFileSync(filePath, 'utf8')
|
||||
this.lock = 0
|
||||
}
|
||||
return content
|
||||
} catch (e) {
|
||||
this.lock = this.lock || 0
|
||||
if (++this.lock > 10) {
|
||||
this.lock = 0
|
||||
return
|
||||
}
|
||||
|
||||
const fileName = basename(filePath)
|
||||
|
||||
return await this._loadFile(resolvePathname(`../${fileName}`, filePath))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Renderer.version = '__VERSION__'
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "2.6.8",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
|
||||
"integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw="
|
||||
},
|
||||
"encoding": {
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
|
||||
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s="
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.18",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz",
|
||||
"integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA=="
|
||||
},
|
||||
"is-stream": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
|
||||
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz",
|
||||
"integrity": "sha512-j8XsFGCLw79vWXkZtMSmmLaOk9z5SQ9bV/tkbZVCqvgwzrjAGq66igobLofHtF63NvMTp2WjytpsNTGKa+XRIQ=="
|
||||
},
|
||||
"resolve-pathname": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.1.0.tgz",
|
||||
"integrity": "sha1-6DWIAbhrg7F1YNTjw4LXrvIQCUQ="
|
||||
}
|
||||
},
|
||||
"version": "4.2.3"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "docsify-server-renderer",
|
||||
"version": "4.2.3",
|
||||
"description": "docsify server renderer",
|
||||
"author": {
|
||||
"name": "qingwei-li",
|
||||
"email": "cinwell.li@gmail.com",
|
||||
"url": "https://github.com/QingWei-Li"
|
||||
},
|
||||
"homepage": "https://docsify.js.org",
|
||||
"license": "MIT",
|
||||
"repository": "QingWei-Li/docsify",
|
||||
"main": "build.js",
|
||||
"scripts": {
|
||||
"test": "echo 'hello'"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "^2.6.8",
|
||||
"node-fetch": "^1.7.0",
|
||||
"resolve-pathname": "^2.1.0"
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -18,7 +18,11 @@ const config = merge({
|
||||
executeScript: null,
|
||||
noEmoji: false,
|
||||
ga: '',
|
||||
mergeNavbar: false
|
||||
mergeNavbar: false,
|
||||
formatUpdated: '',
|
||||
externalLinkTarget: '_blank',
|
||||
routerModel: 'hash',
|
||||
noCompileLinks: []
|
||||
}, window.$docsify)
|
||||
|
||||
const script = document.currentScript ||
|
||||
|
||||
@@ -6,13 +6,13 @@ import { scrollIntoView } from './scroll'
|
||||
export function eventMixin (proto) {
|
||||
proto.$resetEvents = function () {
|
||||
scrollIntoView(this.route.query.id)
|
||||
sidebar.getAndActive('nav')
|
||||
sidebar.getAndActive(this.router, 'nav')
|
||||
}
|
||||
}
|
||||
|
||||
export function initEvent (vm) {
|
||||
// Bind toggle button
|
||||
sidebar.btn('button.sidebar-toggle')
|
||||
sidebar.btn('button.sidebar-toggle', vm.router)
|
||||
// Bind sticky effect
|
||||
if (vm.config.coverpage) {
|
||||
!isMobile && on('scroll', sidebar.sticky)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { isMobile } from '../util/env'
|
||||
import * as dom from '../util/dom'
|
||||
import { parse } from '../route/hash'
|
||||
|
||||
const nav = {}
|
||||
let hoverOver = false
|
||||
@@ -53,7 +52,7 @@ function highlight () {
|
||||
}
|
||||
}
|
||||
|
||||
export function scrollActiveSidebar () {
|
||||
export function scrollActiveSidebar (router) {
|
||||
if (isMobile) return
|
||||
|
||||
const sidebar = dom.getNode('.sidebar')
|
||||
@@ -66,7 +65,7 @@ export function scrollActiveSidebar () {
|
||||
let href = a.getAttribute('href')
|
||||
|
||||
if (href !== '/') {
|
||||
href = parse(href).query.id
|
||||
href = router.parse(href).query.id
|
||||
}
|
||||
|
||||
nav[decodeURIComponent(href)] = li
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { isMobile } from '../util/env'
|
||||
import * as dom from '../util/dom'
|
||||
import { getHash } from '../route/hash'
|
||||
|
||||
const title = dom.$.title
|
||||
/**
|
||||
* Toggle button
|
||||
*/
|
||||
export function btn (el) {
|
||||
export function btn (el, router) {
|
||||
const toggle = _ => dom.body.classList.toggle('close')
|
||||
|
||||
el = dom.getNode(el)
|
||||
@@ -21,7 +20,7 @@ export function btn (el) {
|
||||
dom.body.classList.contains('close') && toggle()
|
||||
)
|
||||
dom.on(sidebar, 'click', _ =>
|
||||
setTimeout((_ => getAndActive(sidebar, true, true), 0))
|
||||
setTimeout((_ => getAndActive(router, sidebar, true, true), 0))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -39,16 +38,17 @@ export function sticky () {
|
||||
|
||||
/**
|
||||
* Get and active link
|
||||
* @param {object} router
|
||||
* @param {string|element} el
|
||||
* @param {Boolean} isParent acitve parent
|
||||
* @param {Boolean} autoTitle auto set title
|
||||
* @return {element}
|
||||
*/
|
||||
export function getAndActive (el, isParent, autoTitle) {
|
||||
export function getAndActive (router, el, isParent, autoTitle) {
|
||||
el = dom.getNode(el)
|
||||
|
||||
const links = dom.findAll(el, 'a')
|
||||
const hash = '#' + getHash()
|
||||
const hash = router.toURL(router.getCurrentPath())
|
||||
let target
|
||||
|
||||
links
|
||||
|
||||
+11
-4
@@ -14,9 +14,10 @@ export function get (url, hasBar = false) {
|
||||
const on = function () {
|
||||
xhr.addEventListener.apply(xhr, arguments)
|
||||
}
|
||||
const cached = cache[url]
|
||||
|
||||
if (cache[url]) {
|
||||
return { then: cb => cb(cache[url]), abort: noop }
|
||||
if (cached) {
|
||||
return { then: cb => cb(cached.content, cached.opt), abort: noop }
|
||||
}
|
||||
|
||||
xhr.open('GET', url)
|
||||
@@ -41,8 +42,14 @@ export function get (url, hasBar = false) {
|
||||
if (target.status >= 400) {
|
||||
error(target)
|
||||
} else {
|
||||
cache[url] = target.response
|
||||
success(target.response)
|
||||
const result = cache[url] = {
|
||||
content: target.response,
|
||||
opt: {
|
||||
updatedAt: xhr.getResponseHeader('last-modified')
|
||||
}
|
||||
}
|
||||
|
||||
success(result.content, result.opt)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
+32
-9
@@ -1,7 +1,8 @@
|
||||
import { get } from './ajax'
|
||||
import { callHook } from '../init/lifecycle'
|
||||
import { getParentPath } from '../route/util'
|
||||
import { getParentPath } from '../router/util'
|
||||
import { noop } from '../util/core'
|
||||
import { getAndActive } from '../event/sidebar'
|
||||
|
||||
function loadNested (path, file, next, vm, first) {
|
||||
path = first ? path : path.replace(/\/$/, '')
|
||||
@@ -9,7 +10,7 @@ function loadNested (path, file, next, vm, first) {
|
||||
|
||||
if (!path) return
|
||||
|
||||
get(vm.$getFile(path + file))
|
||||
get(vm.router.getFile(path + file))
|
||||
.then(next, _ => loadNested(path, file, next, vm))
|
||||
}
|
||||
|
||||
@@ -22,22 +23,29 @@ export function fetchMixin (proto) {
|
||||
// Abort last request
|
||||
last && last.abort && last.abort()
|
||||
|
||||
last = get(this.$getFile(path), true)
|
||||
last = get(this.router.getFile(path), true)
|
||||
|
||||
// Current page is html
|
||||
this.isHTML = /\.html$/g.test(path)
|
||||
|
||||
// Load main content
|
||||
last.then(text => {
|
||||
this._renderMain(text)
|
||||
const loadSideAndNav = () => {
|
||||
if (!loadSidebar) return cb()
|
||||
|
||||
const fn = result => { this._renderSidebar(result); cb() }
|
||||
|
||||
// Load sidebar
|
||||
loadNested(path, loadSidebar, fn, this, true)
|
||||
}
|
||||
|
||||
// Load main content
|
||||
last.then((text, opt) => {
|
||||
this._renderMain(text, opt)
|
||||
loadSideAndNav()
|
||||
},
|
||||
_ => this._renderMain(null))
|
||||
_ => {
|
||||
this._renderMain(null)
|
||||
loadSideAndNav()
|
||||
})
|
||||
|
||||
// Load nav
|
||||
loadNavbar &&
|
||||
@@ -47,7 +55,7 @@ export function fetchMixin (proto) {
|
||||
proto._fetchCover = function () {
|
||||
const { coverpage } = this.config
|
||||
const root = getParentPath(this.route.path)
|
||||
const path = this.$getFile(root + coverpage)
|
||||
const path = this.router.getFile(root + coverpage)
|
||||
|
||||
if (this.route.path !== '/' || !coverpage) {
|
||||
this._renderCover()
|
||||
@@ -70,5 +78,20 @@ export function fetchMixin (proto) {
|
||||
}
|
||||
|
||||
export function initFetch (vm) {
|
||||
vm.$fetch(_ => callHook(vm, 'ready'))
|
||||
const { loadSidebar } = vm.config
|
||||
|
||||
// server-client renderer
|
||||
if (vm.rendered) {
|
||||
const activeEl = getAndActive(vm.router, '.sidebar-nav', true, true)
|
||||
if (loadSidebar && activeEl) {
|
||||
activeEl.parentNode.innerHTML += window.__SUB_SIDEBAR__
|
||||
}
|
||||
vm._bindEventOnRendered(activeEl)
|
||||
vm._fetchCover()
|
||||
vm.$resetEvents()
|
||||
callHook(vm, 'doneEach')
|
||||
callHook(vm, 'ready')
|
||||
} else {
|
||||
vm.$fetch(_ => callHook(vm, 'ready'))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import * as util from './util'
|
||||
import * as dom from './util/dom'
|
||||
import * as render from './render/compiler'
|
||||
import * as route from './route/hash'
|
||||
import { Compiler } from './render/compiler'
|
||||
import { slugify } from './render/slugify'
|
||||
import { get } from './fetch/ajax'
|
||||
import marked from 'marked'
|
||||
import prism from 'prismjs'
|
||||
|
||||
export default function () {
|
||||
window.Docsify = { util, dom, render, route, get, slugify }
|
||||
window.Docsify = { util, dom, get, slugify }
|
||||
window.DocsifyCompiler = Compiler
|
||||
window.marked = marked
|
||||
window.Prism = prism
|
||||
}
|
||||
|
||||
+7
-2
@@ -1,5 +1,5 @@
|
||||
import { initMixin } from './init'
|
||||
import { routeMixin } from './route'
|
||||
import { routerMixin } from './router'
|
||||
import { renderMixin } from './render'
|
||||
import { fetchMixin } from './fetch'
|
||||
import { eventMixin } from './event'
|
||||
@@ -12,7 +12,7 @@ function Docsify () {
|
||||
const proto = Docsify.prototype
|
||||
|
||||
initMixin(proto)
|
||||
routeMixin(proto)
|
||||
routerMixin(proto)
|
||||
renderMixin(proto)
|
||||
fetchMixin(proto)
|
||||
eventMixin(proto)
|
||||
@@ -22,6 +22,11 @@ eventMixin(proto)
|
||||
*/
|
||||
initGlobalAPI()
|
||||
|
||||
/**
|
||||
* Version
|
||||
*/
|
||||
Docsify.version = '__VERSION__'
|
||||
|
||||
/**
|
||||
* Run Docsify
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import config from '../config'
|
||||
import { initLifecycle, callHook } from './lifecycle'
|
||||
import { initRender } from '../render'
|
||||
import { initRoute } from '../route'
|
||||
import { initRouter } from '../router'
|
||||
import { initEvent } from '../event'
|
||||
import { initFetch } from '../fetch'
|
||||
import { isFn } from '../util/core'
|
||||
@@ -14,9 +14,9 @@ export function initMixin (proto) {
|
||||
initLifecycle(vm) // Init hooks
|
||||
initPlugin(vm) // Install plugins
|
||||
callHook(vm, 'init')
|
||||
initRouter(vm) // Add router
|
||||
initRender(vm) // Render base DOM
|
||||
initEvent(vm) // Bind events
|
||||
initRoute(vm) // Add hashchange eventListener
|
||||
initFetch(vm) // Fetch data
|
||||
callHook(vm, 'mounted')
|
||||
}
|
||||
|
||||
@@ -19,23 +19,22 @@ export function initLifecycle (vm) {
|
||||
}
|
||||
|
||||
export function callHook (vm, hook, data, next = noop) {
|
||||
let newData = data
|
||||
const queue = vm._hooks[hook]
|
||||
|
||||
const step = function (index) {
|
||||
const hook = queue[index]
|
||||
if (index >= queue.length) {
|
||||
next(newData)
|
||||
next(data)
|
||||
} else {
|
||||
if (typeof hook === 'function') {
|
||||
if (hook.length === 2) {
|
||||
hook(data, result => {
|
||||
newData = result
|
||||
data = result
|
||||
step(index + 1)
|
||||
})
|
||||
} else {
|
||||
const result = hook(data)
|
||||
newData = result !== undefined ? result : newData
|
||||
data = result !== undefined ? result : data
|
||||
step(index + 1)
|
||||
}
|
||||
} else {
|
||||
|
||||
+153
-118
@@ -4,155 +4,190 @@ import { helper as helperTpl, tree as treeTpl } from './tpl'
|
||||
import { genTree } from './gen-tree'
|
||||
import { slugify } from './slugify'
|
||||
import { emojify } from './emojify'
|
||||
import { toURL, parse } from '../route/hash'
|
||||
import { getBasePath, isAbsolutePath, getPath } from '../route/util'
|
||||
import { isAbsolutePath, getPath } from '../router/util'
|
||||
import { isFn, merge, cached } from '../util/core'
|
||||
|
||||
let markdownCompiler = marked
|
||||
let contentBase = ''
|
||||
let currentPath = ''
|
||||
let renderer = new marked.Renderer()
|
||||
const cacheTree = {}
|
||||
let toc = []
|
||||
const cachedLinks = {}
|
||||
|
||||
/**
|
||||
* Compile markdown content
|
||||
*/
|
||||
export const markdown = cached(text => {
|
||||
let html = ''
|
||||
export class Compiler {
|
||||
constructor (config, router) {
|
||||
this.config = config
|
||||
this.router = router
|
||||
this.cacheTree = {}
|
||||
this.toc = []
|
||||
this.linkTarget = config.externalLinkTarget || '_blank'
|
||||
this.contentBase = router.getBasePath()
|
||||
|
||||
if (!text) return text
|
||||
const renderer = this._initRenderer()
|
||||
let compile
|
||||
const mdConf = config.markdown || {}
|
||||
|
||||
html = markdownCompiler(text)
|
||||
html = emojify(html)
|
||||
slugify.clear()
|
||||
if (isFn(mdConf)) {
|
||||
compile = mdConf(marked, renderer)
|
||||
} else {
|
||||
marked.setOptions(merge(mdConf, {
|
||||
renderer: merge(renderer, mdConf.renderer)
|
||||
}))
|
||||
compile = marked
|
||||
}
|
||||
|
||||
return html
|
||||
})
|
||||
this.compile = cached(text => {
|
||||
let html = ''
|
||||
|
||||
markdown.renderer = renderer
|
||||
if (!text) return text
|
||||
|
||||
markdown.init = function (config = {}, base = window.location.pathname) {
|
||||
contentBase = getBasePath(base)
|
||||
html = compile(text)
|
||||
html = config.noEmoji ? html : emojify(html)
|
||||
slugify.clear()
|
||||
|
||||
if (isFn(config)) {
|
||||
markdownCompiler = config(marked, renderer)
|
||||
} else {
|
||||
renderer = merge(renderer, config.renderer)
|
||||
marked.setOptions(merge(config, { renderer }))
|
||||
}
|
||||
}
|
||||
|
||||
markdown.update = function () {
|
||||
currentPath = parse().path
|
||||
}
|
||||
|
||||
/**
|
||||
* render anchor tag
|
||||
* @link https://github.com/chjj/marked#overriding-renderer-methods
|
||||
*/
|
||||
renderer.heading = function (text, level) {
|
||||
const nextToc = { level, title: text }
|
||||
|
||||
if (/{docsify-ignore}/g.test(text)) {
|
||||
text = text.replace('{docsify-ignore}', '')
|
||||
nextToc.title = text
|
||||
nextToc.ignoreSubHeading = true
|
||||
return html
|
||||
})
|
||||
}
|
||||
|
||||
if (/{docsify-ignore-all}/g.test(text)) {
|
||||
text = text.replace('{docsify-ignore-all}', '')
|
||||
nextToc.title = text
|
||||
nextToc.ignoreAllSubs = true
|
||||
matchNotCompileLink (link) {
|
||||
const links = this.config.noCompileLinks
|
||||
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
const n = links[i]
|
||||
const re = cachedLinks[n] || (cachedLinks[n] = new RegExp(`^${n}$`))
|
||||
|
||||
if (re.test(link)) {
|
||||
return link
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const slug = slugify(text)
|
||||
const url = toURL(currentPath, { id: slug })
|
||||
nextToc.slug = url
|
||||
toc.push(nextToc)
|
||||
_initRenderer () {
|
||||
const renderer = new marked.Renderer()
|
||||
const { linkTarget, router, contentBase } = this
|
||||
const _self = this
|
||||
/**
|
||||
* render anchor tag
|
||||
* @link https://github.com/chjj/marked#overriding-renderer-methods
|
||||
*/
|
||||
renderer.heading = function (text, level) {
|
||||
const nextToc = { level, title: text }
|
||||
|
||||
return `<h${level} id="${slug}"><a href="${url}" data-id="${slug}" class="anchor"><span>${text}</span></a></h${level}>`
|
||||
}
|
||||
// highlight code
|
||||
renderer.code = function (code, lang = '') {
|
||||
const hl = Prism.highlight(code, Prism.languages[lang] || Prism.languages.markup)
|
||||
if (/{docsify-ignore}/g.test(text)) {
|
||||
text = text.replace('{docsify-ignore}', '')
|
||||
nextToc.title = text
|
||||
nextToc.ignoreSubHeading = true
|
||||
}
|
||||
|
||||
return `<pre v-pre data-lang="${lang}"><code class="lang-${lang}">${hl}</code></pre>`
|
||||
}
|
||||
renderer.link = function (href, title, text) {
|
||||
let blank = ''
|
||||
if (!/:|(\/{2})/.test(href)) {
|
||||
href = toURL(href, null, currentPath)
|
||||
} else {
|
||||
blank = ' target="_blank"'
|
||||
}
|
||||
if (title) {
|
||||
title = ` title="${title}"`
|
||||
}
|
||||
return `<a href="${href}"${title || ''}${blank}>${text}</a>`
|
||||
}
|
||||
renderer.paragraph = function (text) {
|
||||
if (/^!>/.test(text)) {
|
||||
return helperTpl('tip', text)
|
||||
} else if (/^\?>/.test(text)) {
|
||||
return helperTpl('warn', text)
|
||||
}
|
||||
return `<p>${text}</p>`
|
||||
}
|
||||
renderer.image = function (href, title, text) {
|
||||
let url = href
|
||||
const titleHTML = title ? ` title="${title}"` : ''
|
||||
if (/{docsify-ignore-all}/g.test(text)) {
|
||||
text = text.replace('{docsify-ignore-all}', '')
|
||||
nextToc.title = text
|
||||
nextToc.ignoreAllSubs = true
|
||||
}
|
||||
|
||||
if (!isAbsolutePath(href)) {
|
||||
url = getPath(contentBase, href)
|
||||
const slug = slugify(text)
|
||||
const url = router.toURL(router.getCurrentPath(), { id: slug })
|
||||
nextToc.slug = url
|
||||
_self.toc.push(nextToc)
|
||||
|
||||
return `<h${level} id="${slug}"><a href="${url}" data-id="${slug}" class="anchor"><span>${text}</span></a></h${level}>`
|
||||
}
|
||||
// highlight code
|
||||
renderer.code = function (code, lang = '') {
|
||||
const hl = Prism.highlight(code, Prism.languages[lang] || Prism.languages.markup)
|
||||
|
||||
return `<pre v-pre data-lang="${lang}"><code class="lang-${lang}">${hl}</code></pre>`
|
||||
}
|
||||
renderer.link = function (href, title, text) {
|
||||
let blank = ''
|
||||
|
||||
if (!/:|(\/{2})/.test(href) &&
|
||||
!_self.matchNotCompileLink(href) &&
|
||||
!/(\s?:ignore)(\s\S+)?$/.test(title)) {
|
||||
href = router.toURL(href, null, router.getCurrentPath())
|
||||
} else {
|
||||
blank = ` target="${linkTarget}"`
|
||||
title = title && title.replace(/:ignore/g, '').trim()
|
||||
}
|
||||
|
||||
if (title) {
|
||||
title = ` title="${title}"`
|
||||
}
|
||||
return `<a href="${href}"${title || ''}${blank}>${text}</a>`
|
||||
}
|
||||
renderer.paragraph = function (text) {
|
||||
if (/^!>/.test(text)) {
|
||||
return helperTpl('tip', text)
|
||||
} else if (/^\?>/.test(text)) {
|
||||
return helperTpl('warn', text)
|
||||
}
|
||||
return `<p>${text}</p>`
|
||||
}
|
||||
renderer.image = function (href, title, text) {
|
||||
let url = href
|
||||
const titleHTML = title ? ` title="${title}"` : ''
|
||||
|
||||
if (!isAbsolutePath(href)) {
|
||||
url = getPath(contentBase, href)
|
||||
}
|
||||
|
||||
return `<img src="${url}" data-origin="${href}" alt="${text}"${titleHTML}>`
|
||||
}
|
||||
|
||||
return renderer
|
||||
}
|
||||
|
||||
return `<img src="${url}" data-origin="${href}" alt="${text}"${titleHTML}>`
|
||||
}
|
||||
/**
|
||||
* Compile sidebar
|
||||
*/
|
||||
sidebar (text, level) {
|
||||
const currentPath = this.router.getCurrentPath()
|
||||
let html = ''
|
||||
|
||||
/**
|
||||
* Compile sidebar
|
||||
*/
|
||||
export function sidebar (text, level) {
|
||||
let html = ''
|
||||
if (text) {
|
||||
html = this.compile(text)
|
||||
html = html && html.match(/<ul[^>]*>([\s\S]+)<\/ul>/g)[0]
|
||||
} else {
|
||||
const tree = this.cacheTree[currentPath] || genTree(this.toc, level)
|
||||
html = treeTpl(tree, '<ul>')
|
||||
this.cacheTree[currentPath] = tree
|
||||
}
|
||||
|
||||
if (text) {
|
||||
html = markdown(text)
|
||||
html = html.match(/<ul[^>]*>([\s\S]+)<\/ul>/g)[0]
|
||||
} else {
|
||||
const tree = cacheTree[currentPath] || genTree(toc, level)
|
||||
html = treeTpl(tree, '<ul>')
|
||||
cacheTree[currentPath] = tree
|
||||
return html
|
||||
}
|
||||
|
||||
return html
|
||||
}
|
||||
/**
|
||||
* Compile sub sidebar
|
||||
*/
|
||||
subSidebar (level) {
|
||||
if (!level) {
|
||||
this.toc = []
|
||||
return
|
||||
}
|
||||
const currentPath = this.router.getCurrentPath()
|
||||
const { cacheTree, toc } = this
|
||||
|
||||
/**
|
||||
* Compile sub sidebar
|
||||
*/
|
||||
export function subSidebar (el, level) {
|
||||
if (el) {
|
||||
toc[0] && toc[0].ignoreAllSubs && (toc = [])
|
||||
toc[0] && toc[0].ignoreAllSubs && (this.toc = [])
|
||||
toc[0] && toc[0].level === 1 && toc.shift()
|
||||
toc.forEach((node, i) => {
|
||||
node.ignoreSubHeading && toc.splice(i, 1)
|
||||
})
|
||||
|
||||
const tree = cacheTree[currentPath] || genTree(toc, level)
|
||||
el.parentNode.innerHTML += treeTpl(tree, '<ul class="app-sub-sidebar">')
|
||||
|
||||
cacheTree[currentPath] = tree
|
||||
this.toc = []
|
||||
return treeTpl(tree, '<ul class="app-sub-sidebar">')
|
||||
}
|
||||
toc = []
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile cover page
|
||||
*/
|
||||
export function cover (text) {
|
||||
const cacheToc = toc.slice()
|
||||
const html = markdown(text)
|
||||
article (text) {
|
||||
return this.compile(text)
|
||||
}
|
||||
|
||||
toc = cacheToc.slice()
|
||||
/**
|
||||
* Compile cover page
|
||||
*/
|
||||
cover (text) {
|
||||
const cacheToc = this.toc.slice()
|
||||
const html = this.compile(text)
|
||||
|
||||
return html
|
||||
this.toc = cacheToc.slice()
|
||||
|
||||
return html
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { inBrowser } from '../util/env'
|
||||
|
||||
function replace (m, $1) {
|
||||
return '<img class="emoji" src="https://assets-cdn.github.com/images/icons/emoji/' + $1 + '.png" alt="' + $1 + '" />'
|
||||
}
|
||||
|
||||
export function emojify (text) {
|
||||
return $docsify.noEmoji ? text : text
|
||||
return text
|
||||
.replace(/<(pre|template|code)[^>]*?>[\s\S]+?<\/(pre|template|code)>/g, m => m.replace(/:/g, '__colon__'))
|
||||
.replace(/:(\w+?):/ig, window.emojify || replace)
|
||||
.replace(/:(\w+?):/ig, (inBrowser && window.emojify) || replace)
|
||||
.replace(/__colon__/g, ':')
|
||||
}
|
||||
|
||||
+71
-42
@@ -1,13 +1,14 @@
|
||||
import * as dom from '../util/dom'
|
||||
import { getAndActive, sticky } from '../event/sidebar'
|
||||
import { scrollActiveSidebar, scroll2Top } from '../event/scroll'
|
||||
import cssVars from '../util/polyfill/css-vars'
|
||||
import * as tpl from './tpl'
|
||||
import { markdown, sidebar, subSidebar, cover } from './compiler'
|
||||
import cssVars from '../util/polyfill/css-vars'
|
||||
import tinydate from 'tinydate'
|
||||
import { callHook } from '../init/lifecycle'
|
||||
import { getBasePath, getPath, isAbsolutePath } from '../route/util'
|
||||
import { isPrimitive } from '../util/core'
|
||||
import { Compiler } from './compiler'
|
||||
import { getAndActive, sticky } from '../event/sidebar'
|
||||
import { getPath, isAbsolutePath } from '../router/util'
|
||||
import { isMobile } from '../util/env'
|
||||
import { isPrimitive } from '../util/core'
|
||||
import { scrollActiveSidebar, scroll2Top } from '../event/scroll'
|
||||
|
||||
function executeScript () {
|
||||
const script = dom.findAll('.markdown-section>script')
|
||||
@@ -21,6 +22,16 @@ function executeScript () {
|
||||
}, 0)
|
||||
}
|
||||
|
||||
function formatUpdated (html, updated, fn) {
|
||||
updated = typeof fn === 'function'
|
||||
? fn(updated)
|
||||
: typeof fn === 'string'
|
||||
? tinydate(fn)(new Date(updated))
|
||||
: updated
|
||||
|
||||
return html.replace(/{docsify-updated}/g, updated)
|
||||
}
|
||||
|
||||
function renderMain (html) {
|
||||
if (!html) {
|
||||
// TODO: Custom 404 page
|
||||
@@ -43,10 +54,6 @@ function renderMain (html) {
|
||||
} else {
|
||||
this.config.executeScript && executeScript()
|
||||
}
|
||||
|
||||
if (this.config.auto2top) {
|
||||
scroll2Top(this.config.auto2top)
|
||||
}
|
||||
}
|
||||
|
||||
function renderNameLink (vm) {
|
||||
@@ -59,7 +66,7 @@ function renderNameLink (vm) {
|
||||
if (isPrimitive(vm.config.nameLink)) {
|
||||
el.setAttribute('href', nameLink)
|
||||
} else if (typeof nameLink === 'object') {
|
||||
const match = Object.keys(nameLink).find(key => path.indexOf(key) > -1)
|
||||
const match = Object.keys(nameLink).filter(key => path.indexOf(key) > -1)[0]
|
||||
|
||||
el.setAttribute('href', nameLink[match])
|
||||
}
|
||||
@@ -72,34 +79,54 @@ export function renderMixin (proto) {
|
||||
}
|
||||
|
||||
proto._renderSidebar = function (text) {
|
||||
const { maxLevel, subMaxLevel, autoHeader, loadSidebar } = this.config
|
||||
const { maxLevel, subMaxLevel, loadSidebar } = this.config
|
||||
|
||||
this._renderTo('.sidebar-nav', sidebar(text, maxLevel))
|
||||
const active = getAndActive('.sidebar-nav', true, true)
|
||||
subSidebar(loadSidebar ? active : '', subMaxLevel)
|
||||
this._renderTo('.sidebar-nav', this.compiler.sidebar(text, maxLevel))
|
||||
const activeEl = getAndActive(this.router, '.sidebar-nav', true, true)
|
||||
if (loadSidebar && activeEl) {
|
||||
activeEl.parentNode.innerHTML += (this.compiler.subSidebar(subMaxLevel) || '')
|
||||
} else {
|
||||
// reset toc
|
||||
this.compiler.subSidebar()
|
||||
}
|
||||
// bind event
|
||||
this.activeLink = active
|
||||
scrollActiveSidebar()
|
||||
this._bindEventOnRendered(activeEl)
|
||||
}
|
||||
|
||||
if (autoHeader && active) {
|
||||
proto._bindEventOnRendered = function (activeEl) {
|
||||
const { autoHeader, auto2top } = this.config
|
||||
|
||||
scrollActiveSidebar(this.router)
|
||||
|
||||
if (autoHeader && activeEl) {
|
||||
const main = dom.getNode('#main')
|
||||
const firstNode = main.children[0]
|
||||
if (firstNode && firstNode.tagName !== 'H1') {
|
||||
const h1 = dom.create('h1')
|
||||
h1.innerText = active.innerText
|
||||
h1.innerText = activeEl.innerText
|
||||
dom.before(main, h1)
|
||||
}
|
||||
}
|
||||
|
||||
auto2top && scroll2Top(auto2top)
|
||||
}
|
||||
|
||||
proto._renderNav = function (text) {
|
||||
text && this._renderTo('nav', markdown(text))
|
||||
getAndActive('nav')
|
||||
text && this._renderTo('nav', this.compiler.compile(text))
|
||||
getAndActive(this.router, 'nav')
|
||||
}
|
||||
|
||||
proto._renderMain = function (text) {
|
||||
proto._renderMain = function (text, opt = {}) {
|
||||
if (!text) {
|
||||
return renderMain.call(this, text)
|
||||
}
|
||||
|
||||
callHook(this, 'beforeEach', text, result => {
|
||||
const html = this.isHTML ? result : markdown(result)
|
||||
let html = this.isHTML ? result : this.compiler.compile(result)
|
||||
if (opt.updatedAt) {
|
||||
html = formatUpdated(html, opt.updatedAt, this.config.formatUpdated)
|
||||
}
|
||||
|
||||
callHook(this, 'afterEach', html, text => renderMain.call(this, text))
|
||||
})
|
||||
}
|
||||
@@ -112,7 +139,7 @@ export function renderMixin (proto) {
|
||||
}
|
||||
dom.toggleClass(el, 'add', 'show')
|
||||
|
||||
let html = this.coverIsHTML ? text : cover(text)
|
||||
let html = this.coverIsHTML ? text : this.compiler.cover(text)
|
||||
const m = html.trim().match('<p><img.*?data-origin="(.*?)"[^a]+alt="(.*?)">([^<]*?)</p>$')
|
||||
|
||||
if (m) {
|
||||
@@ -123,7 +150,7 @@ export function renderMixin (proto) {
|
||||
|
||||
dom.toggleClass(el, 'add', 'has-mask')
|
||||
if (!isAbsolutePath(m[1])) {
|
||||
path = getPath(getBasePath(this.config.basePath), m[1])
|
||||
path = getPath(this.router.getBasePath(), m[1])
|
||||
}
|
||||
el.style.backgroundImage = `url(${path})`
|
||||
el.style.backgroundSize = 'cover'
|
||||
@@ -137,7 +164,6 @@ export function renderMixin (proto) {
|
||||
}
|
||||
|
||||
proto._updateRender = function () {
|
||||
markdown.update()
|
||||
// render name link
|
||||
renderNameLink(this)
|
||||
}
|
||||
@@ -147,29 +173,29 @@ export function initRender (vm) {
|
||||
const config = vm.config
|
||||
|
||||
// Init markdown compiler
|
||||
markdown.init(config.markdown, config.basePath)
|
||||
vm.compiler = new Compiler(config, vm.router)
|
||||
|
||||
const id = config.el || '#app'
|
||||
const navEl = dom.find('nav') || dom.create('nav')
|
||||
|
||||
let el = dom.find(id)
|
||||
const el = dom.find(id)
|
||||
let html = ''
|
||||
let navAppendToTarget = dom.body
|
||||
|
||||
if (!el) {
|
||||
el = dom.create(id)
|
||||
dom.appendTo(dom.body, el)
|
||||
}
|
||||
if (config.repo) {
|
||||
html += tpl.corner(config.repo)
|
||||
}
|
||||
if (config.coverpage) {
|
||||
html += tpl.cover()
|
||||
}
|
||||
if (el) {
|
||||
if (config.repo) {
|
||||
html += tpl.corner(config.repo)
|
||||
}
|
||||
if (config.coverpage) {
|
||||
html += tpl.cover()
|
||||
}
|
||||
|
||||
html += tpl.main(config)
|
||||
// Render main app
|
||||
vm._renderTo(el, html, true)
|
||||
html += tpl.main(config)
|
||||
// Render main app
|
||||
vm._renderTo(el, html, true)
|
||||
} else {
|
||||
vm.rendered = true
|
||||
}
|
||||
|
||||
if (config.mergeNavbar && isMobile) {
|
||||
navAppendToTarget = dom.find('.sidebar')
|
||||
@@ -185,9 +211,12 @@ export function initRender (vm) {
|
||||
dom.before(navAppendToTarget, navEl)
|
||||
|
||||
if (config.themeColor) {
|
||||
dom.$.head.innerHTML += tpl.theme(config.themeColor)
|
||||
dom.$.head.appendChild(
|
||||
dom.create('div', tpl.theme(config.themeColor)).getRootNode()
|
||||
)
|
||||
// Polyfll
|
||||
cssVars(config.themeColor)
|
||||
}
|
||||
vm._updateRender()
|
||||
dom.toggleClass(dom.body, 'ready')
|
||||
}
|
||||
|
||||
@@ -33,12 +33,12 @@ export function main (config) {
|
||||
(config.name
|
||||
? `<h1><a class="app-name-link" data-nosearch>${config.name}</a></h1>`
|
||||
: '') +
|
||||
'<div class="sidebar-nav"></div>' +
|
||||
'<div class="sidebar-nav"><!--sidebar--></div>' +
|
||||
'</aside>')
|
||||
|
||||
return (isMobile ? `${aside}<main>` : `<main>${aside}`) +
|
||||
'<section class="content">' +
|
||||
'<article class="markdown-section" id="main"></article>' +
|
||||
'<article class="markdown-section" id="main"><!--main--></article>' +
|
||||
'</section>' +
|
||||
'</main>'
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
import { merge, cached } from '../util/core'
|
||||
import { parseQuery, stringifyQuery, cleanPath } from './util'
|
||||
export * from './util'
|
||||
|
||||
function replaceHash (path) {
|
||||
const i = window.location.href.indexOf('#')
|
||||
window.location.replace(
|
||||
window.location.href.slice(0, i >= 0 ? i : 0) + '#' + path
|
||||
)
|
||||
}
|
||||
|
||||
const replaceSlug = cached(path => {
|
||||
return path
|
||||
.replace('#', '?id=')
|
||||
// .replace(/\?(\w+)=/g, (_, slug) => slug === 'id' ? '?id=' : `&${slug}=`)
|
||||
})
|
||||
/**
|
||||
* Normalize the current url
|
||||
*
|
||||
* @example
|
||||
* domain.com/docs/ => domain.com/docs/#/
|
||||
* domain.com/docs/#/#slug => domain.com/docs/#/?id=slug
|
||||
*/
|
||||
export function normalize () {
|
||||
let path = getHash()
|
||||
|
||||
path = replaceSlug(path)
|
||||
|
||||
if (path.charAt(0) === '/') return replaceHash(path)
|
||||
replaceHash('/' + path)
|
||||
}
|
||||
|
||||
export function getHash () {
|
||||
// We can't use window.location.hash here because it's not
|
||||
// consistent across browsers - Firefox will pre-decode it!
|
||||
const href = window.location.href
|
||||
const index = href.indexOf('#')
|
||||
return index === -1 ? '' : href.slice(index + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the url
|
||||
* @param {string} [path=window.location.herf]
|
||||
* @return {object} { path, query }
|
||||
*/
|
||||
export function parse (path = window.location.href) {
|
||||
let query = ''
|
||||
|
||||
const queryIndex = path.indexOf('?')
|
||||
if (queryIndex >= 0) {
|
||||
query = path.slice(queryIndex + 1)
|
||||
path = path.slice(0, queryIndex)
|
||||
}
|
||||
|
||||
const hashIndex = path.indexOf('#')
|
||||
if (hashIndex) {
|
||||
path = path.slice(hashIndex + 1)
|
||||
}
|
||||
|
||||
return { path, query: parseQuery(query) }
|
||||
}
|
||||
|
||||
/**
|
||||
* to URL
|
||||
* @param {string} path
|
||||
* @param {object} qs query params
|
||||
* @param {string} currentRoute optional current route
|
||||
*/
|
||||
export function toURL (path, params, currentRoute) {
|
||||
const local = currentRoute && path[0] === '#'
|
||||
const route = parse(replaceSlug(path))
|
||||
|
||||
route.query = merge({}, route.query, params)
|
||||
path = route.path + stringifyQuery(route.query)
|
||||
path = path.replace(/\.md(\?)|\.md$/, '$1')
|
||||
|
||||
if (local) path = currentRoute + path
|
||||
|
||||
return cleanPath('#/' + path)
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import { normalize, parse } from './hash'
|
||||
import { getBasePath, getPath, isAbsolutePath } from './util'
|
||||
import { on } from '../util/dom'
|
||||
|
||||
function getAlias (path, alias) {
|
||||
return alias[path] ? getAlias(alias[path], alias) : path
|
||||
}
|
||||
|
||||
function getFileName (path) {
|
||||
return /\.(md|html)$/g.test(path)
|
||||
? path
|
||||
: /\/$/g.test(path)
|
||||
? `${path}README.md`
|
||||
: `${path}.md`
|
||||
}
|
||||
|
||||
export function routeMixin (proto) {
|
||||
proto.route = {}
|
||||
proto.$getFile = function (path) {
|
||||
const { config } = this
|
||||
const base = getBasePath(config.basePath)
|
||||
|
||||
path = config.alias ? getAlias(path, config.alias) : path
|
||||
path = getFileName(path)
|
||||
path = path === '/README.md' ? (config.homepage || path) : path
|
||||
path = isAbsolutePath(path) ? path : getPath(base, path)
|
||||
|
||||
return path
|
||||
}
|
||||
}
|
||||
|
||||
let lastRoute = {}
|
||||
|
||||
export function initRoute (vm) {
|
||||
normalize()
|
||||
lastRoute = vm.route = parse()
|
||||
vm._updateRender()
|
||||
|
||||
on('hashchange', _ => {
|
||||
normalize()
|
||||
vm.route = parse()
|
||||
vm._updateRender()
|
||||
|
||||
if (lastRoute.path === vm.route.path) {
|
||||
vm.$resetEvents()
|
||||
return
|
||||
}
|
||||
|
||||
vm.$fetch()
|
||||
lastRoute = vm.route
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { History } from './base'
|
||||
import { parseQuery, stringifyQuery, cleanPath } from '../util'
|
||||
import { merge } from '../../util/core'
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
toURL (path, params, currentRoute) {
|
||||
const local = currentRoute && path[0] === '#'
|
||||
const route = this.parse(path)
|
||||
|
||||
route.query = merge({}, route.query, params)
|
||||
path = route.path + stringifyQuery(route.query)
|
||||
path = path.replace(/\.md(\?)|\.md$/, '$1')
|
||||
|
||||
if (local) path = currentRoute + path
|
||||
|
||||
return cleanPath('/' + path)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import { getPath, isAbsolutePath } from '../util'
|
||||
import { noop } 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) {
|
||||
return /\.(md|html)$/g.test(path)
|
||||
? path
|
||||
: /\/$/g.test(path)
|
||||
? `${path}README.md`
|
||||
: `${path}.md`
|
||||
}
|
||||
|
||||
export class History {
|
||||
constructor (config) {
|
||||
this.config = config
|
||||
}
|
||||
|
||||
getBasePath () {
|
||||
return this.config.basePath
|
||||
}
|
||||
|
||||
getFile (path, isRelative) {
|
||||
path = path || this.getCurrentPath()
|
||||
|
||||
const { config } = this
|
||||
const base = this.getBasePath()
|
||||
|
||||
path = config.alias ? getAlias(path, config.alias) : path
|
||||
path = getFileName(path)
|
||||
path = path === '/README.md' ? (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 () {}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import { History } from './base'
|
||||
import { merge, cached, noop } from '../../util/core'
|
||||
import { on } from '../../util/dom'
|
||||
import { parseQuery, stringifyQuery, cleanPath } from '../util'
|
||||
|
||||
function replaceHash (path) {
|
||||
const i = location.href.indexOf('#')
|
||||
location.replace(
|
||||
location.href.slice(0, i >= 0 ? i : 0) + '#' + path
|
||||
)
|
||||
}
|
||||
|
||||
const replaceSlug = cached(path => {
|
||||
return path.replace('#', '?id=')
|
||||
})
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) path = currentRoute + path
|
||||
|
||||
return cleanPath('#/' + path)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import { History } from './base'
|
||||
import { merge, noop } from '../../util/core'
|
||||
import { on } from '../../util/dom'
|
||||
import { parseQuery, stringifyQuery, getPath, cleanPath } 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)
|
||||
}
|
||||
}
|
||||
|
||||
toURL (path, params, currentRoute) {
|
||||
const local = currentRoute && path[0] === '#'
|
||||
const route = this.parse(path)
|
||||
|
||||
route.query = merge({}, route.query, params)
|
||||
path = route.path + stringifyQuery(route.query)
|
||||
path = path.replace(/\.md(\?)|\.md$/, '$1')
|
||||
|
||||
if (local) path = currentRoute + path
|
||||
|
||||
return cleanPath('/' + path)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -16,8 +16,9 @@ export function parseQuery (query) {
|
||||
query.split('&').forEach(function (param) {
|
||||
const parts = param.replace(/\+/g, ' ').split('=')
|
||||
|
||||
res[parts[0]] = decode(parts[1])
|
||||
res[parts[0]] = parts[1] && decode(parts[1])
|
||||
})
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -25,24 +26,20 @@ export function stringifyQuery (obj) {
|
||||
const qs = []
|
||||
|
||||
for (const key in obj) {
|
||||
qs.push(`${encode(key)}=${encode(obj[key])}`.toLowerCase())
|
||||
qs.push(obj[key]
|
||||
? `${encode(key)}=${encode(obj[key])}`.toLowerCase()
|
||||
: encode(key))
|
||||
}
|
||||
|
||||
return qs.length ? `?${qs.join('&')}` : ''
|
||||
}
|
||||
|
||||
export const getBasePath = cached(base => {
|
||||
return /^(\/|https?:)/g.test(base)
|
||||
? base
|
||||
: cleanPath(window.location.pathname + '/' + base)
|
||||
})
|
||||
|
||||
export function getPath (...args) {
|
||||
return cleanPath(args.join('/'))
|
||||
}
|
||||
|
||||
export const isAbsolutePath = cached(path => {
|
||||
return /(:|(\/{2}))/.test(path)
|
||||
return /(:|(\/{2}))/g.test(path)
|
||||
})
|
||||
|
||||
export const getParentPath = cached(path => {
|
||||
+13
-3
@@ -1,5 +1,15 @@
|
||||
export const UA = window.navigator.userAgent.toLowerCase()
|
||||
export const inBrowser = typeof window !== 'undefined'
|
||||
|
||||
export const isIE = UA && /msie|trident/.test(UA)
|
||||
export const isMobile = inBrowser && document.body.clientWidth <= 600
|
||||
|
||||
export const isMobile = 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)/)
|
||||
})()
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './core'
|
||||
export * from './env'
|
||||
export * from '../router/util'
|
||||
|
||||
@@ -10,4 +10,4 @@ const install = function (hook, vm) {
|
||||
})
|
||||
}
|
||||
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins)
|
||||
$docsify.plugins = [].concat(install, $docsify.plugins)
|
||||
|
||||
+11
-10
@@ -7,24 +7,25 @@ function appendScript () {
|
||||
}
|
||||
|
||||
function init (id) {
|
||||
if (!window.ga) {
|
||||
appendScript()
|
||||
window.ga = window.ga || function () {
|
||||
(window.ga.q = window.ga.q || []).push(arguments)
|
||||
}
|
||||
window.ga.l = Number(new Date())
|
||||
window.ga('create', id, 'auto')
|
||||
appendScript()
|
||||
window.ga = window.ga || function () {
|
||||
(window.ga.q = window.ga.q || []).push(arguments)
|
||||
}
|
||||
window.ga.l = Number(new Date())
|
||||
window.ga('create', id, 'auto')
|
||||
}
|
||||
|
||||
function collect () {
|
||||
init(window.$docsify.ga)
|
||||
if (!window.ga) {
|
||||
init($docsify.ga)
|
||||
}
|
||||
|
||||
window.ga('set', 'page', location.hash)
|
||||
window.ga('send', 'pageview')
|
||||
}
|
||||
|
||||
const install = function (hook) {
|
||||
if (!window.$docsify.ga) {
|
||||
if (!$docsify.ga) {
|
||||
console.error('[Docsify] ga is required.')
|
||||
return
|
||||
}
|
||||
@@ -32,4 +33,4 @@ const install = function (hook) {
|
||||
hook.beforeEach(collect)
|
||||
}
|
||||
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins)
|
||||
$docsify.plugins = [].concat(install, $docsify.plugins)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { search } from './search'
|
||||
|
||||
let dom
|
||||
let NO_DATA_TEXT = ''
|
||||
|
||||
function style () {
|
||||
@@ -65,8 +64,8 @@ function style () {
|
||||
.search p.empty {
|
||||
text-align: center;
|
||||
}`
|
||||
const style = dom.create('style', code)
|
||||
dom.appendTo(dom.head, style)
|
||||
const style = Docsify.dom.create('style', code)
|
||||
Docsify.dom.appendTo(Docsify.dom.head, style)
|
||||
}
|
||||
|
||||
function tpl (opts, defaultValue = '') {
|
||||
@@ -74,16 +73,16 @@ function tpl (opts, defaultValue = '') {
|
||||
`<input type="search" value="${defaultValue}" />` +
|
||||
'<div class="results-panel"></div>' +
|
||||
'</div>'
|
||||
const el = dom.create('div', html)
|
||||
const aside = dom.find('aside')
|
||||
const el = Docsify.dom.create('div', html)
|
||||
const aside = Docsify.dom.find('aside')
|
||||
|
||||
dom.toggleClass(el, 'search')
|
||||
dom.before(aside, el)
|
||||
Docsify.dom.toggleClass(el, 'search')
|
||||
Docsify.dom.before(aside, el)
|
||||
}
|
||||
|
||||
function doSearch (value) {
|
||||
const $search = dom.find('div.search')
|
||||
const $panel = dom.find($search, '.results-panel')
|
||||
const $search = Docsify.dom.find('div.search')
|
||||
const $panel = Docsify.dom.find($search, '.results-panel')
|
||||
|
||||
if (!value) {
|
||||
$panel.classList.remove('show')
|
||||
@@ -105,26 +104,27 @@ function doSearch (value) {
|
||||
}
|
||||
|
||||
function bindEvents () {
|
||||
const $search = dom.find('div.search')
|
||||
const $input = dom.find($search, 'input')
|
||||
const $search = Docsify.dom.find('div.search')
|
||||
const $input = Docsify.dom.find($search, 'input')
|
||||
|
||||
let timeId
|
||||
// Prevent to Fold sidebar
|
||||
dom.on($search, 'click',
|
||||
Docsify.dom.on($search, 'click',
|
||||
e => e.target.tagName !== 'A' && e.stopPropagation())
|
||||
dom.on($input, 'input', e => {
|
||||
Docsify.dom.on($input, 'input', e => {
|
||||
clearTimeout(timeId)
|
||||
timeId = setTimeout(_ => doSearch(e.target.value.trim()), 100)
|
||||
})
|
||||
}
|
||||
|
||||
function updatePlaceholder (text, path) {
|
||||
const $input = dom.getNode('.search input[type="search"]')
|
||||
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).find(key => path.indexOf(key) > -1)
|
||||
const match = Object.keys(text).filter(key => path.indexOf(key) > -1)[0]
|
||||
$input.placeholder = text[match]
|
||||
}
|
||||
}
|
||||
@@ -133,14 +133,13 @@ function updateNoData (text, path) {
|
||||
if (typeof text === 'string') {
|
||||
NO_DATA_TEXT = text
|
||||
} else {
|
||||
const match = Object.keys(text).find(key => path.indexOf(key) > -1)
|
||||
const match = Object.keys(text).filter(key => path.indexOf(key) > -1)[0]
|
||||
NO_DATA_TEXT = text[match]
|
||||
}
|
||||
}
|
||||
|
||||
export function init (opts) {
|
||||
dom = Docsify.dom
|
||||
const keywords = Docsify.route.parse().query.s
|
||||
export function init (opts, vm) {
|
||||
const keywords = vm.router.parse().query.s
|
||||
|
||||
style()
|
||||
tpl(opts, keywords)
|
||||
|
||||
@@ -5,6 +5,7 @@ const CONFIG = {
|
||||
placeholder: 'Type to search',
|
||||
noData: 'No Results!',
|
||||
paths: 'auto',
|
||||
depth: 2,
|
||||
maxAge: 86400000 // 1 day
|
||||
}
|
||||
|
||||
@@ -19,12 +20,13 @@ const install = function (hook, vm) {
|
||||
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
|
||||
}
|
||||
|
||||
const isAuto = CONFIG.paths === 'auto'
|
||||
|
||||
hook.mounted(_ => {
|
||||
initComponet(CONFIG)
|
||||
initComponet(CONFIG, vm)
|
||||
!isAuto && initSearch(CONFIG, vm)
|
||||
})
|
||||
hook.doneEach(_ => {
|
||||
@@ -33,4 +35,4 @@ const install = function (hook, vm) {
|
||||
})
|
||||
}
|
||||
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins)
|
||||
$docsify.plugins = [].concat(install, $docsify.plugins)
|
||||
|
||||
@@ -14,18 +14,18 @@ function escapeHtml (string) {
|
||||
return String(string).replace(/[&<>"'\/]/g, s => entityMap[s])
|
||||
}
|
||||
|
||||
function getAllPaths () {
|
||||
function getAllPaths (router) {
|
||||
const paths = []
|
||||
|
||||
helper.dom.findAll('a:not([data-nosearch])')
|
||||
.map(node => {
|
||||
const href = node.href
|
||||
const originHref = node.getAttribute('href')
|
||||
const path = helper.route.parse(href).path
|
||||
const path = router.parse(href).path
|
||||
|
||||
if (path &&
|
||||
paths.indexOf(path) === -1 &&
|
||||
!helper.route.isAbsolutePath(originHref)) {
|
||||
!Docsify.util.isAbsolutePath(originHref)) {
|
||||
paths.push(path)
|
||||
}
|
||||
})
|
||||
@@ -38,16 +38,15 @@ function saveData (maxAge) {
|
||||
localStorage.setItem('docsify.search.index', JSON.stringify(INDEXS))
|
||||
}
|
||||
|
||||
export function genIndex (path, content = '') {
|
||||
export function genIndex (path, content = '', router, depth) {
|
||||
const tokens = window.marked.lexer(content)
|
||||
const slugify = window.Docsify.slugify
|
||||
const toURL = Docsify.route.toURL
|
||||
const index = {}
|
||||
let slug
|
||||
|
||||
tokens.forEach(token => {
|
||||
if (token.type === 'heading' && token.depth <= 2) {
|
||||
slug = toURL(path, { id: slugify(token.text) })
|
||||
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
|
||||
@@ -145,7 +144,7 @@ export function init (config, vm) {
|
||||
return
|
||||
}
|
||||
|
||||
const paths = isAuto ? getAllPaths() : config.paths
|
||||
const paths = isAuto ? getAllPaths(vm.router) : config.paths
|
||||
const len = paths.length
|
||||
let count = 0
|
||||
|
||||
@@ -153,9 +152,9 @@ export function init (config, vm) {
|
||||
if (INDEXS[path]) return count++
|
||||
|
||||
helper
|
||||
.get(vm.$getFile(path))
|
||||
.get(vm.router.getFile(path))
|
||||
.then(result => {
|
||||
INDEXS[path] = genIndex(path, result)
|
||||
INDEXS[path] = genIndex(path, result, vm.router, config.depth)
|
||||
len === ++count && saveData(config.maxAge)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -244,6 +244,10 @@ main {
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
|
||||
@@ -3,3 +3,4 @@ $color-bg: #fff;
|
||||
$color-text: #000;
|
||||
$sidebar-width: 300px;
|
||||
@import "basic/layout";
|
||||
@import "basic/coverpage";
|
||||
|
||||
Reference in New Issue
Block a user