mirror of
https://github.com/wahyd4/docsify.git
synced 2026-08-09 13:26:34 +10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f66e61f63 | ||
|
|
5f07d5a9f3 | ||
|
|
d1d8f88a1a | ||
|
|
b9a7275c8f | ||
|
|
0fddd1ced4 | ||
|
|
262bf13964 | ||
|
|
0b1fc2343f | ||
|
|
6eada5a2f7 | ||
|
|
86923d03d3 | ||
|
|
8b696cd99d | ||
|
|
3b30d42e9a | ||
|
|
50fa6fcb89 | ||
|
|
8463f4d5c5 | ||
|
|
9e7d365872 | ||
|
|
9e9ad57540 | ||
|
|
9c54bafae4 | ||
|
|
1aa6636ba8 | ||
|
|
723a6040f2 | ||
|
|
d6b5403982 | ||
|
|
9f0fc83b54 | ||
|
|
b02e1f1409 | ||
|
|
bca7b00c94 | ||
|
|
0ae14e8ddc | ||
|
|
61e0aacb43 | ||
|
|
b927a30cc6 | ||
|
|
0d59ee939f | ||
|
|
0aead898eb | ||
|
|
d3c9fbd124 | ||
|
|
f3fc596951 | ||
|
|
07a2a91296 | ||
|
|
8ad835ca26 | ||
|
|
0994663c5a | ||
|
|
5067769a65 | ||
|
|
92d6e8a1ee | ||
|
|
0dd9feffe5 | ||
|
|
82173627e5 | ||
|
|
507d9e834c | ||
|
|
83ae93cae0 | ||
|
|
8f9bf29ee5 | ||
|
|
d67d25fed4 | ||
|
|
95a324c7e0 | ||
|
|
5712c1f59d | ||
|
|
490a2cd64e | ||
|
|
b8a3d8f380 | ||
|
|
855c450a97 | ||
|
|
2521c58c73 | ||
|
|
8df746e9d1 | ||
|
|
2945e94e3c | ||
|
|
083cc4af56 | ||
|
|
5cab56cc92 | ||
|
|
d8ad679e2c | ||
|
|
f2975a5e5e | ||
|
|
58789bfec7 | ||
|
|
e7e519bad2 | ||
|
|
f7111b5903 | ||
|
|
42b2dba589 | ||
|
|
2a1157a706 | ||
|
|
3394ebb9a5 | ||
|
|
b4fc6a9d72 | ||
|
|
feb4b89461 | ||
|
|
83d7862505 | ||
|
|
75686f1624 | ||
|
|
780c1e580e | ||
|
|
35dd2e16fa | ||
|
|
be6dcacde7 | ||
|
|
066fff4beb | ||
|
|
42fb331079 | ||
|
|
f15e45c693 | ||
|
|
6b08546654 | ||
|
|
46ff5e14bf | ||
|
|
b51d714d3c | ||
|
|
2c9fdbe7f9 | ||
|
|
bf593a77ad | ||
|
|
3b127a161c | ||
|
|
20a83808f3 | ||
|
|
4419b2119e | ||
|
|
cd99b522e7 | ||
|
|
787656a1ee | ||
|
|
f573caa3c6 | ||
|
|
0455106a62 | ||
|
|
74ce0bf588 | ||
|
|
d355bb4ebe | ||
|
|
dbb92782cf | ||
|
|
754f92ce8e | ||
|
|
fcb66e8bc7 | ||
|
|
2efd859f71 | ||
|
|
515331763d | ||
|
|
2351c3e68c | ||
|
|
079bd00395 | ||
|
|
86594a3118 | ||
|
|
a6d823b826 | ||
|
|
7b6a2ac404 | ||
|
|
3e7d6ab26c | ||
|
|
4b64386465 | ||
|
|
c7e09c34a7 | ||
|
|
c108645e34 | ||
|
|
b7768b1b3c | ||
|
|
fd9c3bd19d | ||
|
|
e2b7b976cf | ||
|
|
8cae16539d | ||
|
|
27e7e749af | ||
|
|
fbd51afdcb | ||
|
|
fe88c154b0 | ||
|
|
30da0d5d46 | ||
|
|
8bee8f0213 | ||
|
|
aad62b65f5 | ||
|
|
e07d36f44e | ||
|
|
5dcd6d43ea | ||
|
|
00e3609b25 | ||
|
|
a6d9669bfa | ||
|
|
94255e22b1 | ||
|
|
00983ab796 | ||
|
|
8e203b07ab | ||
|
|
eff6d21539 | ||
|
|
dc536a3930 |
@@ -4,6 +4,7 @@
|
||||
"browser": true
|
||||
},
|
||||
"globals": {
|
||||
"Docsify": true,
|
||||
"$docsify": true
|
||||
}
|
||||
}
|
||||
|
||||
+72
-75
@@ -1,82 +1,79 @@
|
||||
### 2.4.1
|
||||
|
||||
> 2017-02-13
|
||||
# 3.4.1 / 2017-03-10
|
||||
|
||||
#### Bug fixes
|
||||
- fix(index): cover page
|
||||
* 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)
|
||||
|
||||
### 2.4.0
|
||||
# 3.4.0 / 2017-03-09
|
||||
|
||||
> 2017-02-13
|
||||
* feat(zoom-image): add plugin
|
||||
|
||||
# 3.3.0 / 2017-03-07
|
||||
|
||||
* 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))
|
||||
|
||||
# 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
|
||||
|
||||
* fix(search): dont search nameLink, fixed [#102](https://github.com/QingWei-Li/docsify/issues/102)
|
||||
|
||||
# 3.1.1 / 2017-02-24
|
||||
|
||||
* 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)
|
||||
|
||||
# 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
|
||||
|
||||
* 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
|
||||
|
||||
* fix(render): execute script
|
||||
* fix(render): disable rendering sub list when loadSidebar is false
|
||||
|
||||
# 3.0.3 / 2017-02-19
|
||||
|
||||
* fixed look of links in blockquote
|
||||
* fix(scroll) highlight bug
|
||||
|
||||
# 3.0.2 / 2017-02-19
|
||||
|
||||
* fix(search): add lazy input
|
||||
* fix(compiler): link
|
||||
|
||||
# 3.0.1 / 2017-02-19
|
||||
|
||||
* fix(route): empty alias
|
||||
|
||||
# 3.0.0 / 2017-02-19
|
||||
|
||||
#### Breaking change
|
||||
|
||||
* Not support IE9
|
||||
* The route becomes: `/#/page?id=slug`. The previous route will be redirected
|
||||
|
||||
#### Features
|
||||
|
||||
- feat(hook): add `doneEach`
|
||||
|
||||
|
||||
### 2.3.0
|
||||
|
||||
> 2017-02-13
|
||||
|
||||
#### Features
|
||||
|
||||
- feat(src): add alias feature
|
||||
- docs: update all documents
|
||||
- feat(src): dynamic title
|
||||
- feat(hook): support custom plugin
|
||||
- feat(themes): add dark theme
|
||||
|
||||
#### Bug fixes
|
||||
- fix(event): `auto2top` has no effect on a FF mobile browser, fixed #67
|
||||
- fix: sidebar style
|
||||
- fix(render): fix render link
|
||||
|
||||
### 2.2.1
|
||||
|
||||
> 2017-02-11
|
||||
|
||||
#### Bug fixes
|
||||
- fix(search): crash when not content, fixed #68
|
||||
- fix(event): scroll active sidebar
|
||||
- fix(search): not work in mobile
|
||||
|
||||
### 2.2.0
|
||||
|
||||
#### Features
|
||||
- Add `Google Analytics` plugin.
|
||||
```html
|
||||
<script src="//unpkg.com/docsify" data-ga="UA-XXXXX-Y"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/ga.js"></script>
|
||||
```
|
||||
|
||||
### 2.1.0
|
||||
#### Features
|
||||
- Add search plugin
|
||||
```html
|
||||
<script src="//unpkg.com/docsify"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.js"></script>
|
||||
```
|
||||
|
||||
#### Bug fixes
|
||||
- fix sidebar style
|
||||
|
||||
### 2.0.3
|
||||
#### Bug fixes
|
||||
- fix: rendering emojis
|
||||
- fix: css var polyfill
|
||||
|
||||
### 2.0.2
|
||||
|
||||
#### Bug fixes
|
||||
- fix button style in cover page.
|
||||
|
||||
### 2.0.1
|
||||
#### Bug fixes
|
||||
- border style.
|
||||
|
||||
### 2.0.0
|
||||
#### Features
|
||||
- Customize the theme color
|
||||
|
||||
#### Break change
|
||||
- Remove `data-router`, `data-sidebar`, `data-sidebar-toggle` APIs
|
||||
* 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`)
|
||||
|
||||
+314
-89
@@ -1,287 +1,512 @@
|
||||
### 1.10.5
|
||||
### 2.4.3
|
||||
|
||||
> 2017-02-15
|
||||
|
||||
#### Bug fixes
|
||||
- fix initialize the Vue instance
|
||||
|
||||
* fix emoji replacing error ([#76](https://github.com/QingWei-Li/docsify/issues/76))
|
||||
|
||||
### 2.4.2
|
||||
|
||||
> 2017-02-14
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
* fix(index): load file path error
|
||||
|
||||
### 2.4.1
|
||||
|
||||
> 2017-02-13
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
* fix(index): cover page
|
||||
|
||||
### 2.4.0
|
||||
|
||||
> 2017-02-13
|
||||
|
||||
#### Features
|
||||
|
||||
* feat(hook): add `doneEach`
|
||||
|
||||
### 2.3.0
|
||||
|
||||
> 2017-02-13
|
||||
|
||||
#### Features
|
||||
|
||||
* feat(src): add alias feature
|
||||
* docs: update all documents
|
||||
* feat(src): dynamic title
|
||||
* feat(hook): support custom plugin
|
||||
* feat(themes): add dark theme
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
* fix(event): `auto2top` has no effect on a FF mobile browser, fixed #67
|
||||
* fix: sidebar style
|
||||
* fix(render): fix render link
|
||||
|
||||
### 2.2.1
|
||||
|
||||
> 2017-02-11
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
* fix(search): crash when not content, fixed [#68](https://github.com/QingWei-Li/docsify/issues/68)
|
||||
* fix(event): scroll active sidebar
|
||||
* fix(search): not work in mobile
|
||||
|
||||
### 2.2.0
|
||||
|
||||
#### Features
|
||||
|
||||
* Add `Google Analytics` plugin.
|
||||
```html
|
||||
<script src="//unpkg.com/docsify" data-ga="UA-XXXXX-Y"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/ga.js"></script>
|
||||
```
|
||||
|
||||
### 2.1.0
|
||||
|
||||
#### Features
|
||||
|
||||
* Add search plugin
|
||||
```html
|
||||
<script src="//unpkg.com/docsify"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.js"></script>
|
||||
```
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
* fix sidebar style
|
||||
|
||||
### 2.0.3
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
* fix: rendering emojis
|
||||
* fix: css var polyfill
|
||||
|
||||
### 2.0.2
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
* fix button style in cover page.
|
||||
|
||||
### 2.0.1
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
* border style.
|
||||
|
||||
### 2.0.0
|
||||
|
||||
#### Features
|
||||
|
||||
* Customize the theme color
|
||||
|
||||
#### Break change
|
||||
|
||||
* Remove `data-router`, `data-sidebar`, `data-sidebar-toggle` APIs
|
||||
|
||||
|
||||
### 1.10.5
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
* fix initialize the Vue instance
|
||||
|
||||
### 1.10.4
|
||||
|
||||
#### Bug fixes
|
||||
- fix execute script
|
||||
|
||||
* fix execute script
|
||||
|
||||
### 1.10.3
|
||||
|
||||
#### Bug fixes
|
||||
- compatible vuep QingWei-Li/vuep/issues/2
|
||||
- fix sidebar scroll, fixed #63
|
||||
|
||||
* compatible vuep ([#2](https://github.com/QingWei-Li/vuep/issues/2))
|
||||
* fix sidebar scroll, fixed [#63](https://github.com/QingWei-Li/docsify/issues/63)
|
||||
|
||||
### 1.10.2
|
||||
|
||||
#### Bug fixes
|
||||
- Fix render emojis again
|
||||
|
||||
* Fix render emojis again
|
||||
|
||||
### 1.10.1
|
||||
|
||||
#### Bug fixes
|
||||
- Fix render emojis
|
||||
|
||||
* Fix render emojis
|
||||
|
||||
### 1.10.0
|
||||
|
||||
#### Features
|
||||
- Support emoji :laughing:
|
||||
|
||||
* Support emoji :laughing:
|
||||
|
||||
### 1.9.0
|
||||
|
||||
#### Bug fixes
|
||||
- Destroys the vue instance when the route is changed
|
||||
|
||||
* Destroys the vue instance when the route is changed
|
||||
|
||||
#### Features
|
||||
- Add `!>` and `?>` doc helper.
|
||||
|
||||
* Add `!>` and `?>` doc helper.
|
||||
|
||||
#### Break change
|
||||
- Remove `!` doc helper.
|
||||
|
||||
* Remove `!` doc helper.
|
||||
|
||||
### 1.8.0
|
||||
|
||||
#### Bug fixes
|
||||
- Using `v-pre` skip compilation.
|
||||
|
||||
* Using `v-pre` skip compilation.
|
||||
|
||||
### Features
|
||||
- Execute script when vue exists.
|
||||
|
||||
* Execute script when vue exists.
|
||||
|
||||
### 1.7.4
|
||||
|
||||
#### Bug fixes
|
||||
- Fix bugs caused by the previous version
|
||||
|
||||
* Fix bugs caused by the previous version
|
||||
|
||||
### 1.7.3
|
||||
|
||||
#### Bug fixes
|
||||
- Add `hr` style
|
||||
- Fixed option is an empty string
|
||||
|
||||
* Add `hr` style
|
||||
* Fixed option is an empty string
|
||||
|
||||
### 1.7.2
|
||||
|
||||
#### Bug fixes
|
||||
- Fix sidebar click event in mobile browser.
|
||||
|
||||
* Fix sidebar click event in mobile browser.
|
||||
|
||||
### 1.7.1
|
||||
|
||||
#### Bug fixes
|
||||
- Fix sidebar style in mobile browser.
|
||||
|
||||
* Fix sidebar style in mobile browser.
|
||||
|
||||
### 1.7.0
|
||||
|
||||
#### Bug fixes
|
||||
- Fixed custom cover background, fixed #52
|
||||
- Fixed sticky sidebar
|
||||
|
||||
* Fixed custom cover background, fixed [#52](https://github.com/QingWei-Li/docsify/issues/52)
|
||||
* Fixed sticky sidebar
|
||||
|
||||
### Features
|
||||
- Add `name` and `nameLink`
|
||||
|
||||
* Add `name` and `nameLink`
|
||||
|
||||
### 1.6.1
|
||||
|
||||
#### Bug fixes
|
||||
- Fixed sidebar bug when the coverpage exist
|
||||
|
||||
* Fixed sidebar bug when the coverpage exist
|
||||
|
||||
### 1.6.0
|
||||
|
||||
#### Features
|
||||
- Improve sidebar performance. The active item is automatically scrolled in the visible view.
|
||||
- New doc helper: `! `. e.g. `! content` will be rendered as `<p class="tip">content</p>`
|
||||
|
||||
* Improve sidebar performance. The active item is automatically scrolled in the visible view.
|
||||
* New doc helper: `! `. e.g. `! content` will be rendered as `<p class="tip">content</p>`
|
||||
|
||||
### 1.5.2
|
||||
|
||||
#### Bug fixes
|
||||
- Fixed number at the beginning of the slug
|
||||
|
||||
* Fixed number at the beginning of the slug
|
||||
|
||||
### 1.5.1
|
||||
|
||||
#### Bug fixes
|
||||
- Remove HTML tag when handling slug
|
||||
|
||||
* Remove HTML tag when handling slug
|
||||
|
||||
### 1.5.0
|
||||
|
||||
#### Bug fixes
|
||||
- Fix slugify.
|
||||
- Fix nav highlight.
|
||||
|
||||
* Fix slugify.
|
||||
* Fix nav highlight.
|
||||
|
||||
#### Features
|
||||
- Initialize the configuration by `window.$docsify`.
|
||||
- Markdown parser is configurable.
|
||||
|
||||
* Initialize the configuration by `window.$docsify`.
|
||||
* Markdown parser is configurable.
|
||||
|
||||
### 1.4.3
|
||||
|
||||
#### Bug fixes
|
||||
- Tweak style.
|
||||
|
||||
* Tweak style.
|
||||
|
||||
### 1.4.2
|
||||
|
||||
#### Bug fixes
|
||||
- Fix toggle button style.
|
||||
- Support `mailto`, `tel`, etc. href type
|
||||
- Fix scroll to top.
|
||||
|
||||
* Fix toggle button style.
|
||||
* Support `mailto`, `tel`, etc. href type
|
||||
* Fix scroll to top.
|
||||
|
||||
### 1.4.1
|
||||
|
||||
#### Bug fixes
|
||||
- Fix generate slug.
|
||||
|
||||
* Fix generate slug.
|
||||
|
||||
### 1.4.0 Happly new year 🎉
|
||||
|
||||
#### Features
|
||||
- Display TOC in the custom sidebar, `data-sub-max-level`.
|
||||
- Custom background in coverpage.
|
||||
|
||||
* Display TOC in the custom sidebar, `data-sub-max-level`.
|
||||
* Custom background in coverpage.
|
||||
|
||||
#### Bug fixes
|
||||
- Fix scroll highlight when Vue exist.
|
||||
|
||||
* Fix scroll highlight when Vue exist.
|
||||
|
||||
### 1.3.5
|
||||
|
||||
#### Bug fixes
|
||||
- Fix vue
|
||||
|
||||
* Fix vue
|
||||
|
||||
### 1.3.4
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
- Supports [vuep](https://github.com/QingWei-Li/vuep)
|
||||
* Supports [vuep](https://github.com/QingWei-Li/vuep)
|
||||
|
||||
### 1.3.3
|
||||
|
||||
#### Bug fixes
|
||||
- Fixed cover rendering timing
|
||||
|
||||
* Fixed cover rendering timing
|
||||
|
||||
### 1.3.2
|
||||
|
||||
#### Bug fixes
|
||||
- Fixed render link
|
||||
|
||||
* Fixed render link
|
||||
|
||||
### 1.3.1
|
||||
|
||||
#### Bug fixes
|
||||
- Fixed cover page style
|
||||
- Generate the correct link when rendering the article
|
||||
|
||||
* Fixed cover page style
|
||||
* Generate the correct link when rendering the article
|
||||
|
||||
### 1.3.0
|
||||
|
||||
#### Features
|
||||
- Add cover page
|
||||
- add `<kbd>` style
|
||||
- headling can be cliked
|
||||
|
||||
* Add cover page
|
||||
* add `<kbd>` style
|
||||
* headling can be cliked
|
||||
|
||||
#### Bug fixes
|
||||
- sidebar highlight
|
||||
|
||||
* sidebar highlight
|
||||
|
||||
#### break change
|
||||
- Navbar no longer fixed at the top
|
||||
|
||||
* Navbar no longer fixed at the top
|
||||
|
||||
### 1.2.0
|
||||
|
||||
#### Features
|
||||
- custom basePath
|
||||
- custom homepage
|
||||
|
||||
* custom basePath
|
||||
* custom homepage
|
||||
|
||||
### 1.1.7
|
||||
|
||||
#### Bug fixes
|
||||
- Optimize progress bar
|
||||
|
||||
* Optimize progress bar
|
||||
|
||||
### 1.1.6
|
||||
|
||||
#### Features
|
||||
- Add logo 😂
|
||||
|
||||
* Add logo 😂
|
||||
|
||||
#### Bug fixes
|
||||
- Remove table background color
|
||||
- Fixed highlight sidebar using chinese ids
|
||||
|
||||
* Remove table background color
|
||||
* Fixed highlight sidebar using chinese ids
|
||||
|
||||
### 1.1.5
|
||||
|
||||
#### Features
|
||||
|
||||
- Add table style
|
||||
|
||||
#### Bug fixes
|
||||
- Not fixed position of hte navbar in the mobile browser
|
||||
- Correct calculation of whether the mobile browser
|
||||
|
||||
* Not fixed position of hte navbar in the mobile browser
|
||||
* Correct calculation of whether the mobile browser
|
||||
|
||||
### 1.1.4
|
||||
|
||||
#### Bug fixes
|
||||
- Fixed chinese auchor link
|
||||
|
||||
* Fixed chinese auchor link
|
||||
|
||||
### 1.1.3
|
||||
|
||||
#### Bug fixes
|
||||
- Optimize progress bar again
|
||||
|
||||
* Optimize progress bar again
|
||||
|
||||
### 1.1.2
|
||||
|
||||
#### Bug fixes
|
||||
- fix failed `auto2top` in mobile
|
||||
|
||||
* fix failed `auto2top` in mobile
|
||||
|
||||
|
||||
### 1.1.1
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
- Optimize progress bar
|
||||
|
||||
### 1.1.0
|
||||
|
||||
#### Features
|
||||
- Add progress bar
|
||||
- Add `auto2top` option for hash router
|
||||
|
||||
* Add progress bar
|
||||
* Add `auto2top` option for hash router
|
||||
|
||||
### 1.0.3
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
- Fix cache
|
||||
|
||||
### 1.0.2
|
||||
|
||||
#### Bug fixes
|
||||
- Fix binding events bug, fixed #24
|
||||
- Fix regular expression, fixed #23
|
||||
|
||||
* Fix binding events bug, fixed [#24](https://github.com/QingWei-Li/docsify/issues/24)
|
||||
* Fix regular expression, fixed [#23](https://github.com/QingWei-Li/docsify/issues/23)
|
||||
|
||||
### 1.0.1
|
||||
|
||||
#### Bug fixes
|
||||
- `img` style
|
||||
|
||||
* `img` style
|
||||
|
||||
### 1.0.0
|
||||
|
||||
#### Features
|
||||
- Support hash router
|
||||
|
||||
* Support hash router
|
||||
|
||||
#### Bug fixes
|
||||
- Improved scrolling on mobile
|
||||
|
||||
* Improved scrolling on mobile
|
||||
|
||||
### 0.7.0
|
||||
|
||||
#### Breaking change
|
||||
- `themes/` was removed, only exists in the npm package.
|
||||
|
||||
* `themes/` was removed, only exists in the npm package.
|
||||
|
||||
#### Bug fixes
|
||||
- Fix style.
|
||||
- Fix sidebar animation again.
|
||||
|
||||
* Fix style.
|
||||
* Fix sidebar animation again.
|
||||
|
||||
### 0.6.1
|
||||
|
||||
#### Bug fixes
|
||||
- In the mobile, it should collapse the sidebar when toggle is clicked.
|
||||
- Fix the dropdown list style.
|
||||
- Fix sidebar animation.
|
||||
|
||||
* In the mobile, it should collapse the sidebar when toggle is clicked.
|
||||
* Fix the dropdown list style.
|
||||
* Fix sidebar animation.
|
||||
|
||||
### 0.6.0
|
||||
|
||||
#### Features
|
||||
- Navbar support dropdown list, #6
|
||||
- Sidebar with toggle
|
||||
|
||||
* Navbar support dropdown list, [#6](https://github.com/QingWei-Li/docsify/issues/6)
|
||||
* Sidebar with toggle
|
||||
|
||||
#### Bug fixes
|
||||
- Fix ineffective option, fixed #10
|
||||
|
||||
* Fix ineffective option, fixed [#10](https://github.com/QingWei-Li/docsify/issues/10)
|
||||
|
||||
### 0.5.0
|
||||
|
||||
#### Features
|
||||
- Custom sidebars and navbars by markdown file
|
||||
|
||||
* Custom sidebars and navbars by markdown file
|
||||
|
||||
### 0.4.2
|
||||
|
||||
#### Bug fixes
|
||||
- Correct catch ajax error
|
||||
|
||||
* Correct catch ajax error
|
||||
|
||||
### 0.4.1
|
||||
|
||||
#### Bug fixes
|
||||
- catch ajax error
|
||||
|
||||
* catch ajax error
|
||||
|
||||
### 0.4.0
|
||||
|
||||
#### Features
|
||||
- Custom sidebar
|
||||
|
||||
* Custom sidebar
|
||||
|
||||
#### Bug fixes
|
||||
- Fix undefined language
|
||||
|
||||
* Fix undefined language
|
||||
|
||||
### 0.3.1
|
||||
|
||||
#### Bug fixes
|
||||
- Strip HTML tag when rendering the headings
|
||||
|
||||
* Strip HTML tag when rendering the headings
|
||||
|
||||
### 0.3.0
|
||||
|
||||
#### Features
|
||||
- Add minified css files
|
||||
- Add max level option
|
||||
- Add pure.css
|
||||
|
||||
* Add minified css files
|
||||
* Add max level option
|
||||
* Add pure.css
|
||||
|
||||
### 0.2.1
|
||||
|
||||
#### Bug fixes
|
||||
- Fix vue.css
|
||||
|
||||
* Fix vue.css
|
||||
|
||||
### 0.2.0
|
||||
|
||||
#### Bug fixes
|
||||
- Fix route
|
||||
- Remove dynamic title
|
||||
|
||||
* Fix route
|
||||
* Remove dynamic title
|
||||
|
||||
### 0.1.0
|
||||
|
||||
#### Features
|
||||
- Add buble.css
|
||||
|
||||
* Add buble.css
|
||||
|
||||
@@ -15,23 +15,26 @@
|
||||
</p>
|
||||
|
||||
## Links
|
||||
|
||||
- [Documentation](https://docsify.js.org)
|
||||
- [CLI](https://github.com/QingWei-Li/docsify-cli)
|
||||
|
||||
## Features
|
||||
- Not build static html files
|
||||
- Simple and lightweight (~13kB gzipped)
|
||||
|
||||
- No statically built html files
|
||||
- Simple and lightweight (~16kB gzipped)
|
||||
- Smart full-text search plugin
|
||||
- Multiple themes
|
||||
- Useful plugin API
|
||||
- Compatible with IE9+
|
||||
- Compatible with IE10+
|
||||
|
||||
## Quick start
|
||||
Create a `index.html`.
|
||||
|
||||
index.html
|
||||
Create an `index.html`.
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
@@ -47,21 +50,27 @@ index.html
|
||||
|
||||
## Browser Support
|
||||
|
||||
Modern browsers and Internet Explorer 9+.
|
||||
Modern browsers and Internet Explorer 10+.
|
||||
|
||||
## Showcase
|
||||
These open-source projects are using docsify to generate their sites. Pull requests welcome : )
|
||||
|
||||
- [Snipaste](https://docs.snipaste.com/) - A new way to boost your productivity.
|
||||
- [puck](https://puck.zz173.com/) - A small & magical php framework.
|
||||
- [Samaritan](http://samaritan.stockdb.org) - An Algorithmic Trading Framework for Digital Currency.
|
||||
- [Vudash](http://vudash.github.io/vudash/) - Powerful, Flexible, Open Source dashboards for anything
|
||||
- [Trilogy](http://trilogy.js.org) - No-hassle SQLite with a Promise-based, document store style API.
|
||||
- [Mybatis-Plus](http://mp.baomidou.com/) - An enhanced toolkit of Mybatis to simplify development
|
||||
These open-source projects are using docsify to generate their sites. Pull requests welcome :blush:
|
||||
|
||||
| Project | Description |
|
||||
|---|---|
|
||||
| [Snipaste](https://docs.snipaste.com/) | Snip & Paste |
|
||||
| [puck](https://puck.zz173.com/) | A small & magical php framework. |
|
||||
| [Samaritan](http://samaritan.stockdb.org) | An Algorithmic Trading Framework for Digital Currency. |
|
||||
| [Vudash](http://vudash.github.io/vudash/) | Powerful, Flexible, Open Source dashboards for anything |
|
||||
| [Trilogy](http://trilogy.js.org) | No-hassle SQLite with a Promise-based, document store style API. |
|
||||
| [Mybatis-Plus](http://mp.baomidou.com/) | An enhanced toolkit of Mybatis to simplify development |
|
||||
|
||||
## Similar projects
|
||||
- [docute](https://github.com/egoist/docute) - 📜 Effortlessly documentation done right
|
||||
- [docpress](https://github.com/docpress/docpress) - Documentation website generator
|
||||
|
||||
| Project | Description |
|
||||
|---|---|
|
||||
| [docute](https://github.com/egoist/docute) | 📜 Effortlessly documentation done right |
|
||||
| [docpress](https://github.com/docpress/docpress) | Documentation website generator |
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -69,7 +78,7 @@ These open-source projects are using docsify to generate their sites. Pull reque
|
||||
- Create your feature branch: `git checkout -b my-new-feature`
|
||||
- Commit your changes: `git commit -am 'Add some feature'`
|
||||
- Push to the branch: `git push origin my-new-feature`
|
||||
- Submit a pull request :D
|
||||
- Submit a pull request
|
||||
|
||||
|
||||
## Development
|
||||
@@ -80,4 +89,5 @@ open http://localhost:3000
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
+41
-30
@@ -2,6 +2,7 @@ var rollup = require('rollup')
|
||||
var buble = require('rollup-plugin-buble')
|
||||
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 isProd = process.argv[process.argv.length - 1] !== '--dev'
|
||||
|
||||
@@ -9,7 +10,12 @@ var build = function (opts) {
|
||||
rollup
|
||||
.rollup({
|
||||
entry: 'src/' + opts.entry,
|
||||
plugins: [buble()].concat(opts.plugins || [])
|
||||
plugins: (opts.plugins || []).concat([
|
||||
string({ include: '**/*.css' }),
|
||||
buble(),
|
||||
commonjs(),
|
||||
nodeResolve()
|
||||
])
|
||||
})
|
||||
.then(function (bundle) {
|
||||
var dest = 'lib/' + (opts.output || opts.entry)
|
||||
@@ -27,34 +33,39 @@ var build = function (opts) {
|
||||
}
|
||||
|
||||
build({
|
||||
entry: 'index.js',
|
||||
output: 'docsify.js',
|
||||
plugins: [commonjs(), nodeResolve()]
|
||||
entry: 'core/index.js',
|
||||
output: 'docsify.js'
|
||||
})
|
||||
isProd && build({
|
||||
entry: 'index.js',
|
||||
output: 'docsify.min.js',
|
||||
plugins: [commonjs(), nodeResolve(), uglify()]
|
||||
})
|
||||
build({
|
||||
entry: 'plugins/search.js',
|
||||
output: 'plugins/search.js',
|
||||
moduleName: 'D.Search'
|
||||
})
|
||||
isProd && build({
|
||||
entry: 'plugins/search.js',
|
||||
output: 'plugins/search.min.js',
|
||||
moduleName: 'D.Search',
|
||||
plugins: [uglify()]
|
||||
})
|
||||
build({
|
||||
entry: 'plugins/ga.js',
|
||||
output: 'plugins/ga.js',
|
||||
moduleName: 'D.GA'
|
||||
})
|
||||
isProd && build({
|
||||
entry: 'plugins/ga.js',
|
||||
output: 'plugins/ga.min.js',
|
||||
moduleName: 'D.GA',
|
||||
plugins: [uglify()]
|
||||
|
||||
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' }
|
||||
]
|
||||
|
||||
plugins.forEach(item => {
|
||||
build({
|
||||
entry: 'plugins/' + item.entry,
|
||||
output: 'plugins/' + item.name + '.js',
|
||||
moduleName: 'D.' + item.moduleName
|
||||
})
|
||||
})
|
||||
|
||||
if (isProd) {
|
||||
build({
|
||||
entry: 'core/index.js',
|
||||
output: 'docsify.min.js',
|
||||
plugins: [uglify()]
|
||||
})
|
||||
plugins.forEach(item => {
|
||||
build({
|
||||
entry: 'plugins/' + item.entry,
|
||||
output: 'plugins/' + item.name + '.min.js',
|
||||
moduleName: 'D.' + item.moduleName,
|
||||
plugins: [uglify()]
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
<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">
|
||||
<link rel="stylesheet" href="/themes/vue.css" title="vue">
|
||||
<link rel="stylesheet" href="/themes/dark.css" title="dark" disabled>
|
||||
<link rel="stylesheet" href="/themes/buble.css" title="buble" disabled>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<nav data-cloak>
|
||||
<a href="#/">EN</a>
|
||||
<a href="#/zh-cn/">中文</a>
|
||||
</nav>
|
||||
@@ -19,16 +21,14 @@
|
||||
'/zh-cn/changelog': '/changelog',
|
||||
'/changelog': 'https://raw.githubusercontent.com/QingWei-Li/docsify/master/CHANGELOG'
|
||||
},
|
||||
search: {
|
||||
maxAge: 0
|
||||
}
|
||||
executeScript: true
|
||||
}
|
||||
</script>
|
||||
<script
|
||||
src="/lib/docsify.js"
|
||||
data-name="docsify"
|
||||
data-base-path="/docs/"
|
||||
data-load-sidebar
|
||||
data-sub-max-level="2"
|
||||
data-base-path="docs/"
|
||||
data-auto2top></script>
|
||||
</html>
|
||||
|
||||
+10
-10
@@ -4,24 +4,24 @@
|
||||
|
||||
## What is it
|
||||
|
||||
docsify generates your documentation website on the fly. Unlike GitBook, it does not generate static html files. It smartly loads and parses your Markdown files and displays them in website. All you need to do is create an `index.html` to start and [deploy it on GitHub Pages](/deploy).
|
||||
docsify generates your documentation website on the fly. Unlike GitBook, it does not generate static html files. Instead, it smartly loads and parses your Markdown files and displays them as website. All you need to do is create an `index.html` to start and [deploy it on GitHub Pages](/deploy).
|
||||
|
||||
See the [Quick start](/quickstart) for more details.
|
||||
|
||||
## Features
|
||||
|
||||
- Not build static html files
|
||||
- Simple and lightweight (~13kB gzipped)
|
||||
- Smart full-text search plugin
|
||||
- Multiple themes
|
||||
- Useful plugin API
|
||||
- Compatible with IE9+
|
||||
* No statically built html files
|
||||
* Simple and lightweight (~16kB gzipped)
|
||||
* Smart full-text search plugin
|
||||
* Multiple themes
|
||||
* Useful plugin API
|
||||
* Emoji support
|
||||
* Compatible with IE10+
|
||||
|
||||
## Examples
|
||||
|
||||
Check out the [Showcase](https://github.com/QingWei-Li/docsify/#showcase) to see use the docsify generated website.
|
||||
Check out the [Showcase](https://github.com/QingWei-Li/docsify/#showcase) to docsify in use.
|
||||
|
||||
## Donate
|
||||
|
||||
If you think docsify is helpful to you or that my work is valuable. I am happy if you can help me [buy a cup of coffee](https://github.com/QingWei-Li/donate). :heart:
|
||||
|
||||
Please consider donating if you think docsify is helpful to you or that my work is valuable. I am happy if you can help me [buy a cup of coffee](https://github.com/QingWei-Li/donate). :heart:
|
||||
|
||||
+4
-4
@@ -1,13 +1,13 @@
|
||||

|
||||
|
||||
# docsify <small>2.4.1</small>
|
||||
# docsify <small>3.4</small>
|
||||
|
||||
> A magical documentation site generator.
|
||||
|
||||
- Simple and lightweight (~13kB gzipped)
|
||||
- Not build static html files
|
||||
- Simple and lightweight (~16kB gzipped)
|
||||
- No statically built html files
|
||||
- Multiple themes
|
||||
|
||||
|
||||
[GitHub](https://github.com/QingWei-Li/docsify/)
|
||||
[Get Started](#quick-start)
|
||||
[Get Started](#docsify)
|
||||
|
||||
+14
-12
@@ -1,20 +1,22 @@
|
||||
- Getting started
|
||||
- [Quick start](/quickstart)
|
||||
- [Writing more pages](/more-pages)
|
||||
- [Custom navbar](/custom-navbar)
|
||||
- [Cover page](/cover)
|
||||
- [Quick start](/quickstart)
|
||||
- [Writing more pages](/more-pages)
|
||||
- [Custom navbar](/custom-navbar)
|
||||
- [Cover page](/cover)
|
||||
|
||||
- Configuration
|
||||
- Customization
|
||||
- [Configuration](/configuration)
|
||||
- [Themes](/themes)
|
||||
- [Using plugins](/plugins)
|
||||
- [List of Plugins](/plugins)
|
||||
- [Write a Plugin](/write-a-plugin)
|
||||
- [Markdown configuration](/markdown)
|
||||
- [Lanuage highlight](/language-highlight)
|
||||
- [Language highlighting](/language-highlight)
|
||||
|
||||
- Guide
|
||||
- [Deploy](/deploy)
|
||||
- [Doc helper](/helpers)
|
||||
- [Compatible Vue](/vue)
|
||||
- [CDN](/cdn)
|
||||
- [Deploy](/deploy)
|
||||
- [Helpers](/helpers)
|
||||
- [Vue compatibility](/vue)
|
||||
- [CDN](/cdn)
|
||||
- [Offline Mode(PWA)](/pwa)
|
||||
|
||||
- [Changelog](/changelog)
|
||||
- [Changelog](/changelog)
|
||||
|
||||
+10
-5
@@ -2,10 +2,8 @@
|
||||
|
||||
Recommended: [unpkg](//unpkg.com), which will reflect the latest version as soon as it is published to npm. You can also browse the source of the npm package at [unpkg.com/docsify/](//unpkg.com/docsify/).
|
||||
|
||||
|
||||
## Latest version
|
||||
|
||||
|
||||
```html
|
||||
<!-- load css -->
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/themes/vue.css">
|
||||
@@ -14,8 +12,9 @@ Recommended: [unpkg](//unpkg.com), which will reflect the latest version as soon
|
||||
<script src="//unpkg.com/docsify/lib/docsify.js"></script>
|
||||
```
|
||||
|
||||
## Specific version
|
||||
Alternatively, use [compressed files](#compressed-files).
|
||||
|
||||
## Specific version
|
||||
|
||||
```html
|
||||
<!-- load css -->
|
||||
@@ -27,7 +26,6 @@ Recommended: [unpkg](//unpkg.com), which will reflect the latest version as soon
|
||||
|
||||
## Compressed file
|
||||
|
||||
|
||||
```html
|
||||
<!-- load css -->
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
|
||||
@@ -36,7 +34,14 @@ Recommended: [unpkg](//unpkg.com), which will reflect the latest version as soon
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- load css -->
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify@2.0.0/lib/themes/vue.css">
|
||||
|
||||
<!-- load script -->
|
||||
<script src="//unpkg.com/docsify@2.0.0/lib/docsify.min.js"></script>
|
||||
```
|
||||
|
||||
## Other CDN
|
||||
|
||||
[jsDelivr](http://www.jsdelivr.com/projects/docsify) is available.
|
||||
|
||||
|
||||
+61
-20
@@ -1,6 +1,6 @@
|
||||
# Configuration
|
||||
|
||||
docsify supports two ways to configure. You can configure the `window.$docsify` or write configuration on the script tag via `data-*` attributes.
|
||||
**docsify** supports two different ways of configuration. You can configure the `window.$docsify` or write configuration on the script tag via `data-*` attributes.
|
||||
|
||||
```html
|
||||
<!-- by $docsify -->
|
||||
@@ -53,7 +53,6 @@ window.$docsify = {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## max-level
|
||||
|
||||
- Type: `Number`
|
||||
@@ -72,7 +71,7 @@ window.$docsify = {
|
||||
- Type: `Boolean|String`
|
||||
- Default: `false`
|
||||
|
||||
Load navbar from Markdown file. If **true** it will be loaded from `_navbar.md`.
|
||||
Loads navbar from the Markdown file `_navbar.md` if **true**, or else from the path specified.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
@@ -89,8 +88,7 @@ window.$docsify = {
|
||||
- Type: `Boolean|String`
|
||||
- Default: `false`
|
||||
|
||||
|
||||
Load sidebar from Markdown file. If **true** it will be loaded from `_sidebar.md`.
|
||||
Loads sidebar from the Markdown file `_sidebar.md` if **true**, or else from the path specified.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
@@ -107,21 +105,19 @@ window.$docsify = {
|
||||
- Type: `Number`
|
||||
- Default: `0`
|
||||
|
||||
Add TOC in custom sidebar.
|
||||
Add table of contents (TOC) in custom sidebar.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
subMaxLevel: 3
|
||||
subMaxLevel: 2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## auto2top
|
||||
|
||||
- Type: `Boolean`
|
||||
- Default: `false`
|
||||
|
||||
|
||||
Scrolls to the top of the screen when the route is changed.
|
||||
|
||||
```js
|
||||
@@ -130,13 +126,11 @@ window.$docsify = {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## homepage
|
||||
|
||||
- Type: `String`
|
||||
- Default: `README.md`
|
||||
|
||||
|
||||
`README.md` in your docs folder will be treated as homepage for your website, but sometimes you may need to serve another file as your homepage.
|
||||
|
||||
```js
|
||||
@@ -167,13 +161,12 @@ window.$docsify = {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## coverpage
|
||||
|
||||
- Type: `Boolean|String`
|
||||
- Default: `false`
|
||||
|
||||
Activate the [cover feature](/cover). If ture, it will load from `_coverpage.md`.
|
||||
Activate the [cover feature](/cover). If true, it will load from `_coverpage.md`.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
@@ -188,8 +181,7 @@ window.$docsify = {
|
||||
|
||||
- Type: `String`
|
||||
|
||||
|
||||
Website name appears in the sidebar.
|
||||
Website name as it appears in the sidebar.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
@@ -206,7 +198,13 @@ The name of the link.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
nameLink: '/'
|
||||
nameLink: '/',
|
||||
|
||||
// For each route
|
||||
nameLink: {
|
||||
'/zh-cn/': '/zh-cn/',
|
||||
'/': '/'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -216,9 +214,19 @@ window.$docsify = {
|
||||
|
||||
See [Markdown configuration](/markdown).
|
||||
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
// object
|
||||
markdown: {
|
||||
smartypants: true,
|
||||
renderer: {
|
||||
link: function() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// function
|
||||
markdown: function (marked, renderer) {
|
||||
// ...
|
||||
return marked
|
||||
@@ -230,8 +238,7 @@ window.$docsify = {
|
||||
|
||||
- Type: `String`
|
||||
|
||||
Customize the theme color.
|
||||
Use [CSS3 variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables) feature and polyfill in old browser.
|
||||
Customize the theme color. Use [CSS3 variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables) feature and polyfill in old browser.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
@@ -243,7 +250,6 @@ window.$docsify = {
|
||||
|
||||
- Type: `Object`
|
||||
|
||||
|
||||
Set the route alias. You can freely manage routing rules.
|
||||
|
||||
```js
|
||||
@@ -254,3 +260,38 @@ window.$docsify = {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## auto-header
|
||||
|
||||
- type: `Boolean`
|
||||
|
||||
If `loadSidebar` and `autoHeader` are both enabled, for each link in `_sidebar.md`, prepend a header to the page before converting it to html. Compare [#78](https://github.com/QingWei-Li/docsify/issues/78).
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
loadSidebar: true,
|
||||
autoHeader: true
|
||||
}
|
||||
```
|
||||
|
||||
## execute-script
|
||||
|
||||
- type: `Boolean`
|
||||
|
||||
Execute the script on the page. Only parse the first script tag([demo](themes)). If Vue is present, it is turned on by default.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
executeScript: true
|
||||
}
|
||||
```
|
||||
|
||||
```markdown
|
||||
## This is test
|
||||
|
||||
<script>
|
||||
console.log(2333)
|
||||
</script>
|
||||
```
|
||||
|
||||
Note that if you are running an external script, e.g. an embedded jsfiddle demo, make sure to include the [external-script](plugins?id=external-script) plugin.
|
||||
|
||||
+17
-18
@@ -1,57 +1,56 @@
|
||||
# Cover
|
||||
|
||||
Activate the cover feature by setting `coverpage`. The detail in [Configuration#coverpage](zh-cn/configuration#coverpage).
|
||||
Activate the cover feature by setting `coverpage` to **true**, compare [coverpage configuration](configuration#coverpage).
|
||||
|
||||
## Basic usage
|
||||
|
||||
Set `coverpage` to **true**, and create a `_coverpage.md`. You can see the effect in current website.
|
||||
|
||||
|
||||
*index.html*
|
||||
Set `coverpage` to **true**, and create a `_coverpage.md`:
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
|
||||
<script>
|
||||
window.$docsify = {
|
||||
coverpage: true
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify"></script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
```
|
||||
|
||||
*_coverpage.md*
|
||||
|
||||
```markdown
|
||||
<!-- _coverpage.md -->
|
||||
|
||||

|
||||
|
||||
# docsify
|
||||
# docsify <small>3.5</small>
|
||||
|
||||
> A magical documentation site generator.
|
||||
|
||||
- Simple and lightweight (~12kb gzipped)
|
||||
- Simple and lightweight (~16kB gzipped)
|
||||
- No statically built html files
|
||||
- Multiple themes
|
||||
- Not build static html files
|
||||
|
||||
|
||||
[GitHub](https://github.com/QingWei-Li/docsify/)
|
||||
[Get Started](#quick-start)
|
||||
[Get Started](#docsify)
|
||||
```
|
||||
|
||||
!> A document site can have only one cover page.
|
||||
!> A document site can have only one coverpage!
|
||||
|
||||
## Custom background
|
||||
|
||||
The background color is generated randomly by default. You can customize the background color or image.
|
||||
|
||||
*_coverpage.md*
|
||||
The background color is generated randomly by default. You can customize the background color or a background image:
|
||||
|
||||
```markdown
|
||||
# docsify
|
||||
<!-- _coverpage.md -->
|
||||
|
||||
# docsify <small>3.5</small>
|
||||
|
||||
[GitHub](https://github.com/QingWei-Li/docsify/)
|
||||
[Get Started](#quick-start)
|
||||
|
||||
<!-- background image -->
|
||||

|
||||
|
||||
<!-- background color -->
|
||||

|
||||
```
|
||||
|
||||
+47
-18
@@ -1,10 +1,14 @@
|
||||
# Custom navbar
|
||||
|
||||
You can create navbar in HTML file. But note that the link begins with `#/`.
|
||||
## HTML
|
||||
|
||||
*index.html*
|
||||
If you need custom navigation, you can create a HTML-based navigation bar.
|
||||
|
||||
!> Note that documentation links begin with `#/`.
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
|
||||
<body>
|
||||
<nav>
|
||||
<a href="#/">EN</a>
|
||||
@@ -14,53 +18,78 @@ You can create navbar in HTML file. But note that the link begins with `#/`.
|
||||
</body>
|
||||
```
|
||||
|
||||
## Writing by Markdown
|
||||
|
||||
You can custom navbar by Markdown file. Set the `loadNavbar` to **true** and create a `_navbar.md`. The detail in [Configuration#load-navbar](configuration#load-navbar).
|
||||
|
||||
*index.html*
|
||||
## Markdown
|
||||
|
||||
Alternatively, you can create a custom markdown-based navigation file by setting `loadNavbar` to **true** and creating `_navbar.md`, compare [load-navbar configuration](configuration#load-navbar).
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
|
||||
<script>
|
||||
window.$docsify = {
|
||||
loadNavbar: true
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify"></script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
```
|
||||
|
||||
*_navbar.md*
|
||||
|
||||
|
||||
```markdown
|
||||
<!-- _navbar.md -->
|
||||
|
||||
- [En](/)
|
||||
- [chinese](/zh-cn/)
|
||||
```
|
||||
|
||||
`_navbar.md` is loaded from each level directory. If this directory doesn't have `_navbar.md`, it will fallback to parent directory. For example, the current path is `/guide/quick-start`, the `_navbar.md` will be loaded from `/guide/_navbar.md`.
|
||||
!> You need to create a `.nojekyll` in `./docs` to prevent GitHub Pages from ignoring files that begin with an underscore.
|
||||
|
||||
`_navbar.md` is loaded from each level directory. If the current directory doesn't have `_navbar.md`, it will fall back to the parent directory. If, for example, the current path is `/guide/quick-start`, the `_navbar.md` will be loaded from `/guide/_navbar.md`.
|
||||
|
||||
## Nesting
|
||||
|
||||
You can create sub-lists by indenting items that are under a certain parent.
|
||||
|
||||
```markdown
|
||||
<!-- _navbar.md -->
|
||||
|
||||
- Getting started
|
||||
- [Quick start](/quickstart)
|
||||
- [Writing more pages](/more-pages)
|
||||
- [Custom navbar](/custom-navbar)
|
||||
- [Cover page](/cover)
|
||||
- [Quick start](/quickstart)
|
||||
- [Writing more pages](/more-pages)
|
||||
- [Custom navbar](/custom-navbar)
|
||||
- [Cover page](/cover)
|
||||
|
||||
- Configuration
|
||||
- [Configuration](/configuration)
|
||||
- [Themes](/themes)
|
||||
- [Using plugins](/plugins)
|
||||
- [Markdown configuration](/markdown)
|
||||
- [Lanuage highlight](/language-highlight)
|
||||
- [Language highlight](/language-highlight)
|
||||
```
|
||||
|
||||
Example.
|
||||
renders as
|
||||
|
||||

|
||||
|
||||
## Combining custom navbars with the emoji plugin
|
||||
|
||||
If you use the [emoji plugin](plugins#emoji):
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
|
||||
<script>
|
||||
window.$docsify = {
|
||||
// ...
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script>
|
||||
```
|
||||
|
||||
you could, for example, use flag emojis in your custom navbar Markdown file:
|
||||
|
||||
```markdown
|
||||
<!-- _navbar.md -->
|
||||
|
||||
- [:us:, :uk:](/)
|
||||
- [:cn:](/zh-cn/)
|
||||
```
|
||||
|
||||
+6
-6
@@ -1,16 +1,16 @@
|
||||
# Deploy
|
||||
|
||||
As as GitBook, you can deploy files to GitHub Pages or VPS.
|
||||
Similar to [GitBook](https://www.gitbook.com), you can deploy files to GitHub Pages or VPS.
|
||||
|
||||
## GitHub Pages
|
||||
|
||||
There're three places to populate your docs
|
||||
There're three places to populate your docs for your Github repository:
|
||||
|
||||
- `docs/` folder
|
||||
- master branch
|
||||
- gh-pages branch
|
||||
* `docs/` folder
|
||||
* master branch
|
||||
* gh-pages branch
|
||||
|
||||
You can save your files in `./docs` and setting `master branch /docs folder`.
|
||||
It is recommended that you save your files to the `./docs` subfolder of the `master` branch of your repository. Then select `master branch /docs folder` as your Github Pages source in your repositories' settings page.
|
||||
|
||||

|
||||
|
||||
|
||||
+6
-5
@@ -4,23 +4,24 @@ docsify extends Markdown syntax to make your documents more readable.
|
||||
|
||||
## important content
|
||||
|
||||
Suitable for displaying important information.
|
||||
Important content like:
|
||||
|
||||
```markdown
|
||||
!> **Time** is money, my friend!
|
||||
```
|
||||
|
||||
!> **Time** is money, my friend!
|
||||
is rendered as:
|
||||
|
||||
!> **Time** is money, my friend!
|
||||
|
||||
## General tips
|
||||
|
||||
General tips.
|
||||
|
||||
General tips like:
|
||||
|
||||
```markdown
|
||||
?> *TODO* unit test
|
||||
```
|
||||
|
||||
?> *TODO* unit test
|
||||
are rendered as:
|
||||
|
||||
?> *TODO* unit test
|
||||
|
||||
+10
-2
@@ -6,11 +6,14 @@
|
||||
<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="google-site-verification" content="6t0LoIeFksrjF4c9sqUEsVXiQNxLp2hgoqo0KryT-sE" />
|
||||
<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">
|
||||
<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>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<nav data-cloak>
|
||||
<a href="#/">En</a>
|
||||
<a href="#/zh-cn/">中文</a>
|
||||
</nav>
|
||||
@@ -24,11 +27,16 @@
|
||||
auto2top: true,
|
||||
coverpage: true,
|
||||
loadSidebar: true,
|
||||
executeScript: true,
|
||||
alias: {
|
||||
'/zh-cn/changelog': '/changelog',
|
||||
'/changelog': 'https://raw.githubusercontent.com/QingWei-Li/docsify/master/CHANGELOG'
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof navigator.serviceWorker !== 'undefined') {
|
||||
navigator.serviceWorker.register('sw.js')
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
# language highlight
|
||||
|
||||
|
||||
The code language highlight tool is [Prism](https://github.com/PrismJS/prism). Only supports CSS, JavaScipt and HTML by default. You can load its component to highlight the language you need.
|
||||
|
||||
**docsify** uses [Prism](https://github.com/PrismJS/prism) to highlight code blocks in your pages. By default it only supports CSS, JavaScipt and HTML. You can make **Prism** load additional languages:
|
||||
|
||||
```html
|
||||
<script src="//unpkg.com/docsify"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-php.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-php.min.js"></script>
|
||||
```
|
||||
|
||||
?> See fully supported highlight component [files list](https://github.com/PrismJS/prism/tree/gh-pages/components).
|
||||
?> Check the [component files](https://github.com/PrismJS/prism/tree/gh-pages/components) list for more options.
|
||||
|
||||
+7
-3
@@ -1,12 +1,16 @@
|
||||
# Markdown configuration
|
||||
|
||||
The Markdown parser is [marked](https://github.com/chjj/marked). You can customize how docsify renders your Markdown content to HTML.
|
||||
**docsify** uses [marked](https://github.com/chjj/marked) as its Markdown parser. You can customize how it renders your Markdown content to HTML by customizing `renderer`:
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
markdown: {
|
||||
smartypants: true
|
||||
// ...
|
||||
smartypants: true,
|
||||
renderer: {
|
||||
link: function() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
+22
-18
@@ -1,22 +1,21 @@
|
||||
# More pages
|
||||
|
||||
If you need more pages multi-level routing site. It is easy to achieve in docsify. A simple example: If you create a `guide.md`, then get the route is `/#/guide`.
|
||||
If you need more pages, you can simply create more markdown files in your docsify directory. If you create a file named `guide.md`, then it is accessible via `/#/guide`.
|
||||
|
||||
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
|
||||
|
||||
|
||||
```text
|
||||
docs/README.md => http://domain.com
|
||||
docs/guide.md => http://domain.com/guide
|
||||
@@ -26,41 +25,46 @@ docs/zh-cn/guide.md => http://domain.com/zh-cn/guide
|
||||
|
||||
## Custom sidebar
|
||||
|
||||
By default, the TOC in sidebar is automatically generated based on Markdown file. You can create a Table of Contents page to list down pages in your site.
|
||||
By default, the table of contents in the sidebar is automatically generated based on your markdown files. If you need a custom sidebar, then you can create your own `_sidebar.md` (see [this documentation's sidebar](https://github.com/QingWei-Li/docsify/blob/master/docs/_sidebar.md) for an example):
|
||||
|
||||
First, you need to set `loadSidebar` to **true**. The detail in [Configuration#load-sidebar](configuration#load-sidebar).
|
||||
First, you need to set `loadSidebar` to **true**. Details are available in the [configuration paragraph](configuration#load-sidebar).
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
|
||||
<script>
|
||||
window.$docsify = {
|
||||
loadSidebar: true
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify"></script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
```
|
||||
|
||||
Create the `_sidebar.md`
|
||||
Create the `_sidebar.md`:
|
||||
|
||||
```markdown
|
||||
<!-- docs/_sidebar.md -->
|
||||
|
||||
- [Home](/)
|
||||
- [Guide](/guide)
|
||||
```
|
||||
|
||||
!> Need create a `.nojekyll` in `./docs` to prevent GitHub Pages from ignoring files that begin with an underscore.
|
||||
!> You need to create a `.nojekyll` in `./docs` to prevent GitHub Pages from ignoring files that begin with an underscore.
|
||||
|
||||
`_sidebar.md` is loaded from each level directory. If this directory doesn't have `_sidebar.md`, it will fallback to parent directory. For example, the current path is `/guide/quick-start`, the `_sidebar.md` will be loaded from `/guide/_sidebar.md`.
|
||||
`_sidebar.md` is loaded from each level directory. If the current directory doesn't have `_sidebar.md`, it will fall back to the parent directory. If, for example, the current path is `/guide/quick-start`, the `_sidebar.md` will be loaded from `/guide/_sidebar.md`.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
Custom sidebar can also be automatically generate TOC by setting `subMaxLevel`. The detail in [Configuration#sub-max-level](configuration#sub-max-level).
|
||||
A custom sidebar can also automatically generate a table of contents by setting a `subMaxLevel`, compare [sub-max-level configuration](configuration#sub-max-level).
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
|
||||
<script>
|
||||
window.$docsify = {
|
||||
loadSidebar: true,
|
||||
subMaxLevel: 2
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify"></script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
```
|
||||
|
||||
|
||||
+44
-73
@@ -1,8 +1,6 @@
|
||||
# Using plugins
|
||||
# List of Plugins
|
||||
|
||||
## List of Plugins
|
||||
|
||||
### Full text search
|
||||
## Full text search
|
||||
|
||||
By default, the hyperlink on the current page is recognized and the content is saved in `localStorage`. You can also specify the path to the files.
|
||||
|
||||
@@ -19,20 +17,33 @@ By default, the hyperlink on the current page is recognized and the content is s
|
||||
'/zh-cn/', // => /zh-cn/README.md
|
||||
],
|
||||
|
||||
// 完整配置参数
|
||||
// complete configuration parameters
|
||||
search: {
|
||||
maxAge: 86400000, // Expiration time, the default one day
|
||||
paths: [], // or 'auto'
|
||||
placeholder: 'Type to search'
|
||||
placeholder: 'Type to search',
|
||||
|
||||
// Localization
|
||||
placeholder: {
|
||||
'/zh-cn/': '搜索',
|
||||
'/': 'Type to search'
|
||||
},
|
||||
|
||||
noData: 'No Results!',
|
||||
|
||||
// Localization
|
||||
noData: {
|
||||
'/zh-cn/': '找不到结果',
|
||||
'/': 'No Results'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
||||
```
|
||||
|
||||
|
||||
### Google Analytics
|
||||
## Google Analytics
|
||||
|
||||
Install the plugin and configure the track id.
|
||||
|
||||
@@ -42,83 +53,43 @@ Install the plugin and configure the track id.
|
||||
ga: 'UA-XXXXX-Y'
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/ga.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script>
|
||||
```
|
||||
|
||||
Configure by `data-ga`.
|
||||
|
||||
```html
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js" data-ga="UA-XXXXX-Y"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script>
|
||||
```
|
||||
|
||||
## front matter
|
||||
|
||||
```html
|
||||
<script src="//unpkg.com/docsify" data-ga="UA-XXXXX-Y"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/ga.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/front-matter.min.js"></script>
|
||||
```
|
||||
|
||||
## emoji
|
||||
|
||||
## Write a plugin
|
||||
The default is to support parsing emoji. For example `:100:` will be parsed to :100:. But it is not precise because there is no matching non-emoji string. If you need to correctly parse the emoji string, you need install this plugin.
|
||||
|
||||
A plugin is simply a function that takes `hook` as arguments.
|
||||
The hook supports handling asynchronous tasks.
|
||||
|
||||
#### Full configuration
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
plugins: [
|
||||
function (hook) {
|
||||
hook.init(function() {
|
||||
// Called when the script starts running, only trigger once, no arguments,
|
||||
})
|
||||
|
||||
hook.beforeEach(function(content) {
|
||||
// Invoked each time before parsing the Markdown file.
|
||||
// ...
|
||||
return content
|
||||
})
|
||||
|
||||
hook.afterEach(function(html, next) {
|
||||
// Invoked each time after the Markdown file is parsed.
|
||||
// beforeEach and afterEach support asynchronous。
|
||||
// ...
|
||||
// call `next(html)` when task is done.
|
||||
next(html)
|
||||
})
|
||||
|
||||
hook.doneEach(function() {
|
||||
// Invoked each time after the data is fully loaded, no arguments,
|
||||
// ...
|
||||
})
|
||||
|
||||
hook.ready(function() {
|
||||
// Called after initialization is complete. Only trigger once, no arguments.
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
```html
|
||||
<script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script>
|
||||
```
|
||||
|
||||
!> You can get internal methods through `window.Docsify.utils`.
|
||||
## External Script
|
||||
|
||||
#### Example
|
||||
If the script on the page is an external one (imports a js file via `src` attribute), you'll need this plugin to make it work.
|
||||
|
||||
Add footer component in each pages.
|
||||
```html
|
||||
<script src="//unpkg.com/docsify/lib/plugins/external-script.min.js"></script>
|
||||
```
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
plugins: [
|
||||
function (hook) {
|
||||
var footer = [
|
||||
'<hr/>',
|
||||
'<footer>',
|
||||
'<span><a href="https://github.com/QingWei-Li">cinwell</a> ©2017.</span>',
|
||||
'<span>Proudly published with <a href="https://github.com/QingWei-Li/docsify" target="_blank">docsify</a>.</span>',
|
||||
'</footer>'
|
||||
].join('')
|
||||
## Zoom image
|
||||
|
||||
hook.afterEach(function (html) {
|
||||
return html + footer
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
Medium's Image Zoom. Based on [zoom-image](https://github.com/egoist/zoom-image).
|
||||
|
||||
```html
|
||||
<script src="//unpkg.com/docsify/lib/plugins/zoom-image.min.js"></script>
|
||||
```
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
# Offline Mode
|
||||
|
||||
[Progressive Web Apps](https://developers.google.com/web/progressive-web-apps/) (PWA) are experiences that combine the best of the web with the best of apps. We can enhance our website with service workers to work **offline** or on low-quality networks.
|
||||
|
||||
It is also very easy to use it.
|
||||
|
||||
## Create serviceWorker
|
||||
|
||||
Create a `sw.js` file in your documents root directory and copy the following code:
|
||||
|
||||
*sw.js*
|
||||
|
||||
```js
|
||||
/* ===========================================================
|
||||
* docsify sw.js
|
||||
* ===========================================================
|
||||
* Copyright 2016 @huxpro
|
||||
* Licensed under Apache 2.0
|
||||
* Register service worker.
|
||||
* ========================================================== */
|
||||
|
||||
const RUNTIME = 'docsify'
|
||||
const HOSTNAME_WHITELIST = [
|
||||
self.location.hostname,
|
||||
'fonts.gstatic.com',
|
||||
'fonts.googleapis.com',
|
||||
'unpkg.com'
|
||||
]
|
||||
|
||||
// The Util Function to hack URLs of intercepted requests
|
||||
const getFixedUrl = (req) => {
|
||||
var now = Date.now()
|
||||
var url = new URL(req.url)
|
||||
|
||||
// 1. fixed http URL
|
||||
// Just keep syncing with location.protocol
|
||||
// fetch(httpURL) belongs to active mixed content.
|
||||
// And fetch(httpRequest) is not supported yet.
|
||||
url.protocol = self.location.protocol
|
||||
|
||||
// 2. add query for caching-busting.
|
||||
// Github Pages served with Cache-Control: max-age=600
|
||||
// max-age on mutable content is error-prone, with SW life of bugs can even extend.
|
||||
// Until cache mode of Fetch API landed, we have to workaround cache-busting with query string.
|
||||
// Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190
|
||||
if (url.hostname === self.location.hostname) {
|
||||
url.search += (url.search ? '&' : '?') + 'cache-bust=' + now
|
||||
}
|
||||
return url.href
|
||||
}
|
||||
|
||||
/**
|
||||
* @Lifecycle Activate
|
||||
* New one activated when old isnt being used.
|
||||
*
|
||||
* waitUntil(): activating ====> activated
|
||||
*/
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(self.clients.claim())
|
||||
})
|
||||
|
||||
/**
|
||||
* @Functional Fetch
|
||||
* All network requests are being intercepted here.
|
||||
*
|
||||
* void respondWith(Promise<Response> r)
|
||||
*/
|
||||
self.addEventListener('fetch', event => {
|
||||
// Skip some of cross-origin requests, like those for Google Analytics.
|
||||
if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) {
|
||||
// Stale-while-revalidate
|
||||
// similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale
|
||||
// Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1
|
||||
const cached = caches.match(event.request)
|
||||
const fixedUrl = getFixedUrl(event.request)
|
||||
const fetched = fetch(fixedUrl, { cache: 'no-store' })
|
||||
const fetchedCopy = fetched.then(resp => resp.clone())
|
||||
|
||||
// Call respondWith() with whatever we get first.
|
||||
// If the fetch fails (e.g disconnected), wait for the cache.
|
||||
// If there’s nothing in cache, wait for the fetch.
|
||||
// If neither yields a response, return offline pages.
|
||||
event.respondWith(
|
||||
Promise.race([fetched.catch(_ => cached), cached])
|
||||
.then(resp => resp || fetched)
|
||||
.catch(_ => { /* eat any errors */ })
|
||||
)
|
||||
|
||||
// Update the cache with the version we fetched (only for ok status)
|
||||
event.waitUntil(
|
||||
Promise.all([fetchedCopy, caches.open(RUNTIME)])
|
||||
.then(([response, cache]) => response.ok && cache.put(event.request, response))
|
||||
.catch(_ => { /* eat any errors */ })
|
||||
)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Register
|
||||
|
||||
Now, register it in your `index.html`. It only works on some modern browsers, so we need to judge:
|
||||
|
||||
*index.html*
|
||||
|
||||
```html
|
||||
<script>
|
||||
if (typeof navigator.serviceWorker !== 'undefined') {
|
||||
navigator.serviceWorker.register('sw.js')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## Enjoy it
|
||||
|
||||
Release your website and start experiencing magical offline feature. :ghost: You can turn off Wi-Fi and refresh the current site to experience it.
|
||||
+42
-18
@@ -1,14 +1,14 @@
|
||||
# Quick start
|
||||
|
||||
Recommended install `docsify-cli` globally, which can help us to initialize and preview the website locally.
|
||||
It is recommended to install `docsify-cli` globally, which helps initializing and previewing the website locally.
|
||||
|
||||
```bash
|
||||
npm i docsify-cli -g
|
||||
```
|
||||
|
||||
## initialize
|
||||
## Initialize
|
||||
|
||||
If you want to write the documentation in `./docs` directory, you can use the `init` command.
|
||||
If you want to write the documentation in the `./docs` subdirectory, you can use the `init` command.
|
||||
|
||||
```bash
|
||||
docsify init ./docs
|
||||
@@ -16,33 +16,31 @@ docsify init ./docs
|
||||
|
||||
## Writing content
|
||||
|
||||
After the init is complete, you can see the file list in the docs directory.
|
||||
After the `init` is complete, you can see the file list in the `./docs` subdirectory.
|
||||
|
||||
* `index.html` as the entry file
|
||||
* `README.md` as the home page
|
||||
* `.nojekyll` prevents GitHub Pages from ignoring files that begin with an underscore
|
||||
|
||||
- `index.html` as the entry file
|
||||
- `README.md` as the home page
|
||||
- `.nojekyll` can prevent GitHub Pages from ignoring files that begin with an underscore
|
||||
|
||||
You can easily update the documentation in `docs/README.md`, of course you can add [more pages](more-pages).
|
||||
You can easily update the documentation in `./docs/README.md`, of course you can add [more pages](more-pages).
|
||||
|
||||
## Preview your site
|
||||
|
||||
Run the local server via `docsify serve`. You can preview your site in browser via http://localhost:3000.
|
||||
|
||||
Run the local server with `docsify serve`. You can preview your site in your browser on `http://localhost:3000`.
|
||||
|
||||
```bash
|
||||
docsify serve docs
|
||||
```
|
||||
|
||||
?> More usages of reference [docsify-cli documentation](https://github.com/QingWei-Li/docsify-cli).
|
||||
?> For more use cases of `docsify-cli`, head over to the [docsify-cli documentation](https://github.com/QingWei-Li/docsify-cli).
|
||||
|
||||
## Manually
|
||||
## Manual initialization
|
||||
|
||||
If you don't like npm or feel the trouble to install the tool. What we need is an `index.html`.
|
||||
|
||||
*index.html*
|
||||
If you don't like `npm` or have trouble installing the tool, you can manually create `index.html`:
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
@@ -52,12 +50,38 @@ If you don't like npm or feel the trouble to install the tool. What we need is a
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
<script src="//unpkg.com/docsify"></script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
If your system has Python, you can easily to run a static server to preview your site.
|
||||
If you installed python on your system, you can easily use it to run a static server to preview your site.
|
||||
|
||||
```bash
|
||||
cd docs && python -m SimpleHTTPServer 3000
|
||||
```
|
||||
|
||||
## Loading dialog
|
||||
|
||||
If you want, you can show a loading dialog before docsify starts to render your documentation:
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
|
||||
<div id="app">Please wait...</div>
|
||||
```
|
||||
|
||||
You should set the `data-app` attribute if you changed `el`:
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
|
||||
<div data-app id="main">Please wait...</div>
|
||||
|
||||
<script>
|
||||
window.$docsify = {
|
||||
el: '#main'
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
Compare [el configuration](/configuration#el).
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/* ===========================================================
|
||||
* docsify sw.js
|
||||
* ===========================================================
|
||||
* Copyright 2016 @huxpro
|
||||
* Licensed under Apache 2.0
|
||||
* Register service worker.
|
||||
* ========================================================== */
|
||||
|
||||
const RUNTIME = 'docsify'
|
||||
const HOSTNAME_WHITELIST = [
|
||||
self.location.hostname,
|
||||
'raw.githubusercontent.com',
|
||||
'fonts.gstatic.com',
|
||||
'fonts.googleapis.com',
|
||||
'unpkg.com'
|
||||
]
|
||||
|
||||
// The Util Function to hack URLs of intercepted requests
|
||||
const getFixedUrl = (req) => {
|
||||
var now = Date.now()
|
||||
var url = new URL(req.url)
|
||||
|
||||
// 1. fixed http URL
|
||||
// Just keep syncing with location.protocol
|
||||
// fetch(httpURL) belongs to active mixed content.
|
||||
// And fetch(httpRequest) is not supported yet.
|
||||
url.protocol = self.location.protocol
|
||||
|
||||
// 2. add query for caching-busting.
|
||||
// Github Pages served with Cache-Control: max-age=600
|
||||
// max-age on mutable content is error-prone, with SW life of bugs can even extend.
|
||||
// Until cache mode of Fetch API landed, we have to workaround cache-busting with query string.
|
||||
// Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190
|
||||
if (url.hostname === self.location.hostname) {
|
||||
url.search += (url.search ? '&' : '?') + 'cache-bust=' + now
|
||||
}
|
||||
return url.href
|
||||
}
|
||||
|
||||
/**
|
||||
* @Lifecycle Activate
|
||||
* New one activated when old isnt being used.
|
||||
*
|
||||
* waitUntil(): activating ====> activated
|
||||
*/
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(self.clients.claim())
|
||||
})
|
||||
|
||||
/**
|
||||
* @Functional Fetch
|
||||
* All network requests are being intercepted here.
|
||||
*
|
||||
* void respondWith(Promise<Response> r)
|
||||
*/
|
||||
self.addEventListener('fetch', event => {
|
||||
// Skip some of cross-origin requests, like those for Google Analytics.
|
||||
if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) {
|
||||
// Stale-while-revalidate
|
||||
// similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale
|
||||
// Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1
|
||||
const cached = caches.match(event.request)
|
||||
const fixedUrl = getFixedUrl(event.request)
|
||||
const fetched = fetch(fixedUrl, { cache: 'no-store' })
|
||||
const fetchedCopy = fetched.then(resp => resp.clone())
|
||||
|
||||
// Call respondWith() with whatever we get first.
|
||||
// If the fetch fails (e.g disconnected), wait for the cache.
|
||||
// If there’s nothing in cache, wait for the fetch.
|
||||
// If neither yields a response, return offline pages.
|
||||
event.respondWith(
|
||||
Promise.race([fetched.catch(_ => cached), cached])
|
||||
.then(resp => resp || fetched)
|
||||
.catch(_ => { /* eat any errors */ })
|
||||
)
|
||||
|
||||
// Update the cache with the version we fetched (only for ok status)
|
||||
event.waitUntil(
|
||||
Promise.all([fetchedCopy, caches.open(RUNTIME)])
|
||||
.then(([response, cache]) => response.ok && cache.put(event.request, response))
|
||||
.catch(_ => { /* eat any errors */ })
|
||||
)
|
||||
}
|
||||
})
|
||||
+45
-6
@@ -2,13 +2,52 @@
|
||||
|
||||
There are currently three themes available. Copy [Vue](//vuejs.org) and [buble](//buble.surge.sh) website custom theme and [@liril-net](https://github.com/liril-net) contribution to the theme of the black style.
|
||||
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/themes/vue.css">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/themes/buble.css">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/themes/dark.css">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/themes/vue.css">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/themes/buble.css">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/themes/dark.css">
|
||||
```
|
||||
|
||||
!> This compressed files in `/lib/themes/`.
|
||||
!> Compressed files are available in `/lib/themes/`.
|
||||
|
||||
If you have any ideas or would like to develop new theme, welcome submit [PR](https://github.com/QingWei-Li/docsify/pulls).
|
||||
```html
|
||||
<!-- compressed -->
|
||||
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/buble.css">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/dark.css">
|
||||
```
|
||||
|
||||
If you have any ideas or would like to develop a new theme, you are welcome to submit a [pull request](https://github.com/QingWei-Li/docsify/pulls).
|
||||
|
||||
#### Click to preview
|
||||
|
||||
<div class="demo-theme-preview">
|
||||
<a data-theme="vue">vue.css</a>
|
||||
<a data-theme="buble">buble.css</a>
|
||||
<a data-theme="dark">dark.css</a>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.demo-theme-preview a {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.demo-theme-preview a:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
var preview = Docsify.dom.find('.demo-theme-preview');
|
||||
var themes = Docsify.dom.findAll('[rel="stylesheet"]');
|
||||
|
||||
preview.onclick = function (e) {
|
||||
var title = e.target.getAttribute('data-theme')
|
||||
|
||||
themes.forEach(function (theme) {
|
||||
theme.disabled = theme.title !== title
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
+15
-9
@@ -1,19 +1,21 @@
|
||||
# Compatible with Vue
|
||||
|
||||
You can write Vue components directly in the Markdown file, and it will be parsed.
|
||||
You can use this feature to write vue demo and documentation together.
|
||||
You can write Vue components directly in the Markdown file, and it will be parsed. You can use this feature to write vue demo and documentation together.
|
||||
|
||||
## Basic usage
|
||||
|
||||
Load the Vue in `index.html`.
|
||||
Load the Vue in `./index.html`.
|
||||
|
||||
```html
|
||||
<script src="//unpkg.com/vue"></script>
|
||||
<script src="//unpkg.com/docsify"></script>
|
||||
|
||||
<!-- or use the compressed files -->
|
||||
<script src="//unpkg.com/vue/dist/vue.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
```
|
||||
|
||||
Then you can immediately write Vue code at Markdown file.
|
||||
`new Vue({ el: 'main' })` script is executed by default to create instance.
|
||||
Then you can immediately write Vue code at Markdown file. `new Vue({ el: '#main' })` script is executed by default to create instance.
|
||||
|
||||
*README.md*
|
||||
|
||||
@@ -44,7 +46,7 @@ You can manually initialize a Vue instance.
|
||||
|
||||
<script>
|
||||
new Vue({
|
||||
el: 'main',
|
||||
el: '#main',
|
||||
data: { msg: 'Vue' }
|
||||
})
|
||||
</script>
|
||||
@@ -62,6 +64,11 @@ You can manually initialize a Vue instance.
|
||||
<script src="//unpkg.com/vue"></script>
|
||||
<script src="//unpkg.com/vuep"></script>
|
||||
<script src="//unpkg.com/docsify"></script>
|
||||
|
||||
<!-- or use the compressed files -->
|
||||
<script src="//unpkg.com/vue/dist/vue.min.js"></script>
|
||||
<script src="//unpkg.com/vuep/dist/vuep.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
```
|
||||
|
||||
*README.md*
|
||||
@@ -76,7 +83,7 @@ You can manually initialize a Vue instance.
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
module.exports = {
|
||||
data: function () {
|
||||
return { name: 'Vue' }
|
||||
}
|
||||
@@ -85,5 +92,4 @@ You can manually initialize a Vue instance.
|
||||
</script>
|
||||
```
|
||||
|
||||
?> Example Refer to the vuep [documentation](https://qingwei-li.github.io/vuep/).
|
||||
|
||||
?> Example Refer to the [vuep documentation](https://qingwei-li.github.io/vuep/).
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Write a plugin
|
||||
|
||||
A plugin is simply a function that takes `hook` as an argument. The hook supports handling of asynchronous tasks.
|
||||
|
||||
## Full configuration
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
plugins: [
|
||||
function (hook, vm) {
|
||||
hook.init(function() {
|
||||
// Called when the script starts running, only trigger once, no arguments,
|
||||
})
|
||||
|
||||
hook.beforeEach(function(content) {
|
||||
// Invoked each time before parsing the Markdown file.
|
||||
// ...
|
||||
return content
|
||||
})
|
||||
|
||||
hook.afterEach(function(html, next) {
|
||||
// Invoked each time after the Markdown file is parsed.
|
||||
// beforeEach and afterEach support asynchronous。
|
||||
// ...
|
||||
// call `next(html)` when task is done.
|
||||
next(html)
|
||||
})
|
||||
|
||||
hook.doneEach(function() {
|
||||
// Invoked each time after the data is fully loaded, no arguments,
|
||||
// ...
|
||||
})
|
||||
|
||||
hook.mounted(function() {
|
||||
// Called after initial completion. Only trigger once, no arguments.
|
||||
})
|
||||
|
||||
hook.ready(function() {
|
||||
// Called after initial completion, no arguments.
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
!> You can get internal methods through `window.Docsify`. Get the current instance through the second argument.
|
||||
|
||||
## Example
|
||||
|
||||
Add footer component in each pages.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
plugins: [
|
||||
function (hook) {
|
||||
var footer = [
|
||||
'<hr/>',
|
||||
'<footer>',
|
||||
'<span><a href="https://github.com/QingWei-Li">cinwell</a> ©2017.</span>',
|
||||
'<span>Proudly published with <a href="https://github.com/QingWei-Li/docsify" target="_blank">docsify</a>.</span>',
|
||||
'</footer>'
|
||||
].join('')
|
||||
|
||||
hook.afterEach(function (html) {
|
||||
return html + footer
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -12,11 +12,12 @@ docsify 是一个动态生成文档网站的工具。不同于 GitBook、Hexo
|
||||
|
||||
## 特性
|
||||
- 无需构建,写完文档直接发布
|
||||
- 容易使用并且轻量 (~13Kb gzipped)
|
||||
- 智能的全文检索
|
||||
- 容易使用并且轻量 (~16kB gzipped)
|
||||
- 智能的全文搜索
|
||||
- 提供多套主题
|
||||
- 丰富的 API
|
||||
- 兼容 IE9+
|
||||
- 支持 Emoji
|
||||
- 兼容 IE10+
|
||||
|
||||
## 例子
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
- 入门
|
||||
- [快速开始](zh-cn/quickstart)
|
||||
- [多页文档](zh-cn/more-pages)
|
||||
- [定制导航栏](zh-cn/custom-navbar)
|
||||
- [封面](zh-cn/cover)
|
||||
- [快速开始](zh-cn/quickstart)
|
||||
- [多页文档](zh-cn/more-pages)
|
||||
- [定制导航栏](zh-cn/custom-navbar)
|
||||
- [封面](zh-cn/cover)
|
||||
|
||||
- 配置
|
||||
- 定制化
|
||||
- [配置项](zh-cn/configuration)
|
||||
- [主题](zh-cn/themes)
|
||||
- [使用插件](zh-cn/plugins)
|
||||
- [插件列表](zh-cn/plugins)
|
||||
- [开发插件](zh-cn/write-a-plugin)
|
||||
- [Markdown 配置](zh-cn/markdown)
|
||||
- [代码高亮](zh-cn/language-highlight)
|
||||
|
||||
@@ -16,5 +17,6 @@
|
||||
- [文档助手](zh-cn/helpers)
|
||||
- [兼容 Vue](zh-cn/vue)
|
||||
- [CDN](zh-cn/cdn)
|
||||
- [离线模式(PWA)](zh-cn/pwa)
|
||||
|
||||
- [Changelog](zh-cn/changelog)
|
||||
- [Changelog](zh-cn/changelog)
|
||||
|
||||
@@ -108,12 +108,12 @@ window.$docsify = {
|
||||
- 类型:`Number`
|
||||
- 默认值: `0`
|
||||
|
||||
自定义侧边栏后默认不会再生成目录,你也可以通过设置生成目录的最大层级开启这个功能,
|
||||
自定义侧边栏后默认不会再生成目录,你也可以通过设置生成目录的最大层级开启这个功能。
|
||||
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
subMaxLevel: 3
|
||||
subMaxLevel: 2
|
||||
}
|
||||
```
|
||||
|
||||
@@ -206,18 +206,35 @@ window.$docsify = {
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
nameLink: '/'
|
||||
nameLink: '/',
|
||||
|
||||
// 按照路由切换
|
||||
nameLink: {
|
||||
'/zh-cn/': '/zh-cn/',
|
||||
'/': '/'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## markdown
|
||||
|
||||
- 类型: `Function`
|
||||
- 类型: `Object|Function`
|
||||
|
||||
参考 [Markdown 配置](/zh-cn/markdown)。
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
// object
|
||||
markdown: {
|
||||
smartypants: true,
|
||||
renderer: {
|
||||
link: function() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// function
|
||||
markdown: function (marked, renderer) {
|
||||
// ...
|
||||
return marked
|
||||
@@ -229,7 +246,7 @@ window.$docsify = {
|
||||
|
||||
- 类型:`String`
|
||||
|
||||
替换主题色。利用 [CSS3 支持变量]((https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables)的特性,对于老的浏览器有 polyfill 处理。
|
||||
替换主题色。利用 [CSS3 支持变量](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables)的特性,对于老的浏览器有 polyfill 处理。
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
@@ -253,3 +270,38 @@ window.$docsify = {
|
||||
}
|
||||
```
|
||||
|
||||
## auto-header
|
||||
|
||||
- 类型:`Boolean`
|
||||
|
||||
同时设置 `loadSidebar` 和 `autoHeader` 后,可以根据 `_sidebar.md` 的内容自动为每个页面增加标题。[#78](https://github.com/QingWei-Li/docsify/issues/78)
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
loadSidebar: true,
|
||||
autoHeader: true
|
||||
}
|
||||
```
|
||||
|
||||
## execute-script
|
||||
|
||||
- 类型:`Boolean`
|
||||
|
||||
执行文档里的 script 标签里的脚本,只执行第一个 script ([demo](zh-cn/themes))。 如果 Vue 存在,则自动开启。
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
executeScript: true
|
||||
}
|
||||
```
|
||||
|
||||
```markdown
|
||||
## This is test
|
||||
|
||||
<script>
|
||||
console.log(2333)
|
||||
</script>
|
||||
|
||||
```
|
||||
|
||||
注意如果执行的是一个外链脚本,比如 jsfiddle 的内嵌 demo,请确保引入 [external-script](zh-cn/plugins?id=外链脚本-external-script) 插件。
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
# Markdown 配置
|
||||
|
||||
内置的 Markdown 解析器是 [marked](https://github.com/chjj/marked),可以修改它的配置。
|
||||
内置的 Markdown 解析器是 [marked](https://github.com/chjj/marked),可以修改它的配置。同时可以直接配置 `renderer`。
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
markdown: {
|
||||
smartypants: true
|
||||
// ...
|
||||
smartypants: true,
|
||||
renderer: {
|
||||
link: function() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
+33
-63
@@ -1,10 +1,8 @@
|
||||
# 使用插件
|
||||
# 插件列表
|
||||
|
||||
## 内置插件
|
||||
## 全文搜索 - Search
|
||||
|
||||
### 全文检索 - Search
|
||||
|
||||
全文检索插件会根据当前页面上的超链接获取文档内容,在 `localStorage` 内建立文档索引。默认过期时间为一天,当然我们可以自己指定需要缓存的文件列表或者配置过期时间。
|
||||
全文搜索插件会根据当前页面上的超链接获取文档内容,在 `localStorage` 内建立文档索引。默认过期时间为一天,当然我们可以自己指定需要缓存的文件列表或者配置过期时间。
|
||||
|
||||
|
||||
```html
|
||||
@@ -23,7 +21,21 @@
|
||||
search: {
|
||||
maxAge: 86400000, // 过期时间,单位毫秒,默认一天
|
||||
paths: [], // or 'auto'
|
||||
placeholder: 'Type to search'
|
||||
placeholder: 'Type to search',
|
||||
|
||||
// 支持本地化
|
||||
placeholder: {
|
||||
'/zh-cn/': '搜索',
|
||||
'/': 'Type to search'
|
||||
},
|
||||
|
||||
noData: 'No Results!',
|
||||
|
||||
// 支持本地化
|
||||
noData: {
|
||||
'/zh-cn/': '找不到结果',
|
||||
'/': 'No Results'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -31,7 +43,7 @@
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.js"></script>
|
||||
```
|
||||
|
||||
### 谷歌统计 - Google Analytics
|
||||
## 谷歌统计 - Google Analytics
|
||||
|
||||
需要配置 track id 才能使用。
|
||||
|
||||
@@ -52,68 +64,26 @@
|
||||
<script src="//unpkg.com/docsify/lib/plugins/ga.js"></script>
|
||||
```
|
||||
|
||||
## 自定义插件
|
||||
## emoji
|
||||
|
||||
docsify 提供了一套插件机制,其中提供的钩子(hook)支持处理异步逻辑,可以很方便的扩展功能。
|
||||
默认是提供 emoji 解析的,能将类似 `:100:` 解析成 :100:。但是它不是精准的,因为没有处理非 emoji 的字符串。如果你需要正确解析 emoji 字符串,你可以引入这个插件。
|
||||
|
||||
#### 完整功能
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
plugins: [
|
||||
function (hook) {
|
||||
hook.init(function() {
|
||||
// 初始化时调用,只调用一次,没有参数。
|
||||
})
|
||||
|
||||
hook.beforeEach(function(content) {
|
||||
// 每次开始解析 Markdown 内容时调用
|
||||
// ...
|
||||
return content
|
||||
})
|
||||
|
||||
hook.afterEach(function(html, next) {
|
||||
// 解析成 html 后调用。beforeEach 和 afterEach 支持处理异步逻辑
|
||||
// ...
|
||||
// 异步处理完成后调用 next(html) 返回结果
|
||||
next(html)
|
||||
})
|
||||
|
||||
hook.doneEach(function() {
|
||||
// 每次路由切换时数据全部加载完成后调用,没有参数。
|
||||
// ...
|
||||
})
|
||||
|
||||
hook.ready(function() {
|
||||
// 初始化完成后调用,只调用一次,没有参数。
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
```html
|
||||
<script src="//unpkg.com/docsify/lib/plugins/emoji.js"></script>
|
||||
```
|
||||
|
||||
!> 如果需要用 docsify 的内部方法,可以通过 `window.Docsify.utils` 获取。
|
||||
## 外链脚本 - External Script
|
||||
|
||||
#### 例子
|
||||
如果文档里的 script 是内联脚本,可以直接执行;而如果是外链脚本(即 js 文件内容由 `src` 属性引入),则需要使用此插件。
|
||||
|
||||
给每个页面的末尾加上 `footer`
|
||||
```html
|
||||
<script src="//unpkg.com/docsify/lib/plugins/external-script.js"></script>
|
||||
```
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
plugins: [
|
||||
function (hook) {
|
||||
var footer = [
|
||||
'<hr/>',
|
||||
'<footer>',
|
||||
'<span><a href="https://github.com/QingWei-Li">cinwell</a> ©2017.</span>',
|
||||
'<span>Proudly published with <a href="https://github.com/QingWei-Li/docsify" target="_blank">docsify</a>.</span>',
|
||||
'</footer>'
|
||||
].join('')
|
||||
## 图片缩放 - Zoom image
|
||||
|
||||
hook.afterEach(function (html) {
|
||||
return html + footer
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
Medium's 风格的图片缩放插件. 基于 [zoom-image](https://github.com/egoist/zoom-image)。
|
||||
|
||||
```html
|
||||
<script src="//unpkg.com/docsify/lib/plugins/zoom-image.js"></script>
|
||||
```
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
# 离线模式
|
||||
|
||||
[Progressive Web Apps](https://developers.google.com/web/progressive-web-apps/)(PWA) 是一项融合 Web 和 Native 应用各项优点的解决方案。我们可以利用其支持离线功能的特点,让我们的网站可以在信号差或者离线状态下正常运行。
|
||||
要使用它也非常容易。
|
||||
|
||||
## 创建 serviceWorker
|
||||
这里已经整理好了一份代码,你只需要在网站根目录下创建一个 `sw.js` 文件,并粘贴下面的代码。
|
||||
|
||||
*sw.js*
|
||||
|
||||
```js
|
||||
/* ===========================================================
|
||||
* docsify sw.js
|
||||
* ===========================================================
|
||||
* Copyright 2016 @huxpro
|
||||
* Licensed under Apache 2.0
|
||||
* Register service worker.
|
||||
* ========================================================== */
|
||||
|
||||
const RUNTIME = 'docsify'
|
||||
const HOSTNAME_WHITELIST = [
|
||||
self.location.hostname,
|
||||
'fonts.gstatic.com',
|
||||
'fonts.googleapis.com',
|
||||
'unpkg.com'
|
||||
]
|
||||
|
||||
// The Util Function to hack URLs of intercepted requests
|
||||
const getFixedUrl = (req) => {
|
||||
var now = Date.now()
|
||||
var url = new URL(req.url)
|
||||
|
||||
// 1. fixed http URL
|
||||
// Just keep syncing with location.protocol
|
||||
// fetch(httpURL) belongs to active mixed content.
|
||||
// And fetch(httpRequest) is not supported yet.
|
||||
url.protocol = self.location.protocol
|
||||
|
||||
// 2. add query for caching-busting.
|
||||
// Github Pages served with Cache-Control: max-age=600
|
||||
// max-age on mutable content is error-prone, with SW life of bugs can even extend.
|
||||
// Until cache mode of Fetch API landed, we have to workaround cache-busting with query string.
|
||||
// Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190
|
||||
if (url.hostname === self.location.hostname) {
|
||||
url.search += (url.search ? '&' : '?') + 'cache-bust=' + now
|
||||
}
|
||||
return url.href
|
||||
}
|
||||
|
||||
/**
|
||||
* @Lifecycle Activate
|
||||
* New one activated when old isnt being used.
|
||||
*
|
||||
* waitUntil(): activating ====> activated
|
||||
*/
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(self.clients.claim())
|
||||
})
|
||||
|
||||
/**
|
||||
* @Functional Fetch
|
||||
* All network requests are being intercepted here.
|
||||
*
|
||||
* void respondWith(Promise<Response> r)
|
||||
*/
|
||||
self.addEventListener('fetch', event => {
|
||||
// Skip some of cross-origin requests, like those for Google Analytics.
|
||||
if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) {
|
||||
// Stale-while-revalidate
|
||||
// similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale
|
||||
// Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1
|
||||
const cached = caches.match(event.request)
|
||||
const fixedUrl = getFixedUrl(event.request)
|
||||
const fetched = fetch(fixedUrl, { cache: 'no-store' })
|
||||
const fetchedCopy = fetched.then(resp => resp.clone())
|
||||
|
||||
// Call respondWith() with whatever we get first.
|
||||
// If the fetch fails (e.g disconnected), wait for the cache.
|
||||
// If there’s nothing in cache, wait for the fetch.
|
||||
// If neither yields a response, return offline pages.
|
||||
event.respondWith(
|
||||
Promise.race([fetched.catch(_ => cached), cached])
|
||||
.then(resp => resp || fetched)
|
||||
.catch(_ => { /* eat any errors */ })
|
||||
)
|
||||
|
||||
// Update the cache with the version we fetched (only for ok status)
|
||||
event.waitUntil(
|
||||
Promise.all([fetchedCopy, caches.open(RUNTIME)])
|
||||
.then(([response, cache]) => response.ok && cache.put(event.request, response))
|
||||
.catch(_ => { /* eat any errors */ })
|
||||
)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## 注册
|
||||
|
||||
现在,到 `index.html` 里注册它。这个功能只能工作在一些现代浏览器上,所以我们需要加个判断。
|
||||
|
||||
*index.html*
|
||||
|
||||
```html
|
||||
<script>
|
||||
if (typeof navigator.serviceWorker !== 'undefined') {
|
||||
navigator.serviceWorker.register('sw.js')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 体验一下
|
||||
|
||||
发布你的网站,并开始享受离线模式的魔力吧!:ghost: 当然你现在看到的 docsify 的文档网站已经支持离线模式了,你可以关掉 Wi-Fi 体验一下。
|
||||
@@ -59,3 +59,25 @@ docsify serve docs
|
||||
```bash
|
||||
cd docs && python -m SimpleHTTPServer 3000
|
||||
```
|
||||
|
||||
## Loading 提示
|
||||
|
||||
初始化时会显示 `Loading...` 内容,你可以自定义提示信息。
|
||||
|
||||
*index.html*
|
||||
```html
|
||||
<div id="app">加载中</div>
|
||||
```
|
||||
|
||||
如果更改了 `el` 的配置,需要将该元素加上 `data-app` 属性。
|
||||
|
||||
*index.html*
|
||||
```html
|
||||
<div data-app id="main">加载中</div>
|
||||
|
||||
<script>
|
||||
window.$docsify = {
|
||||
el: '#main'
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
+35
-1
@@ -10,4 +10,38 @@
|
||||
|
||||
!> CSS 的压缩文件位于 `/lib/themes/`
|
||||
|
||||
如果你有其他想法或者想开发别的主题,欢迎提 [PR](https://github.com/QingWei-Li/docsify/pulls)。
|
||||
如果你有其他想法或者想开发别的主题,欢迎提 [PR](https://github.com/QingWei-Li/docsify/pulls)。
|
||||
|
||||
#### 点击切换主题
|
||||
|
||||
|
||||
<div class="demo-theme-preview">
|
||||
<a data-theme="vue">vue.css</a>
|
||||
<a data-theme="buble">buble.css</a>
|
||||
<a data-theme="dark">dark.css</a>
|
||||
</div>
|
||||
|
||||
|
||||
<style>
|
||||
.demo-theme-preview a {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.demo-theme-preview a:hover {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
var preview = Docsify.dom.find('.demo-theme-preview');
|
||||
var themes = Docsify.dom.findAll('[rel="stylesheet"]');
|
||||
|
||||
preview.onclick = function (e) {
|
||||
var title = e.target.getAttribute('data-theme')
|
||||
|
||||
themes.forEach(function (theme) {
|
||||
theme.disabled = theme.title !== title
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@
|
||||
<script src="//unpkg.com/docsify"></script>
|
||||
```
|
||||
|
||||
接着就可以愉快地在 Markdown 里写 Vue 了。默认会执行 `new Vue({ el: 'main' })` 创建示例。
|
||||
接着就可以愉快地在 Markdown 里写 Vue 了。默认会执行 `new Vue({ el: '#main' })` 创建示例。
|
||||
|
||||
*README.md*
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
<script>
|
||||
new Vue({
|
||||
el: 'main',
|
||||
el: '#main',
|
||||
data: { msg: 'Vue' }
|
||||
})
|
||||
</script>
|
||||
@@ -75,7 +75,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
module.exports = {
|
||||
data: function () {
|
||||
return { name: 'Vue' }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# 自定义插件
|
||||
|
||||
docsify 提供了一套插件机制,其中提供的钩子(hook)支持处理异步逻辑,可以很方便的扩展功能。
|
||||
|
||||
## 完整功能
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
plugins: [
|
||||
function (hook, vm) {
|
||||
hook.init(function() {
|
||||
// 初始化时调用,只调用一次,没有参数。
|
||||
})
|
||||
|
||||
hook.beforeEach(function(content) {
|
||||
// 每次开始解析 Markdown 内容时调用
|
||||
// ...
|
||||
return content
|
||||
})
|
||||
|
||||
hook.afterEach(function(html, next) {
|
||||
// 解析成 html 后调用。beforeEach 和 afterEach 支持处理异步逻辑
|
||||
// ...
|
||||
// 异步处理完成后调用 next(html) 返回结果
|
||||
next(html)
|
||||
})
|
||||
|
||||
hook.doneEach(function() {
|
||||
// 每次路由切换时数据全部加载完成后调用,没有参数。
|
||||
// ...
|
||||
})
|
||||
|
||||
hook.mounted(function() {
|
||||
// 初始化完成后调用 ,只调用一次,没有参数。
|
||||
})
|
||||
|
||||
hook.ready(function() {
|
||||
// 初始化并第一次加完成数据后调用,没有参数。
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
!> 如果需要用 docsify 的内部方法,可以通过 `window.Docsify` 获取,通过 `vm` 获取当前实例。
|
||||
|
||||
## 例子
|
||||
|
||||
给每个页面的末尾加上 `footer`
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
plugins: [
|
||||
function (hook) {
|
||||
var footer = [
|
||||
'<hr/>',
|
||||
'<footer>',
|
||||
'<span><a href="https://github.com/QingWei-Li">cinwell</a> ©2017.</span>',
|
||||
'<span>Proudly published with <a href="https://github.com/QingWei-Li/docsify" target="_blank">docsify</a>.</span>',
|
||||
'</footer>'
|
||||
].join('')
|
||||
|
||||
hook.afterEach(function (html) {
|
||||
return html + footer
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
+1247
-778
File diff suppressed because it is too large
Load Diff
Vendored
+2
-2
File diff suppressed because one or more lines are too long
@@ -0,0 +1,159 @@
|
||||
this.D = this.D || {};
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var AllGithubEmoji = ['+1', '100', '1234', '8ball', 'a', 'ab', 'abc', 'abcd',
|
||||
'accept', 'aerial_tramway', 'airplane', 'alarm_clock', 'alien', 'ambulance',
|
||||
'anchor', 'angel', 'anger', 'angry', 'anguished', 'ant', 'apple', 'aquarius',
|
||||
'aries', 'arrow_backward', 'arrow_double_down', 'arrow_double_up', 'arrow_down',
|
||||
'arrow_down_small', 'arrow_forward', 'arrow_heading_down', 'arrow_heading_up',
|
||||
'arrow_left', 'arrow_lower_left', 'arrow_lower_right', 'arrow_right',
|
||||
'arrow_right_hook', 'arrow_up', 'arrow_up_down', 'arrow_up_small', 'arrow_upper_left',
|
||||
'arrow_upper_right', 'arrows_clockwise', 'arrows_counterclockwise', 'art',
|
||||
'articulated_lorry', 'astonished', 'athletic_shoe', 'atm', 'b', 'baby', 'baby_bottle',
|
||||
'baby_chick', 'baby_symbol', 'back', 'baggage_claim', 'balloon', 'ballot_box_with_check',
|
||||
'bamboo', 'banana', 'bangbang', 'bank', 'bar_chart', 'barber', 'baseball', 'basketball',
|
||||
'bath', 'bathtub', 'battery', 'bear', 'bee', 'beer', 'beers', 'beetle', 'beginner',
|
||||
'bell', 'bento', 'bicyclist', 'bike', 'bikini', 'bird', 'birthday', 'black_circle',
|
||||
'black_joker', 'black_large_square', 'black_medium_small_square', 'black_medium_square',
|
||||
'black_nib', 'black_small_square', 'black_square_button', 'blossom', 'blowfish',
|
||||
'blue_book', 'blue_car', 'blue_heart', 'blush', 'boar', 'boat', 'bomb', 'book',
|
||||
'bookmark', 'bookmark_tabs', 'books', 'boom', 'boot', 'bouquet', 'bow', 'bowling',
|
||||
'bowtie', 'boy', 'bread', 'bride_with_veil', 'bridge_at_night', 'briefcase',
|
||||
'broken_heart', 'bug', 'bulb', 'bullettrain_front', 'bullettrain_side', 'bus',
|
||||
'busstop', 'bust_in_silhouette', 'busts_in_silhouette', 'cactus', 'cake', 'calendar',
|
||||
'calling', 'camel', 'camera', 'cancer', 'candy', 'capital_abcd', 'capricorn', 'car',
|
||||
'card_index', 'carousel_horse', 'cat', 'cat2', 'cd', 'chart', 'chart_with_downwards_trend',
|
||||
'chart_with_upwards_trend', 'checkered_flag', 'cherries', 'cherry_blossom', 'chestnut',
|
||||
'chicken', 'children_crossing', 'chocolate_bar', 'christmas_tree', 'church', 'cinema',
|
||||
'circus_tent', 'city_sunrise', 'city_sunset', 'cl', 'clap', 'clapper', 'clipboard',
|
||||
'clock1', 'clock10', 'clock1030', 'clock11', 'clock1130', 'clock12', 'clock1230',
|
||||
'clock130', 'clock2', 'clock230', 'clock3', 'clock330', 'clock4', 'clock430',
|
||||
'clock5', 'clock530', 'clock6', 'clock630', 'clock7', 'clock730', 'clock8', 'clock830',
|
||||
'clock9', 'clock930', 'closed_book', 'closed_lock_with_key', 'closed_umbrella',
|
||||
'cloud', 'clubs', 'cn', 'cocktail', 'coffee', 'cold_sweat', 'collision', 'computer',
|
||||
'confetti_ball', 'confounded', 'confused', 'congratulations', 'construction',
|
||||
'construction_worker', 'convenience_store', 'cookie', 'cool', 'cop', 'copyright',
|
||||
'corn', 'couple', 'couple_with_heart', 'couplekiss', 'cow', 'cow2', 'credit_card',
|
||||
'crescent_moon', 'crocodile', 'crossed_flags', 'crown', 'cry', 'crying_cat_face',
|
||||
'crystal_ball', 'cupid', 'curly_loop', 'currency_exchange', 'curry', 'custard',
|
||||
'customs', 'cyclone', 'dancer', 'dancers', 'dango', 'dart', 'dash', 'date', 'de',
|
||||
'deciduous_tree', 'department_store', 'diamond_shape_with_a_dot_inside', 'diamonds',
|
||||
'disappointed', 'disappointed_relieved', 'dizzy', 'dizzy_face', 'do_not_litter',
|
||||
'dog', 'dog2', 'dollar', 'dolls', 'dolphin', 'door', 'doughnut', 'dragon',
|
||||
'dragon_face', 'dress', 'dromedary_camel', 'droplet', 'dvd', 'e-mail', 'ear',
|
||||
'ear_of_rice', 'earth_africa', 'earth_americas', 'earth_asia', 'egg', 'eggplant',
|
||||
'eight', 'eight_pointed_black_star', 'eight_spoked_asterisk', 'electric_plug',
|
||||
'elephant', 'email', 'end', 'envelope', 'envelope_with_arrow', 'es', 'euro',
|
||||
'european_castle', 'european_post_office', 'evergreen_tree', 'exclamation',
|
||||
'expressionless', 'eyeglasses', 'eyes', 'facepunch', 'factory', 'fallen_leaf',
|
||||
'family', 'fast_forward', 'fax', 'fearful', 'feelsgood', 'feet', 'ferris_wheel',
|
||||
'file_folder', 'finnadie', 'fire', 'fire_engine', 'fireworks', 'first_quarter_moon',
|
||||
'first_quarter_moon_with_face', 'fish', 'fish_cake', 'fishing_pole_and_fish',
|
||||
'fist', 'five', 'flags', 'flashlight', 'flipper', 'floppy_disk', 'flower_playing_cards',
|
||||
'flushed', 'foggy', 'football', 'footprints', 'fork_and_knife', 'fountain',
|
||||
'four', 'four_leaf_clover', 'fr', 'free', 'fried_shrimp', 'fries', 'frog',
|
||||
'frowning', 'fu', 'fuelpump', 'full_moon', 'full_moon_with_face', 'game_die',
|
||||
'gb', 'gem', 'gemini', 'ghost', 'gift', 'gift_heart', 'girl', 'globe_with_meridians',
|
||||
'goat', 'goberserk', 'godmode', 'golf', 'grapes', 'green_apple', 'green_book',
|
||||
'green_heart', 'grey_exclamation', 'grey_question', 'grimacing', 'grin',
|
||||
'grinning', 'guardsman', 'guitar', 'gun', 'haircut', 'hamburger', 'hammer',
|
||||
'hamster', 'hand', 'handbag', 'hankey', 'hash', 'hatched_chick', 'hatching_chick',
|
||||
'headphones', 'hear_no_evil', 'heart', 'heart_decoration', 'heart_eyes',
|
||||
'heart_eyes_cat', 'heartbeat', 'heartpulse', 'hearts', 'heavy_check_mark',
|
||||
'heavy_division_sign', 'heavy_dollar_sign', 'heavy_exclamation_mark', 'heavy_minus_sign',
|
||||
'heavy_multiplication_x', 'heavy_plus_sign', 'helicopter', 'herb', 'hibiscus',
|
||||
'high_brightness', 'high_heel', 'hocho', 'honey_pot', 'honeybee', 'horse',
|
||||
'horse_racing', 'hospital', 'hotel', 'hotsprings', 'hourglass', 'hourglass_flowing_sand',
|
||||
'house', 'house_with_garden', 'hurtrealbad', 'hushed', 'ice_cream', 'icecream',
|
||||
'id', 'ideograph_advantage', 'imp', 'inbox_tray', 'incoming_envelope',
|
||||
'information_desk_person', 'information_source', 'innocent', 'interrobang',
|
||||
'iphone', 'it', 'izakaya_lantern', 'jack_o_lantern', 'japan', 'japanese_castle',
|
||||
'japanese_goblin', 'japanese_ogre', 'jeans', 'joy', 'joy_cat', 'jp', 'key',
|
||||
'keycap_ten', 'kimono', 'kiss', 'kissing', 'kissing_cat', 'kissing_closed_eyes',
|
||||
'kissing_heart', 'kissing_smiling_eyes', 'koala', 'koko', 'kr', 'lantern',
|
||||
'large_blue_circle', 'large_blue_diamond', 'large_orange_diamond', 'last_quarter_moon',
|
||||
'last_quarter_moon_with_face', 'laughing', 'leaves', 'ledger', 'left_luggage',
|
||||
'left_right_arrow', 'leftwards_arrow_with_hook', 'lemon', 'leo', 'leopard',
|
||||
'libra', 'light_rail', 'link', 'lips', 'lipstick', 'lock', 'lock_with_ink_pen',
|
||||
'lollipop', 'loop', 'loud_sound', 'loudspeaker', 'love_hotel', 'love_letter',
|
||||
'low_brightness', 'm', 'mag', 'mag_right', 'mahjong', 'mailbox', 'mailbox_closed',
|
||||
'mailbox_with_mail', 'mailbox_with_no_mail', 'man', 'man_with_gua_pi_mao',
|
||||
'man_with_turban', 'mans_shoe', 'maple_leaf', 'mask', 'massage', 'meat_on_bone',
|
||||
'mega', 'melon', 'memo', 'mens', 'metal', 'metro', 'microphone', 'microscope',
|
||||
'milky_way', 'minibus', 'minidisc', 'mobile_phone_off', 'money_with_wings',
|
||||
'moneybag', 'monkey', 'monkey_face', 'monorail', 'moon', 'mortar_board', 'mount_fuji',
|
||||
'mountain_bicyclist', 'mountain_cableway', 'mountain_railway', 'mouse', 'mouse2',
|
||||
'movie_camera', 'moyai', 'muscle', 'mushroom', 'musical_keyboard', 'musical_note',
|
||||
'musical_score', 'mute', 'nail_care', 'name_badge', 'neckbeard', 'necktie',
|
||||
'negative_squared_cross_mark', 'neutral_face', 'new', 'new_moon', 'new_moon_with_face',
|
||||
'newspaper', 'ng', 'night_with_stars', 'nine', 'no_bell', 'no_bicycles', 'no_entry',
|
||||
'no_entry_sign', 'no_good', 'no_mobile_phones', 'no_mouth', 'no_pedestrians',
|
||||
'no_smoking', 'non-potable_water', 'nose', 'notebook', 'notebook_with_decorative_cover',
|
||||
'notes', 'nut_and_bolt', 'o', 'o2', 'ocean', 'octocat', 'octopus', 'oden', 'office',
|
||||
'ok', 'ok_hand', 'ok_woman', 'older_man', 'older_woman', 'on', 'oncoming_automobile',
|
||||
'oncoming_bus', 'oncoming_police_car', 'oncoming_taxi', 'one', 'open_book',
|
||||
'open_file_folder', 'open_hands', 'open_mouth', 'ophiuchus', 'orange_book',
|
||||
'outbox_tray', 'ox', 'package', 'page_facing_up', 'page_with_curl', 'pager',
|
||||
'palm_tree', 'panda_face', 'paperclip', 'parking', 'part_alternation_mark',
|
||||
'partly_sunny', 'passport_control', 'paw_prints', 'peach', 'pear', 'pencil',
|
||||
'pencil2', 'penguin', 'pensive', 'performing_arts', 'persevere', 'person_frowning',
|
||||
'person_with_blond_hair', 'person_with_pouting_face', 'phone', 'pig', 'pig2',
|
||||
'pig_nose', 'pill', 'pineapple', 'pisces', 'pizza', 'point_down', 'point_left',
|
||||
'point_right', 'point_up', 'point_up_2', 'police_car', 'poodle', 'poop',
|
||||
'post_office', 'postal_horn', 'postbox', 'potable_water', 'pouch', 'poultry_leg',
|
||||
'pound', 'pouting_cat', 'pray', 'princess', 'punch', 'purple_heart', 'purse',
|
||||
'pushpin', 'put_litter_in_its_place', 'question', 'rabbit', 'rabbit2', 'racehorse',
|
||||
'radio', 'radio_button', 'rage', 'rage1', 'rage2', 'rage3', 'rage4', 'railway_car',
|
||||
'rainbow', 'raised_hand', 'raised_hands', 'raising_hand', 'ram', 'ramen', 'rat',
|
||||
'recycle', 'red_car', 'red_circle', 'registered', 'relaxed', 'relieved', 'repeat',
|
||||
'repeat_one', 'restroom', 'revolving_hearts', 'rewind', 'ribbon', 'rice',
|
||||
'rice_ball', 'rice_cracker', 'rice_scene', 'ring', 'rocket', 'roller_coaster',
|
||||
'rooster', 'rose', 'rotating_light', 'round_pushpin', 'rowboat', 'ru', 'rugby_football',
|
||||
'runner', 'running', 'running_shirt_with_sash', 'sa', 'sagittarius', 'sailboat',
|
||||
'sake', 'sandal', 'santa', 'satellite', 'satisfied', 'saxophone', 'school',
|
||||
'school_satchel', 'scissors', 'scorpius', 'scream', 'scream_cat', 'scroll',
|
||||
'seat', 'secret', 'see_no_evil', 'seedling', 'seven', 'shaved_ice', 'sheep',
|
||||
'shell', 'ship', 'shipit', 'shirt', 'shit', 'shoe', 'shower', 'signal_strength',
|
||||
'six', 'six_pointed_star', 'ski', 'skull', 'sleeping', 'sleepy', 'slot_machine',
|
||||
'small_blue_diamond', 'small_orange_diamond', 'small_red_triangle',
|
||||
'small_red_triangle_down', 'smile', 'smile_cat', 'smiley', 'smiley_cat',
|
||||
'smiling_imp', 'smirk', 'smirk_cat', 'smoking', 'snail', 'snake', 'snowboarder',
|
||||
'snowflake', 'snowman', 'sob', 'soccer', 'soon', 'sos', 'sound', 'space_invader',
|
||||
'spades', 'spaghetti', 'sparkle', 'sparkler', 'sparkles', 'sparkling_heart',
|
||||
'speak_no_evil', 'speaker', 'speech_balloon', 'speedboat', 'squirrel', 'star',
|
||||
'star2', 'stars', 'station', 'statue_of_liberty', 'steam_locomotive', 'stew',
|
||||
'straight_ruler', 'strawberry', 'stuck_out_tongue', 'stuck_out_tongue_closed_eyes',
|
||||
'stuck_out_tongue_winking_eye', 'sun_with_face', 'sunflower', 'sunglasses',
|
||||
'sunny', 'sunrise', 'sunrise_over_mountains', 'surfer', 'sushi', 'suspect',
|
||||
'suspension_railway', 'sweat', 'sweat_drops', 'sweat_smile', 'sweet_potato',
|
||||
'swimmer', 'symbols', 'syringe', 'tada', 'tanabata_tree', 'tangerine', 'taurus',
|
||||
'taxi', 'tea', 'telephone', 'telephone_receiver', 'telescope', 'tennis', 'tent',
|
||||
'thought_balloon', 'three', 'thumbsdown', 'thumbsup', 'ticket', 'tiger', 'tiger2',
|
||||
'tired_face', 'tm', 'toilet', 'tokyo_tower', 'tomato', 'tongue', 'top', 'tophat',
|
||||
'tractor', 'traffic_light', 'train', 'train2', 'tram', 'triangular_flag_on_post',
|
||||
'triangular_ruler', 'trident', 'triumph', 'trolleybus', 'trollface', 'trophy',
|
||||
'tropical_drink', 'tropical_fish', 'truck', 'trumpet', 'tshirt', 'tulip',
|
||||
'turtle', 'tv', 'twisted_rightwards_arrows', 'two', 'two_hearts', 'two_men_holding_hands',
|
||||
'two_women_holding_hands', 'u5272', 'u5408', 'u55b6', 'u6307', 'u6708', 'u6709',
|
||||
'u6e80', 'u7121', 'u7533', 'u7981', 'u7a7a', 'uk', 'umbrella', 'unamused',
|
||||
'underage', 'unlock', 'up', 'us', 'v', 'vertical_traffic_light', 'vhs',
|
||||
'vibration_mode', 'video_camera', 'video_game', 'violin', 'virgo', 'volcano',
|
||||
'vs', 'walking', 'waning_crescent_moon', 'waning_gibbous_moon', 'warning',
|
||||
'watch', 'water_buffalo', 'watermelon', 'wave', 'wavy_dash', 'waxing_crescent_moon',
|
||||
'waxing_gibbous_moon', 'wc', 'weary', 'wedding', 'whale', 'whale2', 'wheelchair',
|
||||
'white_check_mark', 'white_circle', 'white_flower', 'white_large_square',
|
||||
'white_medium_small_square', 'white_medium_square', 'white_small_square',
|
||||
'white_square_button', 'wind_chime', 'wine_glass', 'wink', 'wolf', 'woman',
|
||||
'womans_clothes', 'womans_hat', 'womens', 'worried', 'wrench', 'x', 'yellow_heart',
|
||||
'yen', 'yum', 'zap', 'zero', 'zzz'];
|
||||
|
||||
// emoji from All-Github-Emoji-Icons
|
||||
// https://github.com/scotch-io/All-Github-Emoji-Icons
|
||||
window.emojify = function (match, $1) {
|
||||
return AllGithubEmoji.indexOf($1) === -1
|
||||
? match
|
||||
: '<img class="emoji" src="https://assets-cdn.github.com/images/icons/emoji/' + $1 + '.png" alt="' + $1 + '" />'
|
||||
};
|
||||
|
||||
}());
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,25 @@
|
||||
this.D = this.D || {};
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function handleExternalScript () {
|
||||
var container = Docsify.dom.getNode('#main');
|
||||
var script = Docsify.dom.find(container, 'script');
|
||||
|
||||
if (script && script.src) {
|
||||
var newScript = document.createElement('script');['src', 'async', 'defer'].forEach(function (attribute) {
|
||||
newScript[attribute] = script[attribute];
|
||||
});
|
||||
|
||||
script.parentNode.removeChild(script);
|
||||
container.appendChild(newScript);
|
||||
}
|
||||
}
|
||||
|
||||
var install = function (hook) {
|
||||
hook.doneEach(handleExternalScript);
|
||||
};
|
||||
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins);
|
||||
|
||||
}());
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
this.D=this.D||{},function(){"use strict";function i(){var i=Docsify.dom.getNode("#main"),n=Docsify.dom.find(i,"script");if(n&&n.src){var c=document.createElement("script");["src","async","defer"].forEach(function(i){c[i]=n[i]}),n.parentNode.removeChild(n),i.appendChild(c)}}var n=function(n){n.doneEach(i)};window.$docsify.plugins=[].concat(n,window.$docsify.plugins)}();
|
||||
@@ -0,0 +1,503 @@
|
||||
this.D = this.D || {};
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Fork https://github.com/egoist/docute/blob/master/src/utils/yaml.js
|
||||
*/
|
||||
/* eslint-disable */
|
||||
/*
|
||||
YAML parser for Javascript
|
||||
Author: Diogo Costa
|
||||
This program is released under the MIT License as follows:
|
||||
Copyright (c) 2011 Diogo Costa (costa.h4evr@gmail.com)
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name YAML
|
||||
* @namespace
|
||||
*/
|
||||
|
||||
|
||||
var errors = [];
|
||||
var reference_blocks = [];
|
||||
var processing_time = 0;
|
||||
var regex$1 =
|
||||
{
|
||||
"regLevel" : new RegExp("^([\\s\\-]+)"),
|
||||
"invalidLine" : new RegExp("^\\-\\-\\-|^\\.\\.\\.|^\\s*#.*|^\\s*$"),
|
||||
"dashesString" : new RegExp("^\\s*\\\"([^\\\"]*)\\\"\\s*$"),
|
||||
"quotesString" : new RegExp("^\\s*\\\'([^\\\']*)\\\'\\s*$"),
|
||||
"float" : new RegExp("^[+-]?[0-9]+\\.[0-9]+(e[+-]?[0-9]+(\\.[0-9]+)?)?$"),
|
||||
"integer" : new RegExp("^[+-]?[0-9]+$"),
|
||||
"array" : new RegExp("\\[\\s*(.*)\\s*\\]"),
|
||||
"map" : new RegExp("\\{\\s*(.*)\\s*\\}"),
|
||||
"key_value" : new RegExp("([a-z0-9_-][ a-z0-9_-]*):( .+)", "i"),
|
||||
"single_key_value" : new RegExp("^([a-z0-9_-][ a-z0-9_-]*):( .+?)$", "i"),
|
||||
"key" : new RegExp("([a-z0-9_-][ a-z0-9_-]+):( .+)?", "i"),
|
||||
"item" : new RegExp("^-\\s+"),
|
||||
"trim" : new RegExp("^\\s+|\\s+$"),
|
||||
"comment" : new RegExp("([^\\\'\\\"#]+([\\\'\\\"][^\\\'\\\"]*[\\\'\\\"])*)*(#.*)?")
|
||||
};
|
||||
|
||||
/**
|
||||
* @class A block of lines of a given level.
|
||||
* @param {int} lvl The block's level.
|
||||
* @private
|
||||
*/
|
||||
function Block(lvl) {
|
||||
return {
|
||||
/* The block's parent */
|
||||
parent: null,
|
||||
/* Number of children */
|
||||
length: 0,
|
||||
/* Block's level */
|
||||
level: lvl,
|
||||
/* Lines of code to process */
|
||||
lines: [],
|
||||
/* Blocks with greater level */
|
||||
children : [],
|
||||
/* Add a block to the children collection */
|
||||
addChild : function(obj) {
|
||||
this.children.push(obj);
|
||||
obj.parent = this;
|
||||
++this.length;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function parser$1(str) {
|
||||
var regLevel = regex$1["regLevel"];
|
||||
var invalidLine = regex$1["invalidLine"];
|
||||
var lines = str.split("\n");
|
||||
var m;
|
||||
var level = 0, curLevel = 0;
|
||||
|
||||
var blocks = [];
|
||||
|
||||
var result = new Block(-1);
|
||||
var currentBlock = new Block(0);
|
||||
result.addChild(currentBlock);
|
||||
var levels = [];
|
||||
var line = "";
|
||||
|
||||
blocks.push(currentBlock);
|
||||
levels.push(level);
|
||||
|
||||
for(var i = 0, len = lines.length; i < len; ++i) {
|
||||
line = lines[i];
|
||||
|
||||
if(line.match(invalidLine)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(m = regLevel.exec(line)) {
|
||||
level = m[1].length;
|
||||
} else
|
||||
{ level = 0; }
|
||||
|
||||
if(level > curLevel) {
|
||||
var oldBlock = currentBlock;
|
||||
currentBlock = new Block(level);
|
||||
oldBlock.addChild(currentBlock);
|
||||
blocks.push(currentBlock);
|
||||
levels.push(level);
|
||||
} else if(level < curLevel) {
|
||||
var added = false;
|
||||
|
||||
var k = levels.length - 1;
|
||||
for(; k >= 0; --k) {
|
||||
if(levels[k] == level) {
|
||||
currentBlock = new Block(level);
|
||||
blocks.push(currentBlock);
|
||||
levels.push(level);
|
||||
if(blocks[k].parent!= null)
|
||||
{ blocks[k].parent.addChild(currentBlock); }
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!added) {
|
||||
errors.push("Error: Invalid indentation at line " + i + ": " + line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
currentBlock.lines.push(line.replace(regex$1["trim"], ""));
|
||||
curLevel = level;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function processValue(val) {
|
||||
val = val.replace(regex$1["trim"], "");
|
||||
var m = null;
|
||||
|
||||
if(val == 'true') {
|
||||
return true;
|
||||
} else if(val == 'false') {
|
||||
return false;
|
||||
} else if(val == '.NaN') {
|
||||
return Number.NaN;
|
||||
} else if(val == 'null') {
|
||||
return null;
|
||||
} else if(val == '.inf') {
|
||||
return Number.POSITIVE_INFINITY;
|
||||
} else if(val == '-.inf') {
|
||||
return Number.NEGATIVE_INFINITY;
|
||||
} else if(m = val.match(regex$1["dashesString"])) {
|
||||
return m[1];
|
||||
} else if(m = val.match(regex$1["quotesString"])) {
|
||||
return m[1];
|
||||
} else if(m = val.match(regex$1["float"])) {
|
||||
return parseFloat(m[0]);
|
||||
} else if(m = val.match(regex$1["integer"])) {
|
||||
return parseInt(m[0]);
|
||||
} else if( !isNaN(m = Date.parse(val))) {
|
||||
return new Date(m);
|
||||
} else if(m = val.match(regex$1["single_key_value"])) {
|
||||
var res = {};
|
||||
res[m[1]] = processValue(m[2]);
|
||||
return res;
|
||||
} else if(m = val.match(regex$1["array"])){
|
||||
var count = 0, c = ' ';
|
||||
var res = [];
|
||||
var content = "";
|
||||
var str = false;
|
||||
for(var j = 0, lenJ = m[1].length; j < lenJ; ++j) {
|
||||
c = m[1][j];
|
||||
if(c == '\'' || c == '"') {
|
||||
if(str === false) {
|
||||
str = c;
|
||||
content += c;
|
||||
continue;
|
||||
} else if((c == '\'' && str == '\'') || (c == '"' && str == '"')) {
|
||||
str = false;
|
||||
content += c;
|
||||
continue;
|
||||
}
|
||||
} else if(str === false && (c == '[' || c == '{')) {
|
||||
++count;
|
||||
} else if(str === false && (c == ']' || c == '}')) {
|
||||
--count;
|
||||
} else if(str === false && count == 0 && c == ',') {
|
||||
res.push(processValue(content));
|
||||
content = "";
|
||||
continue;
|
||||
}
|
||||
|
||||
content += c;
|
||||
}
|
||||
|
||||
if(content.length > 0)
|
||||
{ res.push(processValue(content)); }
|
||||
return res;
|
||||
} else if(m = val.match(regex$1["map"])){
|
||||
var count = 0, c = ' ';
|
||||
var res = [];
|
||||
var content = "";
|
||||
var str = false;
|
||||
for(var j = 0, lenJ = m[1].length; j < lenJ; ++j) {
|
||||
c = m[1][j];
|
||||
if(c == '\'' || c == '"') {
|
||||
if(str === false) {
|
||||
str = c;
|
||||
content += c;
|
||||
continue;
|
||||
} else if((c == '\'' && str == '\'') || (c == '"' && str == '"')) {
|
||||
str = false;
|
||||
content += c;
|
||||
continue;
|
||||
}
|
||||
} else if(str === false && (c == '[' || c == '{')) {
|
||||
++count;
|
||||
} else if(str === false && (c == ']' || c == '}')) {
|
||||
--count;
|
||||
} else if(str === false && count == 0 && c == ',') {
|
||||
res.push(content);
|
||||
content = "";
|
||||
continue;
|
||||
}
|
||||
|
||||
content += c;
|
||||
}
|
||||
|
||||
if(content.length > 0)
|
||||
{ res.push(content); }
|
||||
|
||||
var newRes = {};
|
||||
for(var j = 0, lenJ = res.length; j < lenJ; ++j) {
|
||||
if(m = res[j].match(regex$1["key_value"])) {
|
||||
newRes[m[1]] = processValue(m[2]);
|
||||
}
|
||||
}
|
||||
|
||||
return newRes;
|
||||
} else
|
||||
{ return val; }
|
||||
}
|
||||
|
||||
function processFoldedBlock(block) {
|
||||
var lines = block.lines;
|
||||
var children = block.children;
|
||||
var str = lines.join(" ");
|
||||
var chunks = [str];
|
||||
for(var i = 0, len = children.length; i < len; ++i) {
|
||||
chunks.push(processFoldedBlock(children[i]));
|
||||
}
|
||||
return chunks.join("\n");
|
||||
}
|
||||
|
||||
function processLiteralBlock(block) {
|
||||
var lines = block.lines;
|
||||
var children = block.children;
|
||||
var str = lines.join("\n");
|
||||
for(var i = 0, len = children.length; i < len; ++i) {
|
||||
str += processLiteralBlock(children[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function processBlock(blocks) {
|
||||
var m = null;
|
||||
var res = {};
|
||||
var lines = null;
|
||||
var children = null;
|
||||
var currentObj = null;
|
||||
|
||||
var level = -1;
|
||||
|
||||
var processedBlocks = [];
|
||||
|
||||
var isMap = true;
|
||||
|
||||
for(var j = 0, lenJ = blocks.length; j < lenJ; ++j) {
|
||||
|
||||
if(level != -1 && level != blocks[j].level)
|
||||
{ continue; }
|
||||
|
||||
processedBlocks.push(j);
|
||||
|
||||
level = blocks[j].level;
|
||||
lines = blocks[j].lines;
|
||||
children = blocks[j].children;
|
||||
currentObj = null;
|
||||
|
||||
for(var i = 0, len = lines.length; i < len; ++i) {
|
||||
var line = lines[i];
|
||||
|
||||
if(m = line.match(regex$1["key"])) {
|
||||
var key = m[1];
|
||||
|
||||
if(key[0] == '-') {
|
||||
key = key.replace(regex$1["item"], "");
|
||||
if (isMap) {
|
||||
isMap = false;
|
||||
if (typeof(res.length) === "undefined") {
|
||||
res = [];
|
||||
}
|
||||
}
|
||||
if(currentObj != null) { res.push(currentObj); }
|
||||
currentObj = {};
|
||||
isMap = true;
|
||||
}
|
||||
|
||||
if(typeof m[2] != "undefined") {
|
||||
var value = m[2].replace(regex$1["trim"], "");
|
||||
if(value[0] == '&') {
|
||||
var nb = processBlock(children);
|
||||
if(currentObj != null) { currentObj[key] = nb; }
|
||||
else { res[key] = nb; }
|
||||
reference_blocks[value.substr(1)] = nb;
|
||||
} else if(value[0] == '|') {
|
||||
if(currentObj != null) { currentObj[key] = processLiteralBlock(children.shift()); }
|
||||
else { res[key] = processLiteralBlock(children.shift()); }
|
||||
} else if(value[0] == '*') {
|
||||
var v = value.substr(1);
|
||||
var no = {};
|
||||
|
||||
if(typeof reference_blocks[v] == "undefined") {
|
||||
errors.push("Reference '" + v + "' not found!");
|
||||
} else {
|
||||
for(var k in reference_blocks[v]) {
|
||||
no[k] = reference_blocks[v][k];
|
||||
}
|
||||
|
||||
if(currentObj != null) { currentObj[key] = no; }
|
||||
else { res[key] = no; }
|
||||
}
|
||||
} else if(value[0] == '>') {
|
||||
if(currentObj != null) { currentObj[key] = processFoldedBlock(children.shift()); }
|
||||
else { res[key] = processFoldedBlock(children.shift()); }
|
||||
} else {
|
||||
if(currentObj != null) { currentObj[key] = processValue(value); }
|
||||
else { res[key] = processValue(value); }
|
||||
}
|
||||
} else {
|
||||
if(currentObj != null) { currentObj[key] = processBlock(children); }
|
||||
else { res[key] = processBlock(children); }
|
||||
}
|
||||
} else if(line.match(/^-\s*$/)) {
|
||||
if (isMap) {
|
||||
isMap = false;
|
||||
if (typeof(res.length) === "undefined") {
|
||||
res = [];
|
||||
}
|
||||
}
|
||||
if(currentObj != null) { res.push(currentObj); }
|
||||
currentObj = {};
|
||||
isMap = true;
|
||||
continue;
|
||||
} else if(m = line.match(/^-\s*(.*)/)) {
|
||||
if(currentObj != null)
|
||||
{ currentObj.push(processValue(m[1])); }
|
||||
else {
|
||||
if (isMap) {
|
||||
isMap = false;
|
||||
if (typeof(res.length) === "undefined") {
|
||||
res = [];
|
||||
}
|
||||
}
|
||||
res.push(processValue(m[1]));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(currentObj != null) {
|
||||
if (isMap) {
|
||||
isMap = false;
|
||||
if (typeof(res.length) === "undefined") {
|
||||
res = [];
|
||||
}
|
||||
}
|
||||
res.push(currentObj);
|
||||
}
|
||||
}
|
||||
|
||||
for(var j = processedBlocks.length - 1; j >= 0; --j) {
|
||||
blocks.splice.call(blocks, processedBlocks[j], 1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function semanticAnalysis(blocks) {
|
||||
var res = processBlock(blocks.children);
|
||||
return res;
|
||||
}
|
||||
|
||||
function preProcess(src) {
|
||||
var m;
|
||||
var lines = src.split("\n");
|
||||
|
||||
var r = regex$1["comment"];
|
||||
|
||||
for(var i in lines) {
|
||||
if(m = lines[i].match(r)) {
|
||||
/* var cmt = "";
|
||||
if(typeof m[3] != "undefined")
|
||||
lines[i] = m[1];
|
||||
else if(typeof m[3] != "undefined")
|
||||
lines[i] = m[3];
|
||||
else
|
||||
lines[i] = "";
|
||||
*/
|
||||
if(typeof m[3] !== "undefined") {
|
||||
lines[i] = m[0].substr(0, m[0].length - m[3].length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
function load(str) {
|
||||
errors = [];
|
||||
reference_blocks = [];
|
||||
processing_time = (new Date()).getTime();
|
||||
var pre = preProcess(str);
|
||||
var doc = parser$1(pre);
|
||||
var res = semanticAnalysis(doc);
|
||||
processing_time = (new Date()).getTime() - processing_time;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fork https://github.com/egoist/docute/blob/master/src/utils/front-matter.js
|
||||
*/
|
||||
/* eslint-disable */
|
||||
var optionalByteOrderMark = '\\ufeff?';
|
||||
var pattern = '^(' +
|
||||
optionalByteOrderMark +
|
||||
'(= yaml =|---)' +
|
||||
'$([\\s\\S]*?)' +
|
||||
'(?:\\2|\\.\\.\\.)' +
|
||||
'$' +
|
||||
'' +
|
||||
'(?:\\n)?)';
|
||||
// NOTE: If this pattern uses the 'g' flag the `regex` variable definition will
|
||||
// need to be moved down into the functions that use it.
|
||||
var regex = new RegExp(pattern, 'm');
|
||||
|
||||
function extractor (string) {
|
||||
string = string || '';
|
||||
|
||||
var lines = string.split(/(\r?\n)/);
|
||||
if (lines[0] && /= yaml =|---/.test(lines[0])) {
|
||||
return parse(string)
|
||||
} else {
|
||||
return { attributes: {}, body: string }
|
||||
}
|
||||
}
|
||||
|
||||
function parse (string) {
|
||||
var match = regex.exec(string);
|
||||
|
||||
if (!match) {
|
||||
return {
|
||||
attributes: {},
|
||||
body: string
|
||||
}
|
||||
}
|
||||
|
||||
var yaml = match[match.length - 1].replace(/^\s+|\s+$/g, '');
|
||||
var attributes = load(yaml) || {};
|
||||
var body = string.replace(match[0], '');
|
||||
|
||||
return { attributes: attributes, body: body, frontmatter: yaml }
|
||||
}
|
||||
|
||||
var install = function (hook, vm) {
|
||||
hook.beforeEach(function (content) {
|
||||
var ref = extractor(content);
|
||||
var attributes = ref.attributes;
|
||||
var body = ref.body;
|
||||
|
||||
Docsify.util.merge(vm.config, attributes.config);
|
||||
|
||||
return body
|
||||
});
|
||||
};
|
||||
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins);
|
||||
|
||||
}());
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
+4
-13
@@ -1,9 +1,8 @@
|
||||
this.D = this.D || {};
|
||||
this.D.GA = (function () {
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// From https://github.com/egoist/vue-ga/blob/master/src/index.js
|
||||
|
||||
function appendScript () {
|
||||
var script = document.createElement('script');
|
||||
script.async = true;
|
||||
@@ -28,23 +27,15 @@ function collect () {
|
||||
window.ga('send', 'pageview');
|
||||
}
|
||||
|
||||
var install = function () {
|
||||
if (install.installed) { return }
|
||||
install.installed = true;
|
||||
|
||||
var install = function (hook) {
|
||||
if (!window.$docsify.ga) {
|
||||
console.error('[Docsify] ga is required.');
|
||||
return
|
||||
}
|
||||
|
||||
window.$docsify.plugins = [].concat(function (hook) {
|
||||
hook.init(collect);
|
||||
hook.beforeEach(collect);
|
||||
}, window.$docsify.plugins);
|
||||
hook.beforeEach(collect);
|
||||
};
|
||||
|
||||
var ga = install();
|
||||
|
||||
return ga;
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins);
|
||||
|
||||
}());
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
this.D=this.D||{},this.D.GA=function(){"use strict";function i(){var i=document.createElement("script");i.async=!0,i.src="https://www.google-analytics.com/analytics.js",document.body.appendChild(i)}function n(n){window.ga||(i(),window.ga=window.ga||function(){(window.ga.q=window.ga.q||[]).push(arguments)},window.ga.l=Number(new Date),window.ga("create",n,"auto"))}function o(){n(window.$docsify.ga),window.ga("set","page",location.href),window.ga("send","pageview")}var t=function(){if(!t.installed)return t.installed=!0,window.$docsify.ga?void(window.$docsify.plugins=[].concat(function(i){i.init(o),i.beforeEach(o)},window.$docsify.plugins)):void console.error("[Docsify] ga is required.")},a=t();return a}();
|
||||
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.href),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)}();
|
||||
|
||||
+178
-189
@@ -1,166 +1,83 @@
|
||||
this.D = this.D || {};
|
||||
this.D.Search = (function () {
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var INDEXS = {};
|
||||
var CONFIG = {
|
||||
placeholder: 'Type to search',
|
||||
paths: 'auto',
|
||||
maxAge: 86400000 // 1 day
|
||||
};
|
||||
var helper;
|
||||
|
||||
var isObj = function (obj) {
|
||||
return Object.prototype.toString.call(obj) === '[object Object]'
|
||||
};
|
||||
|
||||
var escapeHtml = function (string) {
|
||||
function escapeHtml (string) {
|
||||
var entityMap = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'\'': ''',
|
||||
'/': '/'
|
||||
};
|
||||
|
||||
return String(string).replace(/[&<>"'\/]/g, function (s) { return entityMap[s]; })
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* find all filepath from A tag
|
||||
*/
|
||||
var getAllPaths = function () {
|
||||
var paths = [];[].slice.call(document.querySelectorAll('a'))
|
||||
function getAllPaths () {
|
||||
var paths = [];
|
||||
|
||||
helper.dom.findAll('a:not([data-nosearch])')
|
||||
.map(function (node) {
|
||||
var href = node.href;
|
||||
if (/#\/[^#]*?$/.test(href)) {
|
||||
var path = href.replace(/^[^#]+#/, '');
|
||||
var originHref = node.getAttribute('href');
|
||||
var path = helper.route.parse(href).path;
|
||||
|
||||
if (paths.indexOf(path) <= 0) { paths.push(path); }
|
||||
if (path &&
|
||||
paths.indexOf(path) === -1 &&
|
||||
!helper.route.isAbsolutePath(originHref)) {
|
||||
paths.push(path);
|
||||
}
|
||||
});
|
||||
|
||||
return paths
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* return file path
|
||||
*/
|
||||
var genFilePath = function (path, basePath) {
|
||||
if ( basePath === void 0 ) basePath = window.$docsify.basePath;
|
||||
function saveData (maxAge) {
|
||||
localStorage.setItem('docsify.search.expires', Date.now() + maxAge);
|
||||
localStorage.setItem('docsify.search.index', JSON.stringify(INDEXS));
|
||||
}
|
||||
|
||||
var filePath = /\/$/.test(path) ? (path + "README.md") : (path + ".md");
|
||||
|
||||
filePath = basePath + filePath;
|
||||
|
||||
return filePath.replace(/\/+/g, '/')
|
||||
};
|
||||
|
||||
/**
|
||||
* generate index
|
||||
*/
|
||||
var genIndex = function (path, content) {
|
||||
function genIndex (path, content) {
|
||||
if ( content === void 0 ) content = '';
|
||||
|
||||
INDEXS[path] = { slug: '', title: '', body: '' };
|
||||
var tokens = window.marked.lexer(content);
|
||||
var slugify = window.Docsify.slugify;
|
||||
var toURL = Docsify.route.toURL;
|
||||
var index = {};
|
||||
var slug;
|
||||
|
||||
content
|
||||
// remove PRE and TEMPLATE tag
|
||||
.replace(/<template[^>]*?>[\s\S]+?<\/template>/g, '')
|
||||
// find all html tag
|
||||
.replace(/<(\w+)([^>]*?)>([\s\S]+?)<\//g, function (match, tag, attr, html) {
|
||||
// remove all html tag
|
||||
var text = html.replace(/<[^>]+>/g, '');
|
||||
|
||||
// tag is headline
|
||||
if (/^h\d$/.test(tag)) {
|
||||
// <h1 id="xxx"></h1>
|
||||
var id = attr.match(/id="(\S+)"/)[1];
|
||||
|
||||
slug = ("#/" + path + "#" + id).replace(/\/+/, '/');
|
||||
INDEXS[slug] = { slug: slug, title: text, body: '' };
|
||||
} else {
|
||||
if (!slug) { return }
|
||||
// other html tag
|
||||
if (!INDEXS[slug]) {
|
||||
INDEXS[slug] = {};
|
||||
} else {
|
||||
if (INDEXS[slug].body && INDEXS[slug].body.length) {
|
||||
INDEXS[slug].body += '\n' + text;
|
||||
} else {
|
||||
INDEXS[slug].body = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* component
|
||||
*/
|
||||
var SearchComponent = function SearchComponent () {
|
||||
if (this.rendered) { return }
|
||||
|
||||
this.style();
|
||||
|
||||
var el = document.createElement('div');
|
||||
var aside = document.querySelector('aside');
|
||||
|
||||
el.classList.add('search');
|
||||
aside.insertBefore(el, aside.children[0]);
|
||||
this.render(el);
|
||||
this.rendered = true;
|
||||
this.bindEvent();
|
||||
};
|
||||
|
||||
SearchComponent.prototype.style = 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 }\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 ";
|
||||
var style = document.createElement('style');
|
||||
|
||||
style.innerHTML = code;
|
||||
document.head.appendChild(style);
|
||||
};
|
||||
|
||||
SearchComponent.prototype.render = function render (dom) {
|
||||
dom.innerHTML = "<input type=\"search\" placeholder=\"" + (CONFIG.placeholder) + "\" /><div class=\"results-panel\"></div>";
|
||||
};
|
||||
|
||||
SearchComponent.prototype.bindEvent = function bindEvent () {
|
||||
var this$1 = this;
|
||||
|
||||
var search = document.querySelector('.search');
|
||||
var input = search.querySelector('.search input');
|
||||
var panel = search.querySelector('.results-panel');
|
||||
|
||||
search.addEventListener('click', function (e) { return e.target.tagName !== 'A' && e.stopPropagation(); });
|
||||
input.addEventListener('input', function (e) {
|
||||
var target = e.target;
|
||||
|
||||
if (target.value.trim() !== '') {
|
||||
var matchingPosts = this$1.search(target.value);
|
||||
var html = '';
|
||||
|
||||
matchingPosts.forEach(function (post, index) {
|
||||
html += "\n <div class=\"matching-post\">\n <h2><a href=\"" + (post.url) + "\">" + (post.title) + "</a></h2>\n <p>" + (post.content) + "</p>\n </div>\n ";
|
||||
});
|
||||
if (panel.classList.contains('results-panel')) {
|
||||
panel.classList.add('show');
|
||||
panel.innerHTML = html || '<p class="empty">No Results!</p>';
|
||||
}
|
||||
tokens.forEach(function (token) {
|
||||
if (token.type === 'heading' && token.depth <= 2) {
|
||||
slug = toURL(path, { id: slugify(token.text) });
|
||||
index[slug] = { slug: slug, title: token.text, body: '' };
|
||||
} else {
|
||||
if (panel.classList.contains('results-panel')) {
|
||||
panel.classList.remove('show');
|
||||
panel.innerHTML = '';
|
||||
if (!slug) { return }
|
||||
if (!index[slug]) {
|
||||
index[slug] = { slug: slug, title: '', body: '' };
|
||||
} else {
|
||||
if (index[slug].body) {
|
||||
index[slug].body += '\n' + (token.text || '');
|
||||
} else {
|
||||
index[slug].body = token.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
slugify.clear();
|
||||
return index
|
||||
}
|
||||
|
||||
// From [weex website] https://weex-project.io/js/common.js
|
||||
SearchComponent.prototype.search = function search (keywords) {
|
||||
function search (keywords) {
|
||||
var matchingResults = [];
|
||||
var data = Object.keys(INDEXS).map(function (key) { return INDEXS[key]; });
|
||||
var data = [];
|
||||
Object.keys(INDEXS).forEach(function (key) {
|
||||
data = data.concat(Object.keys(INDEXS[key]).map(function (page) { return INDEXS[key][page]; }));
|
||||
});
|
||||
|
||||
keywords = keywords.trim().split(/[\s\-\,\\/]+/);
|
||||
|
||||
@@ -172,14 +89,14 @@ SearchComponent.prototype.search = function search (keywords) {
|
||||
var postContent = post.body && post.body.trim();
|
||||
var postUrl = post.slug || '';
|
||||
|
||||
if (postTitle !== '' && postContent !== '') {
|
||||
if (postTitle && postContent) {
|
||||
keywords.forEach(function (keyword, i) {
|
||||
var regEx = new RegExp(keyword, 'gi');
|
||||
var indexTitle = -1;
|
||||
var indexContent = -1;
|
||||
|
||||
indexTitle = postTitle.search(regEx);
|
||||
indexContent = postContent.search(regEx);
|
||||
indexTitle = postTitle && postTitle.search(regEx);
|
||||
indexContent = postContent && postContent.search(regEx);
|
||||
|
||||
if (indexTitle < 0 && indexContent < 0) {
|
||||
isMatch = false;
|
||||
@@ -196,7 +113,7 @@ SearchComponent.prototype.search = function search (keywords) {
|
||||
if (end > postContent.length) { end = postContent.length; }
|
||||
|
||||
var matchContent = '...' +
|
||||
postContent
|
||||
escapeHtml(postContent)
|
||||
.substring(start, end)
|
||||
.replace(regEx, ("<em class=\"search-keyword\">" + keyword + "</em>")) +
|
||||
'...';
|
||||
@@ -217,13 +134,15 @@ SearchComponent.prototype.search = function search (keywords) {
|
||||
}
|
||||
};
|
||||
|
||||
for (var i = 0; i < data.length; i++) loop( i );
|
||||
for (var i = 0; i < data.length; i++) loop( i );
|
||||
|
||||
return matchingResults
|
||||
};
|
||||
}
|
||||
|
||||
var searchPlugin = function () {
|
||||
var isAuto = CONFIG.paths === 'auto';
|
||||
function init$1 (config, vm) {
|
||||
helper = Docsify;
|
||||
|
||||
var isAuto = config.paths === 'auto';
|
||||
var isExpired = localStorage.getItem('docsify.search.expires') < Date.now();
|
||||
|
||||
INDEXS = JSON.parse(localStorage.getItem('docsify.search.index'));
|
||||
@@ -234,68 +153,138 @@ var searchPlugin = function () {
|
||||
return
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
var paths = isAuto ? getAllPaths() : CONFIG.paths;
|
||||
var paths = isAuto ? getAllPaths() : config.paths;
|
||||
var len = paths.length;
|
||||
var ref = window.Docsify.utils;
|
||||
var load = ref.load;
|
||||
var marked = ref.marked;
|
||||
var slugify = ref.slugify;
|
||||
var alias = window.$docsify.alias;
|
||||
var done = function () {
|
||||
localStorage.setItem('docsify.search.expires', Date.now() + CONFIG.maxAge);
|
||||
localStorage.setItem('docsify.search.index', JSON.stringify(INDEXS));
|
||||
};
|
||||
var count = 0;
|
||||
|
||||
paths.forEach(function (path) {
|
||||
if (INDEXS[path]) { return count++ }
|
||||
var route;
|
||||
|
||||
// replace route
|
||||
if (alias && alias[path]) {
|
||||
route = genFilePath(alias[path] || path, '');
|
||||
} else {
|
||||
route = genFilePath(path);
|
||||
helper
|
||||
.get(vm.$getFile(path))
|
||||
.then(function (result) {
|
||||
INDEXS[path] = genIndex(path, result);
|
||||
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}\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);
|
||||
}
|
||||
|
||||
function tpl (opts) {
|
||||
var html =
|
||||
"<input type=\"search\" />" +
|
||||
'<div class="results-panel"></div>' +
|
||||
'</div>';
|
||||
var el = dom.create('div', html);
|
||||
var aside = dom.find('aside');
|
||||
|
||||
dom.toggleClass(el, 'search');
|
||||
dom.before(aside, el);
|
||||
}
|
||||
|
||||
function bindEvents () {
|
||||
var $search = dom.find('div.search');
|
||||
var $input = dom.find($search, 'input');
|
||||
var $panel = dom.find($search, '.results-panel');
|
||||
var doSearch = function (value) {
|
||||
if (!value) {
|
||||
$panel.classList.remove('show');
|
||||
$panel.innerHTML = '';
|
||||
return
|
||||
}
|
||||
var matchs = search(value);
|
||||
|
||||
load(route).then(function (content) {
|
||||
genIndex(path, marked(content));
|
||||
slugify.clear();
|
||||
count++;
|
||||
|
||||
if (len === count) { done(); }
|
||||
var html = '';
|
||||
matchs.forEach(function (post) {
|
||||
html += "<div class=\"matching-post\">\n <h2><a href=\"" + (post.url) + "\">" + (post.title) + "</a></h2>\n <p>" + (post.content) + "</p>\n</div>";
|
||||
});
|
||||
|
||||
$panel.classList.add('show');
|
||||
$panel.innerHTML = html || ("<p class=\"empty\">" + NO_DATA_TEXT + "</p>");
|
||||
};
|
||||
|
||||
var timeId;
|
||||
// Prevent to Fold sidebar
|
||||
dom.on($search, 'click',
|
||||
function (e) { return e.target.tagName !== 'A' && e.stopPropagation(); });
|
||||
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"]');
|
||||
|
||||
if (typeof text === 'string') {
|
||||
$input.placeholder = text;
|
||||
} else {
|
||||
var match = Object.keys(text).find(function (key) { return path.indexOf(key) > -1; });
|
||||
$input.placeholder = text[match];
|
||||
}
|
||||
}
|
||||
|
||||
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; });
|
||||
NO_DATA_TEXT = text[match];
|
||||
}
|
||||
}
|
||||
|
||||
function init$$1 (opts) {
|
||||
dom = Docsify.dom;
|
||||
style();
|
||||
tpl(opts);
|
||||
bindEvents();
|
||||
}
|
||||
|
||||
function update (opts, vm) {
|
||||
updatePlaceholder(opts.placeholder, vm.route.path);
|
||||
updateNoData(opts.noData, vm.route.path);
|
||||
}
|
||||
|
||||
var CONFIG = {
|
||||
placeholder: 'Type to search',
|
||||
noData: 'No Results!',
|
||||
paths: 'auto',
|
||||
maxAge: 86400000 // 1 day
|
||||
};
|
||||
|
||||
var install = function (hook, vm) {
|
||||
var util = Docsify.util;
|
||||
var opts = vm.config.search || CONFIG;
|
||||
|
||||
if (Array.isArray(opts)) {
|
||||
CONFIG.paths = opts;
|
||||
} else if (typeof opts === 'object') {
|
||||
CONFIG.paths = Array.isArray(opts.paths) ? opts.paths : 'auto';
|
||||
CONFIG.maxAge = util.isPrimitive(opts.maxAge) ? opts.maxAge : CONFIG.maxAge;
|
||||
CONFIG.placeholder = opts.placeholder || CONFIG.placeholder;
|
||||
CONFIG.noData = opts.noData || CONFIG.noData;
|
||||
}
|
||||
|
||||
var isAuto = CONFIG.paths === 'auto';
|
||||
|
||||
hook.mounted(function (_) {
|
||||
init$$1(CONFIG);
|
||||
!isAuto && init$1(CONFIG, vm);
|
||||
});
|
||||
hook.doneEach(function (_) {
|
||||
update(CONFIG, vm);
|
||||
isAuto && init$1(CONFIG, vm);
|
||||
});
|
||||
};
|
||||
|
||||
var install = function () {
|
||||
if (install.installed) { return }
|
||||
install.installed = true;
|
||||
|
||||
var userConfig = window.$docsify.search;
|
||||
var isNil = window.Docsify.utils.isNil;
|
||||
|
||||
if (Array.isArray(userConfig)) {
|
||||
CONFIG.paths = userConfig;
|
||||
} else if (isObj(userConfig)) {
|
||||
CONFIG.paths = Array.isArray(userConfig.paths) ? userConfig.paths : 'auto';
|
||||
CONFIG.maxAge = isNil(userConfig.maxAge) ? CONFIG.maxAge : userConfig.maxAge;
|
||||
CONFIG.placeholder = userConfig.placeholder || CONFIG.placeholder;
|
||||
}
|
||||
|
||||
window.$docsify.plugins = [].concat(function (hook) {
|
||||
var isAuto = CONFIG.paths === 'auto';
|
||||
|
||||
hook.ready(function () {
|
||||
new SearchComponent();
|
||||
!isAuto && searchPlugin();
|
||||
});
|
||||
isAuto && hook.doneEach(searchPlugin);
|
||||
}, window.$docsify.plugins);
|
||||
};
|
||||
|
||||
var search = install();
|
||||
|
||||
return search;
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins);
|
||||
|
||||
}());
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,304 @@
|
||||
this.D = this.D || {};
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function createCommonjsModule(fn, module) {
|
||||
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
||||
}
|
||||
|
||||
var zoomImage = createCommonjsModule(function (module, exports) {
|
||||
(function (global, factory) {
|
||||
module.exports = factory();
|
||||
}(commonjsGlobal, (function () { 'use strict';
|
||||
|
||||
var windowWidth = function () { return document.documentElement.clientWidth; };
|
||||
var windowHeight = function () { return document.documentElement.clientHeight; };
|
||||
|
||||
var elemOffset = function (elem) {
|
||||
var rect = elem.getBoundingClientRect();
|
||||
var docElem = document.documentElement;
|
||||
var win = window;
|
||||
return {
|
||||
top: rect.top + win.pageYOffset - docElem.clientTop,
|
||||
left: rect.left + win.pageXOffset - docElem.clientLeft
|
||||
}
|
||||
};
|
||||
|
||||
var once = function (elem, type, handler) {
|
||||
var fn = function (e) {
|
||||
e.target.removeEventListener(type, fn);
|
||||
handler();
|
||||
};
|
||||
elem.addEventListener(type, fn);
|
||||
};
|
||||
|
||||
var Size = function Size(w, h) {
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
};
|
||||
|
||||
var ZoomImage = function ZoomImage(img, offset) {
|
||||
this.img = img;
|
||||
this.preservedTransform = img.style.transform;
|
||||
this.wrap = null;
|
||||
this.overlay = null;
|
||||
this.offset = offset;
|
||||
};
|
||||
|
||||
ZoomImage.prototype.forceRepaint = function forceRepaint () {
|
||||
var _ = this.img.offsetWidth;
|
||||
return
|
||||
};
|
||||
|
||||
ZoomImage.prototype.zoom = function zoom () {
|
||||
var size = new Size(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 scale = this.calculateScale(size);
|
||||
|
||||
this.forceRepaint();
|
||||
this.animate(scale);
|
||||
|
||||
document.body.classList.add('zoom-overlay-open');
|
||||
};
|
||||
|
||||
ZoomImage.prototype.calculateScale = function calculateScale (size) {
|
||||
var maxScaleFactor = size.w / this.img.width;
|
||||
|
||||
var viewportWidth = (windowWidth() - this.offset);
|
||||
var viewportHeight = (windowHeight() - this.offset);
|
||||
var imageAspectRatio = size.w / size.h;
|
||||
var viewportAspectRatio = viewportWidth / viewportHeight;
|
||||
|
||||
if (size.w < viewportWidth && size.h < viewportHeight) {
|
||||
return maxScaleFactor
|
||||
} else if (imageAspectRatio < viewportAspectRatio) {
|
||||
return (viewportHeight / size.h) * maxScaleFactor
|
||||
}
|
||||
return (viewportWidth / size.w) * maxScaleFactor
|
||||
};
|
||||
|
||||
ZoomImage.prototype.animate = function animate (scale) {
|
||||
var imageOffset = elemOffset(this.img);
|
||||
var scrollTop = window.pageYOffset;
|
||||
|
||||
var viewportX = (windowWidth() / 2);
|
||||
var viewportY = scrollTop + (windowHeight() / 2);
|
||||
|
||||
var imageCenterX = imageOffset.left + (this.img.width / 2);
|
||||
var imageCenterY = imageOffset.top + (this.img.height / 2);
|
||||
|
||||
var tx = viewportX - imageCenterX;
|
||||
var ty = viewportY - imageCenterY;
|
||||
var tz = 0;
|
||||
|
||||
var imgTr = "scale(" + scale + ")";
|
||||
var wrapTr = "translate3d(" + tx + "px, " + ty + "px, " + tz + "px)";
|
||||
|
||||
this.img.style.transform = imgTr;
|
||||
this.wrap.style.transform = wrapTr;
|
||||
};
|
||||
|
||||
ZoomImage.prototype.dispose = function dispose () {
|
||||
if (this.wrap === null || this.wrap.parentNode === null) {
|
||||
return
|
||||
}
|
||||
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');
|
||||
};
|
||||
|
||||
ZoomImage.prototype.close = function close () {
|
||||
var this$1 = this;
|
||||
|
||||
document.body.classList.add('zoom-overlay-transitioning');
|
||||
this.img.style.transform = this.preservedTransform;
|
||||
if (this.img.style.length === 0) {
|
||||
this.img.removeAttribute('style');
|
||||
}
|
||||
this.wrap.style.transform = 'none';
|
||||
|
||||
once(this.img, 'transitionend', function () {
|
||||
this$1.dispose();
|
||||
// remove class should happen after dispose. Otherwise,
|
||||
// a new click event could fire and create a duplicate ZoomImage for
|
||||
// the same <img> element.
|
||||
document.body.classList.remove('zoom-overlay-open');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Pure JavaScript implementation of zoom.js.
|
||||
*
|
||||
* Original preamble:
|
||||
* zoom.js - It's the best way to zoom an image
|
||||
* @version v0.0.2
|
||||
* @link https://github.com/fat/zoom.js
|
||||
* @license MIT
|
||||
*
|
||||
* Needs a related CSS file to work. See the README at
|
||||
* https://github.com/nishanths/zoom.js for more info.
|
||||
*
|
||||
* This is a fork of the original zoom.js implementation by @fat.
|
||||
* Copyrights for the original project are held by @fat. All other copyright
|
||||
* for changes in the fork are held by Nishanth Shanmugham.
|
||||
*
|
||||
* Copyright (c) 2013 @fat
|
||||
* The MIT License. Copyright © 2016 Nishanth Shanmugham.
|
||||
*/
|
||||
|
||||
var current = null;
|
||||
var offset = 80;
|
||||
var initialScrollPos = -1;
|
||||
var initialTouchPos = -1;
|
||||
|
||||
function handleScroll() {
|
||||
if (initialScrollPos === -1) {
|
||||
initialScrollPos = window.pageYOffset;
|
||||
}
|
||||
|
||||
var deltaY = Math.abs(initialScrollPos - window.pageYOffset);
|
||||
if (deltaY >= 40) {
|
||||
closeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeyup(e) {
|
||||
if (e.keyCode === 27) {
|
||||
closeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
function handleTouchStart(e) {
|
||||
var t = e.touches[0];
|
||||
if (t === null) {
|
||||
return
|
||||
}
|
||||
|
||||
initialTouchPos = t.pageY;
|
||||
e.target.addEventListener('touchmove', handleTouchMove);
|
||||
}
|
||||
|
||||
function handleTouchMove(e) {
|
||||
var t = e.touches[0];
|
||||
if (t === null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (Math.abs(t.pageY - initialTouchPos) > 10) {
|
||||
closeCurrent();
|
||||
e.target.removeEventListener('touchmove', handleTouchMove);
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
closeCurrent();
|
||||
}
|
||||
|
||||
function addCloseListeners() {
|
||||
document.addEventListener('scroll', handleScroll);
|
||||
document.addEventListener('keyup', handleKeyup);
|
||||
document.addEventListener('touchstart', handleTouchStart);
|
||||
document.addEventListener('click', handleClick, true);
|
||||
}
|
||||
|
||||
function removeCloseListeners() {
|
||||
document.removeEventListener('scroll', handleScroll);
|
||||
document.removeEventListener('keyup', handleKeyup);
|
||||
document.removeEventListener('touchstart', handleTouchStart);
|
||||
document.removeEventListener('click', handleClick, true);
|
||||
}
|
||||
|
||||
function closeCurrent(force) {
|
||||
if (current === null) {
|
||||
return
|
||||
}
|
||||
if (force) {
|
||||
current.dispose();
|
||||
} else {
|
||||
current.close();
|
||||
}
|
||||
removeCloseListeners();
|
||||
current = null;
|
||||
}
|
||||
|
||||
function prepareZoom(e) {
|
||||
if (document.body.classList.contains('zoom-overlay-open')) {
|
||||
return
|
||||
}
|
||||
|
||||
if (e.metaKey || e.ctrlKey) {
|
||||
window.open((e.target.getAttribute('data-original') || e.target.src), '_blank');
|
||||
return
|
||||
}
|
||||
|
||||
if (e.target.width >= windowWidth() - offset) {
|
||||
return
|
||||
}
|
||||
|
||||
closeCurrent(true);
|
||||
|
||||
current = new ZoomImage(e.target, offset);
|
||||
current.zoom();
|
||||
|
||||
addCloseListeners();
|
||||
}
|
||||
|
||||
var zoom = function (el) {
|
||||
el.setAttribute('data-action', 'zoom');
|
||||
el.addEventListener('click', prepareZoom);
|
||||
return function () { return el.removeEventListener('click', prepareZoom); }
|
||||
};
|
||||
|
||||
return zoom;
|
||||
|
||||
})));
|
||||
});
|
||||
|
||||
var style = "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";
|
||||
|
||||
function install (hook) {
|
||||
var dom = Docsify.dom;
|
||||
var destroys;
|
||||
|
||||
// add style
|
||||
dom.appendTo(dom.head, dom.create('style', style));
|
||||
|
||||
hook.doneEach(function (_) {
|
||||
var images = dom.findAll('img:not(.emoji)');
|
||||
|
||||
if (Array.isArray(destroys) && destroys.length) {
|
||||
destroys.forEach(function (o) { return o(); });
|
||||
destroys = [];
|
||||
}
|
||||
|
||||
destroys = images.map(zoomImage);
|
||||
});
|
||||
}
|
||||
|
||||
$docsify.plugins = [].concat(install, $docsify.plugins);
|
||||
|
||||
}());
|
||||
Vendored
+1
@@ -0,0 +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)}();
|
||||
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
+5
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docsify",
|
||||
"version": "2.4.1",
|
||||
"version": "3.4.1",
|
||||
"description": "A magical documentation generator.",
|
||||
"main": "lib/docsify.js",
|
||||
"files": [
|
||||
@@ -12,7 +12,7 @@
|
||||
"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 test"
|
||||
"test": "eslint src"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -40,11 +40,13 @@
|
||||
"rollup-plugin-buble": "^0.15.0",
|
||||
"rollup-plugin-commonjs": "^7.0.0",
|
||||
"rollup-plugin-node-resolve": "^2.0.0",
|
||||
"rollup-plugin-string": "^2.0.2",
|
||||
"rollup-plugin-uglify": "^1.0.1",
|
||||
"serve-static": "^1.11.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"marked": "^0.3.6",
|
||||
"prismjs": "^1.5.1"
|
||||
"prismjs": "^1.5.1",
|
||||
"zoom-image": "^0.1.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { merge, hyphenate, isPrimitive } from './util/core'
|
||||
|
||||
const config = merge({
|
||||
el: '#app',
|
||||
repo: '',
|
||||
maxLevel: 6,
|
||||
subMaxLevel: 0,
|
||||
loadSidebar: null,
|
||||
loadNavbar: null,
|
||||
homepage: 'README.md',
|
||||
coverpage: '',
|
||||
basePath: '',
|
||||
auto2top: false,
|
||||
name: '',
|
||||
themeColor: '',
|
||||
nameLink: window.location.pathname,
|
||||
autoHeader: false,
|
||||
executeScript: null,
|
||||
ga: ''
|
||||
}, window.$docsify)
|
||||
|
||||
const script = document.currentScript ||
|
||||
[].slice.call(document.getElementsByTagName('script'))
|
||||
.filter(n => /docsify\./.test(n.src))[0]
|
||||
|
||||
if (script) {
|
||||
for (const prop in config) {
|
||||
const val = script.getAttribute('data-' + hyphenate(prop))
|
||||
|
||||
if (isPrimitive(val)) {
|
||||
config[prop] = val === '' ? true : val
|
||||
}
|
||||
}
|
||||
|
||||
if (config.loadSidebar === true) config.loadSidebar = '_sidebar.md'
|
||||
if (config.loadNavbar === true) config.loadNavbar = '_navbar.md'
|
||||
if (config.coverpage === true) config.coverpage = '_coverpage.md'
|
||||
if (config.repo === true) config.repo = ''
|
||||
if (config.name === true) config.name = ''
|
||||
}
|
||||
|
||||
window.$docsify = config
|
||||
|
||||
export default config
|
||||
@@ -0,0 +1,22 @@
|
||||
import { isMobile } from '../util/env'
|
||||
import { body, on } from '../util/dom'
|
||||
import * as sidebar from './sidebar'
|
||||
import { scrollIntoView } from './scroll'
|
||||
|
||||
export function eventMixin (proto) {
|
||||
proto.$resetEvents = function () {
|
||||
scrollIntoView(this.route.query.id)
|
||||
sidebar.getAndActive('nav')
|
||||
}
|
||||
}
|
||||
|
||||
export function initEvent (vm) {
|
||||
// Bind toggle button
|
||||
sidebar.btn('button.sidebar-toggle')
|
||||
// Bind sticky effect
|
||||
if (vm.config.coverpage) {
|
||||
!isMobile && on('scroll', sidebar.sticky)
|
||||
} else {
|
||||
body.classList.add('sticky')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import { isMobile } from '../util/env'
|
||||
import * as dom from '../util/dom'
|
||||
import { parse } from '../route/hash'
|
||||
|
||||
const nav = {}
|
||||
let hoverOver = false
|
||||
|
||||
function highlight () {
|
||||
const sidebar = dom.getNode('.sidebar')
|
||||
const anchors = dom.findAll('.anchor')
|
||||
const wrap = dom.find(sidebar, '.sidebar-nav')
|
||||
let active = dom.find(sidebar, 'li.active')
|
||||
const top = dom.body.scrollTop
|
||||
let last
|
||||
|
||||
for (let i = 0, len = anchors.length; i < len; i += 1) {
|
||||
const node = anchors[i]
|
||||
|
||||
if (node.offsetTop > top) {
|
||||
if (!last) last = node
|
||||
break
|
||||
} else {
|
||||
last = node
|
||||
}
|
||||
}
|
||||
if (!last) return
|
||||
const li = nav[last.getAttribute('data-id')]
|
||||
|
||||
if (!li || li === active) return
|
||||
|
||||
active && active.classList.remove('active')
|
||||
li.classList.add('active')
|
||||
active = li
|
||||
|
||||
// scroll into view
|
||||
// https://github.com/vuejs/vuejs.org/blob/master/themes/vue/source/js/common.js#L282-L297
|
||||
if (!hoverOver && dom.body.classList.contains('sticky')) {
|
||||
const height = sidebar.clientHeight
|
||||
const curOffset = 0
|
||||
const cur = active.offsetTop + active.clientHeight + 40
|
||||
const isInView = (
|
||||
active.offsetTop >= wrap.scrollTop &&
|
||||
cur <= wrap.scrollTop + height
|
||||
)
|
||||
const notThan = cur - curOffset < height
|
||||
const top = isInView
|
||||
? wrap.scrollTop
|
||||
: notThan
|
||||
? curOffset
|
||||
: cur - height
|
||||
|
||||
sidebar.scrollTop = top
|
||||
}
|
||||
}
|
||||
|
||||
export function scrollActiveSidebar () {
|
||||
if (isMobile) return
|
||||
|
||||
const sidebar = dom.getNode('.sidebar')
|
||||
const lis = dom.findAll(sidebar, 'li')
|
||||
|
||||
for (let i = 0, len = lis.length; i < len; i += 1) {
|
||||
const li = lis[i]
|
||||
const a = li.querySelector('a')
|
||||
if (!a) continue
|
||||
let href = a.getAttribute('href')
|
||||
|
||||
if (href !== '/') {
|
||||
href = parse(href).query.id
|
||||
}
|
||||
|
||||
nav[decodeURIComponent(href)] = li
|
||||
}
|
||||
|
||||
dom.off('scroll', highlight)
|
||||
dom.on('scroll', highlight)
|
||||
dom.on(sidebar, 'mouseover', () => { hoverOver = true })
|
||||
dom.on(sidebar, 'mouseleave', () => { hoverOver = false })
|
||||
}
|
||||
|
||||
export function scrollIntoView (id) {
|
||||
const section = dom.find('#' + id)
|
||||
section && section.scrollIntoView()
|
||||
}
|
||||
|
||||
const scrollEl = dom.$.scrollingElement || dom.$.documentElement
|
||||
|
||||
export function scroll2Top (offset = 0) {
|
||||
scrollEl.scrollTop = offset === true ? 0 : Number(offset)
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
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) {
|
||||
const toggle = () => dom.body.classList.toggle('close')
|
||||
|
||||
el = dom.getNode(el)
|
||||
dom.on(el, 'click', toggle)
|
||||
|
||||
const sidebar = dom.getNode('.sidebar')
|
||||
|
||||
dom.on(sidebar, 'click', () => {
|
||||
isMobile && toggle()
|
||||
setTimeout(() => getAndActive(sidebar, true, true), 0)
|
||||
})
|
||||
}
|
||||
|
||||
export function sticky () {
|
||||
const cover = dom.getNode('section.cover')
|
||||
if (!cover) return
|
||||
const coverHeight = cover.getBoundingClientRect().height
|
||||
|
||||
if (window.pageYOffset >= coverHeight || cover.classList.contains('hidden')) {
|
||||
dom.toggleClass(dom.body, 'add', 'sticky')
|
||||
} else {
|
||||
dom.toggleClass(dom.body, 'remove', 'sticky')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get and active link
|
||||
* @param {string|element} el
|
||||
* @param {Boolean} isParent acitve parent
|
||||
* @param {Boolean} autoTitle auto set title
|
||||
* @return {element}
|
||||
*/
|
||||
export function getAndActive (el, isParent, autoTitle) {
|
||||
el = dom.getNode(el)
|
||||
|
||||
const links = dom.findAll(el, 'a')
|
||||
const hash = '#' + getHash()
|
||||
let target
|
||||
|
||||
links
|
||||
.sort((a, b) => b.href.length - a.href.length)
|
||||
.forEach(a => {
|
||||
const href = a.getAttribute('href')
|
||||
const node = isParent ? a.parentNode : a
|
||||
|
||||
if (hash.indexOf(href) === 0 && !target) {
|
||||
target = a
|
||||
dom.toggleClass(node, 'add', 'active')
|
||||
} else {
|
||||
dom.toggleClass(node, 'remove', 'active')
|
||||
}
|
||||
})
|
||||
|
||||
if (autoTitle) {
|
||||
dom.$.title = target ? `${target.innerText} - ${title}` : title
|
||||
}
|
||||
|
||||
return target
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import progressbar from '../render/progressbar'
|
||||
import { noop } from '../util/core'
|
||||
|
||||
const cache = {}
|
||||
|
||||
/**
|
||||
* Simple ajax get
|
||||
* @param {string} url
|
||||
* @param {boolean} [hasBar=false] has progress bar
|
||||
* @return { then(resolve, reject), abort }
|
||||
*/
|
||||
export function get (url, hasBar = false) {
|
||||
const xhr = new XMLHttpRequest()
|
||||
const on = function () {
|
||||
xhr.addEventListener.apply(xhr, arguments)
|
||||
}
|
||||
|
||||
if (cache[url]) {
|
||||
return { then: cb => cb(cache[url]), abort: noop }
|
||||
}
|
||||
|
||||
xhr.open('GET', url)
|
||||
xhr.send()
|
||||
|
||||
return {
|
||||
then: function (success, error = noop) {
|
||||
if (hasBar) {
|
||||
const id = setInterval(_ => progressbar({
|
||||
step: Math.floor(Math.random() * 5 + 1)
|
||||
}), 500)
|
||||
|
||||
on('progress', progressbar)
|
||||
on('loadend', evt => {
|
||||
progressbar(evt)
|
||||
clearInterval(id)
|
||||
})
|
||||
}
|
||||
|
||||
on('error', error)
|
||||
on('load', ({ target }) => {
|
||||
if (target.status >= 400) {
|
||||
error(target)
|
||||
} else {
|
||||
cache[url] = target.response
|
||||
success(target.response)
|
||||
}
|
||||
})
|
||||
},
|
||||
abort: _ => xhr.readyState !== 4 && xhr.abort()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { get } from './ajax'
|
||||
import { callHook } from '../init/lifecycle'
|
||||
import { getParentPath } from '../route/util'
|
||||
import { noop } from '../util/core'
|
||||
|
||||
function loadNested (path, file, next, vm, first) {
|
||||
path = first ? path : path.replace(/\/$/, '')
|
||||
path = getParentPath(path)
|
||||
|
||||
if (!path) return
|
||||
|
||||
get(vm.$getFile(path + file))
|
||||
.then(next, _ => loadNested(path, file, next, vm))
|
||||
}
|
||||
|
||||
export function fetchMixin (proto) {
|
||||
let last
|
||||
proto._fetch = function (cb = noop) {
|
||||
const { path } = this.route
|
||||
const { loadNavbar, loadSidebar } = this.config
|
||||
|
||||
// Abort last request
|
||||
last && last.abort && last.abort()
|
||||
|
||||
last = get(this.$getFile(path), true)
|
||||
|
||||
// Current page is html
|
||||
this.isHTML = /\.html$/g.test(path)
|
||||
|
||||
// Load main content
|
||||
last.then(text => {
|
||||
this._renderMain(text)
|
||||
if (!loadSidebar) return cb()
|
||||
|
||||
const fn = result => { this._renderSidebar(result); cb() }
|
||||
|
||||
// Load sidebar
|
||||
loadNested(path, loadSidebar, fn, this, true)
|
||||
},
|
||||
_ => this._renderMain(null))
|
||||
|
||||
// Load nav
|
||||
loadNavbar &&
|
||||
loadNested(path, loadNavbar, text => this._renderNav(text), this, true)
|
||||
}
|
||||
|
||||
proto._fetchCover = function () {
|
||||
const { coverpage } = this.config
|
||||
const root = getParentPath(this.route.path)
|
||||
const path = this.$getFile(root + coverpage)
|
||||
|
||||
if (this.route.path !== '/' || !coverpage) {
|
||||
this._renderCover()
|
||||
return
|
||||
}
|
||||
|
||||
this.coverIsHTML = /\.html$/g.test(path)
|
||||
get(path)
|
||||
.then(text => this._renderCover(text))
|
||||
}
|
||||
|
||||
proto.$fetch = function (cb = noop) {
|
||||
this._fetchCover()
|
||||
this._fetch(result => {
|
||||
this.$resetEvents()
|
||||
callHook(this, 'doneEach')
|
||||
cb()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function initFetch (vm) {
|
||||
vm.$fetch(_ => callHook(vm, 'ready'))
|
||||
}
|
||||
@@ -0,0 +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 { 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.marked = marked
|
||||
window.Prism = prism
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { initMixin } from './init'
|
||||
import { routeMixin } from './route'
|
||||
import { renderMixin } from './render'
|
||||
import { fetchMixin } from './fetch'
|
||||
import { eventMixin } from './event'
|
||||
import initGlobalAPI from './global-api'
|
||||
|
||||
function Docsify () {
|
||||
this._init()
|
||||
}
|
||||
|
||||
const proto = Docsify.prototype
|
||||
|
||||
initMixin(proto)
|
||||
routeMixin(proto)
|
||||
renderMixin(proto)
|
||||
fetchMixin(proto)
|
||||
eventMixin(proto)
|
||||
|
||||
/**
|
||||
* Global API
|
||||
*/
|
||||
initGlobalAPI()
|
||||
|
||||
/**
|
||||
* Run Docsify
|
||||
*/
|
||||
setTimeout(_ => new Docsify(), 0)
|
||||
@@ -0,0 +1,27 @@
|
||||
import config from '../config'
|
||||
import { initLifecycle, callHook } from './lifecycle'
|
||||
import { initRender } from '../render'
|
||||
import { initRoute } from '../route'
|
||||
import { initEvent } from '../event'
|
||||
import { initFetch } from '../fetch'
|
||||
import { isFn } from '../util/core'
|
||||
|
||||
export function initMixin (proto) {
|
||||
proto._init = function () {
|
||||
const vm = this
|
||||
vm.config = config || {}
|
||||
|
||||
initLifecycle(vm) // Init hooks
|
||||
initPlugin(vm) // Install plugins
|
||||
callHook(vm, 'init')
|
||||
initRender(vm) // Render base DOM
|
||||
initEvent(vm) // Bind events
|
||||
initRoute(vm) // Add hashchange eventListener
|
||||
initFetch(vm) // Fetch data
|
||||
callHook(vm, 'mounted')
|
||||
}
|
||||
}
|
||||
|
||||
function initPlugin (vm) {
|
||||
[].concat(vm.config.plugins).forEach(fn => isFn(fn) && fn(vm._lifecycle, vm))
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { noop } from '../util/core'
|
||||
|
||||
export function initLifecycle (vm) {
|
||||
const hooks = [
|
||||
'init',
|
||||
'mounted',
|
||||
'beforeEach',
|
||||
'afterEach',
|
||||
'doneEach',
|
||||
'ready'
|
||||
]
|
||||
|
||||
vm._hooks = {}
|
||||
vm._lifecycle = {}
|
||||
hooks.forEach(hook => {
|
||||
const arr = vm._hooks[hook] = []
|
||||
vm._lifecycle[hook] = fn => arr.push(fn)
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
} else {
|
||||
if (typeof hook === 'function') {
|
||||
if (hook.length === 2) {
|
||||
hook(data, result => {
|
||||
newData = result
|
||||
step(index + 1)
|
||||
})
|
||||
} else {
|
||||
const result = hook(data)
|
||||
newData = result !== undefined ? result : newData
|
||||
step(index + 1)
|
||||
}
|
||||
} else {
|
||||
step(index + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
step(0)
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
import marked from 'marked'
|
||||
import Prism from 'prismjs'
|
||||
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 { isFn, merge, cached } from '../util/core'
|
||||
|
||||
let markdownCompiler = marked
|
||||
let contentBase = ''
|
||||
let currentPath = ''
|
||||
let renderer = new marked.Renderer()
|
||||
const cacheTree = {}
|
||||
let toc = []
|
||||
|
||||
/**
|
||||
* Compile markdown content
|
||||
*/
|
||||
export const markdown = cached(text => {
|
||||
let html = ''
|
||||
|
||||
if (!text) return text
|
||||
|
||||
html = markdownCompiler(text)
|
||||
html = emojify(html)
|
||||
slugify.clear()
|
||||
|
||||
return html
|
||||
})
|
||||
|
||||
markdown.renderer = renderer
|
||||
|
||||
markdown.init = function (config = {}, base = window.location.pathname) {
|
||||
contentBase = getBasePath(base)
|
||||
|
||||
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 slug = slugify(text)
|
||||
const url = toURL(currentPath, { id: slug })
|
||||
|
||||
toc.push({ level, slug: url, 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)
|
||||
|
||||
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)
|
||||
} 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 (!isAbsolutePath(href)) {
|
||||
url = getPath(contentBase, href)
|
||||
}
|
||||
|
||||
return `<img src="${url}" data-origin="${href}" alt="${text}"${titleHTML}>`
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile sidebar
|
||||
*/
|
||||
export function sidebar (text, level) {
|
||||
let html = ''
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile sub sidebar
|
||||
*/
|
||||
export function subSidebar (el, level) {
|
||||
if (el) {
|
||||
toc[0] && toc[0].level === 1 && toc.shift()
|
||||
const tree = cacheTree[currentPath] || genTree(toc, level)
|
||||
el.parentNode.innerHTML += treeTpl(tree, '<ul class="app-sub-sidebar">')
|
||||
cacheTree[currentPath] = tree
|
||||
}
|
||||
toc = []
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile cover page
|
||||
*/
|
||||
export function cover (text) {
|
||||
const cacheToc = toc.slice()
|
||||
const html = markdown(text)
|
||||
|
||||
toc = cacheToc.slice()
|
||||
|
||||
return html
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
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 text
|
||||
.replace(/<(pre|template|code)[^>]*?>[\s\S]+?<\/(pre|template|code)>/g, m => m.replace(/:/g, '__colon__'))
|
||||
.replace(/:(\w+?):/ig, window.emojify || replace)
|
||||
.replace(/__colon__/g, ':')
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* gen toc tree
|
||||
* @link https://github.com/killercup/grock/blob/5280ae63e16c5739e9233d9009bc235ed7d79a50/styles/solarized/assets/js/behavior.coffee#L54-L81
|
||||
* @param {Array} toc
|
||||
* @param {Number} maxLevel
|
||||
* @return {Array}
|
||||
*/
|
||||
export function genTree (toc, maxLevel) {
|
||||
const headlines = []
|
||||
const last = {}
|
||||
|
||||
toc.forEach(headline => {
|
||||
const level = headline.level || 1
|
||||
const len = level - 1
|
||||
|
||||
if (level > maxLevel) return
|
||||
if (last[len]) {
|
||||
last[len].children = (last[len].children || []).concat(headline)
|
||||
} else {
|
||||
headlines.push(headline)
|
||||
}
|
||||
last[level] = headline
|
||||
})
|
||||
|
||||
return headlines
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
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 { callHook } from '../init/lifecycle'
|
||||
import { getBasePath, getPath, isAbsolutePath } from '../route/util'
|
||||
import { isPrimitive } from '../util/core'
|
||||
|
||||
function executeScript () {
|
||||
const script = dom.findAll('.markdown-section>script')
|
||||
.filter(s => !/template/.test(s.type))[0]
|
||||
if (!script) return false
|
||||
const code = script.innerText.trim()
|
||||
if (!code) return false
|
||||
|
||||
setTimeout(_ => {
|
||||
window.__EXECUTE_RESULT__ = new Function(code)()
|
||||
}, 0)
|
||||
}
|
||||
|
||||
function renderMain (html) {
|
||||
if (!html) {
|
||||
// TODO: Custom 404 page
|
||||
html = 'not found'
|
||||
}
|
||||
|
||||
this._renderTo('.markdown-section', html)
|
||||
// Render sidebar with the TOC
|
||||
!this.config.loadSidebar && this._renderSidebar()
|
||||
|
||||
// execute script
|
||||
if (this.config.executeScript !== false &&
|
||||
typeof window.Vue !== 'undefined' &&
|
||||
!executeScript()) {
|
||||
setTimeout(_ => {
|
||||
const vueVM = window.__EXECUTE_RESULT__
|
||||
vueVM && vueVM.$destroy && vueVM.$destroy()
|
||||
window.__EXECUTE_RESULT__ = new window.Vue().$mount('#main')
|
||||
}, 0)
|
||||
} else {
|
||||
this.config.executeScript && executeScript()
|
||||
}
|
||||
|
||||
if (this.config.auto2top) {
|
||||
scroll2Top(this.config.auto2top)
|
||||
}
|
||||
}
|
||||
|
||||
function renderNameLink (vm) {
|
||||
const el = dom.getNode('.app-name-link')
|
||||
const nameLink = vm.config.nameLink
|
||||
const path = vm.route.path
|
||||
|
||||
if (!el) return
|
||||
|
||||
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)
|
||||
|
||||
el.setAttribute('href', nameLink[match])
|
||||
}
|
||||
}
|
||||
|
||||
export function renderMixin (proto) {
|
||||
proto._renderTo = function (el, content, replace) {
|
||||
const node = dom.getNode(el)
|
||||
if (node) node[replace ? 'outerHTML' : 'innerHTML'] = content
|
||||
}
|
||||
|
||||
proto._renderSidebar = function (text) {
|
||||
const { maxLevel, subMaxLevel, autoHeader, loadSidebar } = this.config
|
||||
|
||||
this._renderTo('.sidebar-nav', sidebar(text, maxLevel))
|
||||
const active = getAndActive('.sidebar-nav', true, true)
|
||||
subSidebar(loadSidebar ? active : '', subMaxLevel)
|
||||
// bind event
|
||||
this.activeLink = active
|
||||
scrollActiveSidebar()
|
||||
|
||||
if (autoHeader && active) {
|
||||
const main = dom.getNode('#main')
|
||||
const firstNode = main.children[0]
|
||||
if (firstNode && firstNode.tagName !== 'H1') {
|
||||
const h1 = dom.create('h1')
|
||||
h1.innerText = active.innerText
|
||||
dom.before(main, h1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proto._renderNav = function (text) {
|
||||
text && this._renderTo('nav', markdown(text))
|
||||
getAndActive('nav')
|
||||
}
|
||||
|
||||
proto._renderMain = function (text) {
|
||||
callHook(this, 'beforeEach', text, result => {
|
||||
const html = this.isHTML ? result : markdown(result)
|
||||
callHook(this, 'afterEach', html, text => renderMain.call(this, text))
|
||||
})
|
||||
}
|
||||
|
||||
proto._renderCover = function (text) {
|
||||
const el = dom.getNode('.cover')
|
||||
if (!text) {
|
||||
dom.toggleClass(el, 'remove', 'show')
|
||||
return
|
||||
}
|
||||
dom.toggleClass(el, 'add', 'show')
|
||||
|
||||
let html = this.coverIsHTML ? text : cover(text)
|
||||
const m = html.trim().match('<p><img.*?data-origin="(.*?)"[^a]+alt="(.*?)">([^<]*?)</p>$')
|
||||
|
||||
if (m) {
|
||||
if (m[2] === 'color') {
|
||||
el.style.background = m[1] + (m[3] || '')
|
||||
} else {
|
||||
let path = m[1]
|
||||
|
||||
dom.toggleClass(el, 'add', 'has-mask')
|
||||
if (!isAbsolutePath(m[1])) {
|
||||
path = getPath(getBasePath(this.config.basePath), m[1])
|
||||
}
|
||||
el.style.backgroundImage = `url(${path})`
|
||||
el.style.backgroundSize = 'cover'
|
||||
el.style.backgroundPosition = 'center center'
|
||||
}
|
||||
html = html.replace(m[0], '')
|
||||
}
|
||||
|
||||
this._renderTo('.cover-main', html)
|
||||
sticky()
|
||||
}
|
||||
|
||||
proto._updateRender = function () {
|
||||
markdown.update()
|
||||
// render name link
|
||||
renderNameLink(this)
|
||||
}
|
||||
}
|
||||
|
||||
export function initRender (vm) {
|
||||
const config = vm.config
|
||||
|
||||
// Init markdown compiler
|
||||
markdown.init(config.markdown, config.basePath)
|
||||
|
||||
const id = config.el || '#app'
|
||||
const navEl = dom.find('nav') || dom.create('nav')
|
||||
|
||||
let el = dom.find(id)
|
||||
let html = ''
|
||||
|
||||
navEl.classList.add('app-nav')
|
||||
|
||||
if (!config.repo) {
|
||||
navEl.classList.add('no-badge')
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
||||
html += tpl.main(config)
|
||||
// Render main app
|
||||
vm._renderTo(el, html, true)
|
||||
// Add nav
|
||||
dom.before(dom.body, navEl)
|
||||
|
||||
if (config.themeColor) {
|
||||
dom.$.head.innerHTML += tpl.theme(config.themeColor)
|
||||
// Polyfll
|
||||
cssVars(config.themeColor)
|
||||
}
|
||||
dom.toggleClass(dom.body, 'ready')
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import * as dom from '../util/dom'
|
||||
|
||||
let barEl
|
||||
let timeId
|
||||
|
||||
/**
|
||||
* Init progress component
|
||||
*/
|
||||
function init () {
|
||||
const div = dom.create('div')
|
||||
|
||||
div.classList.add('progress')
|
||||
dom.appendTo(dom.body, div)
|
||||
barEl = div
|
||||
}
|
||||
/**
|
||||
* Render progress bar
|
||||
*/
|
||||
export default function ({ loaded, total, step }) {
|
||||
let num
|
||||
|
||||
!barEl && init()
|
||||
|
||||
if (step) {
|
||||
num = parseInt(barEl.style.width || 0, 10) + step
|
||||
num = num > 80 ? 80 : num
|
||||
} else {
|
||||
num = Math.floor(loaded / total * 100)
|
||||
}
|
||||
|
||||
barEl.style.opacity = 1
|
||||
barEl.style.width = num >= 95 ? '100%' : num + '%'
|
||||
|
||||
if (num >= 95) {
|
||||
clearTimeout(timeId)
|
||||
timeId = setTimeout(_ => {
|
||||
barEl.style.opacity = 0
|
||||
barEl.style.width = '0%'
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
let cache = {}
|
||||
const re = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,.\/:;<=>?@\[\]^`{|}~]/g
|
||||
|
||||
export function slugify (str) {
|
||||
if (typeof str !== 'string') return ''
|
||||
|
||||
let slug = str.toLowerCase().trim()
|
||||
.replace(/<[^>\d]+>/g, '')
|
||||
.replace(re, '')
|
||||
.replace(/\s/g, '-')
|
||||
.replace(/-+/g, '-')
|
||||
.replace(/^(\d)/, '_$1')
|
||||
let count = cache[slug]
|
||||
|
||||
count = cache.hasOwnProperty(slug) ? (count + 1) : 0
|
||||
cache[slug] = count
|
||||
|
||||
if (count) {
|
||||
slug = slug + '-' + count
|
||||
}
|
||||
|
||||
return slug
|
||||
}
|
||||
|
||||
slugify.clear = function () {
|
||||
cache = {}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import { isMobile } from '../util/env'
|
||||
/**
|
||||
* Render github corner
|
||||
* @param {Object} data
|
||||
* @return {String}
|
||||
*/
|
||||
export function corner (data) {
|
||||
if (!data) return ''
|
||||
if (!/\/\//.test(data)) data = 'https://github.com/' + data
|
||||
data = data.replace(/^git\+/, '')
|
||||
|
||||
return (
|
||||
`<a href="${data}" class="github-corner" aria-label="View source on Github">` +
|
||||
'<svg viewBox="0 0 250 250" aria-hidden="true">' +
|
||||
'<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>' +
|
||||
'<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>' +
|
||||
'<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path>' +
|
||||
'</svg>' +
|
||||
'</a>')
|
||||
}
|
||||
|
||||
/**
|
||||
* Render main content
|
||||
*/
|
||||
export function main (config) {
|
||||
const aside = (
|
||||
'<button class="sidebar-toggle">' +
|
||||
'<div class="sidebar-toggle-button">' +
|
||||
'<span></span><span></span><span></span>' +
|
||||
'</div>' +
|
||||
'</button>' +
|
||||
'<aside class="sidebar">' +
|
||||
(config.name
|
||||
? `<h1><a class="app-name-link" data-nosearch>${config.name}</a></h1>`
|
||||
: '') +
|
||||
'<div class="sidebar-nav"></div>' +
|
||||
'</aside>')
|
||||
|
||||
return (isMobile ? `${aside}<main>` : `<main>${aside}`) +
|
||||
'<section class="content">' +
|
||||
'<article class="markdown-section" id="main"></article>' +
|
||||
'</section>' +
|
||||
'</main>'
|
||||
}
|
||||
|
||||
/**
|
||||
* Cover Page
|
||||
*/
|
||||
export function cover () {
|
||||
const SL = ', 100%, 85%'
|
||||
const bgc = 'linear-gradient(to left bottom, ' +
|
||||
`hsl(${Math.floor(Math.random() * 255) + SL}) 0%,` +
|
||||
`hsl(${Math.floor(Math.random() * 255) + SL}) 100%)`
|
||||
|
||||
return `<section class="cover" style="background: ${bgc}">` +
|
||||
'<div class="cover-main"></div>' +
|
||||
'<div class="mask"></div>' +
|
||||
'</section>'
|
||||
}
|
||||
|
||||
/**
|
||||
* Render tree
|
||||
* @param {Array} tree
|
||||
* @param {String} tpl
|
||||
* @return {String}
|
||||
*/
|
||||
export function tree (toc, tpl = '') {
|
||||
if (!toc || !toc.length) return ''
|
||||
|
||||
toc.forEach(node => {
|
||||
tpl += `<li><a class="section-link" href="${node.slug}">${node.title}</a></li>`
|
||||
if (node.children) {
|
||||
tpl += `<li><ul class="children">${tree(node.children)}</li></ul>`
|
||||
}
|
||||
})
|
||||
|
||||
return tpl
|
||||
}
|
||||
|
||||
export function helper (className, content) {
|
||||
return `<p class="${className}">${content.slice(5).trim()}</p>`
|
||||
}
|
||||
|
||||
export function theme (color) {
|
||||
return `<style>:root{--theme-color: ${color};}</style>`
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
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
|
||||
*/
|
||||
export function toURL (path, params) {
|
||||
const route = parse(replaceSlug(path))
|
||||
|
||||
route.query = merge({}, route.query, params)
|
||||
path = route.path + stringifyQuery(route.query)
|
||||
|
||||
return cleanPath('#/' + path)
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
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,58 @@
|
||||
import { cached } from '../util/core'
|
||||
|
||||
const decode = decodeURIComponent
|
||||
const encode = encodeURIComponent
|
||||
|
||||
export function parseQuery (query) {
|
||||
const res = {}
|
||||
|
||||
query = query.trim().replace(/^(\?|#|&)/, '')
|
||||
|
||||
if (!query) {
|
||||
return res
|
||||
}
|
||||
|
||||
// Simple parse
|
||||
query.split('&').forEach(function (param) {
|
||||
const parts = param.replace(/\+/g, ' ').split('=')
|
||||
|
||||
res[parts[0]] = decode(parts[1])
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
export function stringifyQuery (obj) {
|
||||
const qs = []
|
||||
|
||||
for (const key in obj) {
|
||||
qs.push(`${encode(key)}=${encode(obj[key])}`.toLowerCase())
|
||||
}
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
export const getParentPath = cached(path => {
|
||||
return /\/$/g.test(path)
|
||||
? path
|
||||
: (path = path.match(/(\S*\/)[^\/]+$/))
|
||||
? path[1]
|
||||
: ''
|
||||
})
|
||||
|
||||
export const cleanPath = cached(path => {
|
||||
return path.replace(/\/+/g, '/')
|
||||
})
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Create a cached version of a pure function.
|
||||
*/
|
||||
export function cached (fn) {
|
||||
const cache = Object.create(null)
|
||||
return function cachedFn (str) {
|
||||
const hit = cache[str]
|
||||
return hit || (cache[str] = fn(str))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hyphenate a camelCase string.
|
||||
*/
|
||||
export const hyphenate = cached(str => {
|
||||
return str.replace(/([A-Z])/g, m => '-' + m.toLowerCase())
|
||||
})
|
||||
|
||||
/**
|
||||
* Simple Object.assign polyfill
|
||||
*/
|
||||
export const merge = Object.assign || function (to) {
|
||||
const hasOwn = Object.prototype.hasOwnProperty
|
||||
|
||||
for (let i = 1; i < arguments.length; i++) {
|
||||
const from = Object(arguments[i])
|
||||
|
||||
for (const key in from) {
|
||||
if (hasOwn.call(from, key)) {
|
||||
to[key] = from[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return to
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if value is primitive
|
||||
*/
|
||||
export function isPrimitive (value) {
|
||||
return typeof value === 'string' || typeof value === 'number'
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform no operation.
|
||||
*/
|
||||
export function noop () {}
|
||||
|
||||
/**
|
||||
* Check if value is function
|
||||
*/
|
||||
export function isFn (obj) {
|
||||
return typeof obj === 'function'
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import { isFn } from '../util/core'
|
||||
|
||||
const cacheNode = {}
|
||||
|
||||
/**
|
||||
* Get Node
|
||||
* @param {String|Element} el
|
||||
* @param {Boolean} noCache
|
||||
* @return {Element}
|
||||
*/
|
||||
export function getNode (el, noCache = false) {
|
||||
if (typeof el === 'string') {
|
||||
if (typeof window.Vue !== 'undefined') {
|
||||
return find(el)
|
||||
}
|
||||
el = noCache ? find(el) : (cacheNode[el] || (cacheNode[el] = find(el)))
|
||||
}
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
export const $ = document
|
||||
|
||||
export const body = $.body
|
||||
|
||||
export const head = $.head
|
||||
|
||||
/**
|
||||
* Find element
|
||||
* @example
|
||||
* find('nav') => document.querySelector('nav')
|
||||
* find(nav, 'a') => nav.querySelector('a')
|
||||
*/
|
||||
export function find (el, node) {
|
||||
return node ? el.querySelector(node) : $.querySelector(el)
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all elements
|
||||
* @example
|
||||
* findAll('a') => [].slice.call(document.querySelectorAll('a'))
|
||||
* findAll(nav, 'a') => [].slice.call(nav.querySelectorAll('a'))
|
||||
*/
|
||||
export function findAll (el, node) {
|
||||
return [].slice.call(node ? el.querySelectorAll(node) : $.querySelectorAll(el))
|
||||
}
|
||||
|
||||
export function create (node, tpl) {
|
||||
node = $.createElement(node)
|
||||
if (tpl) node.innerHTML = tpl
|
||||
return node
|
||||
}
|
||||
|
||||
export function appendTo (target, el) {
|
||||
return target.appendChild(el)
|
||||
}
|
||||
|
||||
export function before (target, el) {
|
||||
return target.insertBefore(el, target.children[0])
|
||||
}
|
||||
|
||||
export function on (el, type, handler) {
|
||||
isFn(type)
|
||||
? window.addEventListener(el, type)
|
||||
: el.addEventListener(type, handler)
|
||||
}
|
||||
|
||||
export function off (el, type, handler) {
|
||||
isFn(type)
|
||||
? window.removeEventListener(el, type)
|
||||
: el.removeEventListener(type, handler)
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle class
|
||||
*
|
||||
* @example
|
||||
* toggleClass(el, 'active') => el.classList.toggle('active')
|
||||
* toggleClass(el, 'add', 'active') => el.classList.add('active')
|
||||
*/
|
||||
export function toggleClass (el, type, val) {
|
||||
el && el.classList[val ? type : 'toggle'](val || type)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export const UA = window.navigator.userAgent.toLowerCase()
|
||||
|
||||
export const isIE = UA && /msie|trident/.test(UA)
|
||||
|
||||
export const isMobile = document.body.clientWidth <= 600
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './core'
|
||||
export * from './env'
|
||||
@@ -0,0 +1,33 @@
|
||||
import * as dom from '../dom'
|
||||
import { get } from '../../fetch/ajax'
|
||||
|
||||
function replaceVar (block, color) {
|
||||
block.innerHTML = block.innerHTML
|
||||
.replace(/var\(\s*--theme-color.*?\)/g, color)
|
||||
}
|
||||
|
||||
export default function (color) {
|
||||
// Variable support
|
||||
if (window.CSS &&
|
||||
window.CSS.supports &&
|
||||
window.CSS.supports('(--v:red)')) return
|
||||
|
||||
const styleBlocks = dom.findAll('style:not(.inserted),link')
|
||||
|
||||
;[].forEach.call(styleBlocks, block => {
|
||||
if (block.nodeName === 'STYLE') {
|
||||
replaceVar(block, color)
|
||||
} else if (block.nodeName === 'LINK') {
|
||||
const href = block.getAttribute('href')
|
||||
|
||||
if (!/\.css$/.test(href)) return
|
||||
|
||||
get(href).then(res => {
|
||||
const style = dom.create('style', res)
|
||||
|
||||
dom.head.appendChild(style)
|
||||
replaceVar(style, color)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
-159
@@ -1,159 +0,0 @@
|
||||
import { isMobile } from './util'
|
||||
|
||||
/**
|
||||
* Active sidebar when scroll
|
||||
* @link https://buble.surge.sh/
|
||||
*/
|
||||
export function scrollActiveSidebar () {
|
||||
if (isMobile()) return
|
||||
|
||||
let hoveredOverSidebar = false
|
||||
const anchors = document.querySelectorAll('.anchor')
|
||||
const sidebar = document.querySelector('.sidebar')
|
||||
const sidebarContainer = sidebar.querySelector('.sidebar-nav')
|
||||
const sidebarHeight = sidebar.clientHeight
|
||||
|
||||
const nav = {}
|
||||
const lis = sidebar.querySelectorAll('li')
|
||||
let active = sidebar.querySelector('li.active')
|
||||
|
||||
for (let i = 0, len = lis.length; i < len; i += 1) {
|
||||
const li = lis[i]
|
||||
const a = li.querySelector('a')
|
||||
if (!a) continue
|
||||
let href = a.getAttribute('href')
|
||||
|
||||
if (href !== '/') {
|
||||
const match = href.match('#([^#]+)$')
|
||||
if (match && match.length) href = match[0].slice(1)
|
||||
}
|
||||
|
||||
nav[decodeURIComponent(href)] = li
|
||||
}
|
||||
|
||||
function highlight () {
|
||||
const top = document.body.scrollTop
|
||||
let last
|
||||
|
||||
for (let i = 0, len = anchors.length; i < len; i += 1) {
|
||||
const node = anchors[i]
|
||||
|
||||
if (node.offsetTop > top) {
|
||||
if (!last) last = node
|
||||
break
|
||||
} else {
|
||||
last = node
|
||||
}
|
||||
}
|
||||
if (!last) return
|
||||
const li = nav[last.getAttribute('data-id')]
|
||||
|
||||
if (!li || li === active) return
|
||||
if (active) active.classList.remove('active')
|
||||
|
||||
li.classList.add('active')
|
||||
active = li
|
||||
|
||||
// scroll into view
|
||||
// https://github.com/vuejs/vuejs.org/blob/master/themes/vue/source/js/common.js#L282-L297
|
||||
if (!hoveredOverSidebar && !sticky.noSticky) {
|
||||
const currentPageOffset = 0
|
||||
const currentActiveOffset = active.offsetTop + active.clientHeight + 40
|
||||
const currentActiveIsInView = (
|
||||
active.offsetTop >= sidebarContainer.scrollTop &&
|
||||
currentActiveOffset <= sidebarContainer.scrollTop + sidebarHeight
|
||||
)
|
||||
const linkNotFurtherThanSidebarHeight = currentActiveOffset - currentPageOffset < sidebarHeight
|
||||
const newScrollTop = currentActiveIsInView
|
||||
? sidebarContainer.scrollTop
|
||||
: linkNotFurtherThanSidebarHeight
|
||||
? currentPageOffset
|
||||
: currentActiveOffset - sidebarHeight
|
||||
|
||||
sidebar.scrollTop = newScrollTop
|
||||
}
|
||||
}
|
||||
|
||||
window.removeEventListener('scroll', highlight)
|
||||
window.addEventListener('scroll', highlight)
|
||||
sidebar.addEventListener('mouseover', () => { hoveredOverSidebar = true })
|
||||
sidebar.addEventListener('mouseleave', () => { hoveredOverSidebar = false })
|
||||
}
|
||||
|
||||
export function scrollIntoView () {
|
||||
const id = window.location.hash.match(/#[^#\/]+$/g)
|
||||
if (!id || !id.length) return
|
||||
const section = document.querySelector(decodeURIComponent(id[0]))
|
||||
|
||||
if (section) setTimeout(() => section.scrollIntoView(), 0)
|
||||
|
||||
return section
|
||||
}
|
||||
|
||||
/**
|
||||
* Acitve link
|
||||
*/
|
||||
export function activeLink (dom, activeParent) {
|
||||
const host = window.location.href
|
||||
|
||||
dom = typeof dom === 'object' ? dom : document.querySelector(dom)
|
||||
if (!dom) return
|
||||
let target
|
||||
|
||||
;[].slice.call(dom.querySelectorAll('a'))
|
||||
.sort((a, b) => b.href.length - a.href.length)
|
||||
.forEach(node => {
|
||||
if (host.indexOf(node.href) === 0 && !target) {
|
||||
activeParent
|
||||
? node.parentNode.classList.add('active')
|
||||
: node.classList.add('active')
|
||||
target = node
|
||||
} else {
|
||||
activeParent
|
||||
? node.parentNode.classList.remove('active')
|
||||
: node.classList.remove('active')
|
||||
}
|
||||
})
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
/**
|
||||
* sidebar toggle
|
||||
*/
|
||||
export function bindToggle (dom) {
|
||||
dom = typeof dom === 'object' ? dom : document.querySelector(dom)
|
||||
if (!dom) return
|
||||
const body = document.body
|
||||
|
||||
dom.addEventListener('click', () => body.classList.toggle('close'))
|
||||
|
||||
if (isMobile()) {
|
||||
const sidebar = document.querySelector('.sidebar')
|
||||
sidebar.addEventListener('click', () => {
|
||||
body.classList.toggle('close')
|
||||
setTimeout(() => activeLink(sidebar, true), 0)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const scrollingElement = document.scrollingElement || document.documentElement
|
||||
|
||||
export function scroll2Top (offset = 0) {
|
||||
scrollingElement.scrollTop = offset === true ? 0 : Number(offset)
|
||||
}
|
||||
|
||||
export function sticky () {
|
||||
sticky.dom = sticky.dom || document.querySelector('section.cover')
|
||||
const coverHeight = sticky.dom.getBoundingClientRect().height
|
||||
|
||||
return (function () {
|
||||
if (window.pageYOffset >= coverHeight || sticky.dom.classList.contains('hidden')) {
|
||||
document.body.classList.add('sticky')
|
||||
sticky.noSticky = false
|
||||
} else {
|
||||
document.body.classList.remove('sticky')
|
||||
sticky.noSticky = true
|
||||
}
|
||||
})()
|
||||
}
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
export default class Hook {
|
||||
constructor () {
|
||||
this.beforeHooks = []
|
||||
this.afterHooks = []
|
||||
this.initHooks = []
|
||||
this.readyHooks = []
|
||||
this.doneEachHooks = []
|
||||
}
|
||||
|
||||
beforeEach (fn) {
|
||||
this.beforeHooks.push(fn)
|
||||
}
|
||||
|
||||
afterEach (fn) {
|
||||
this.afterHooks.push(fn)
|
||||
}
|
||||
|
||||
doneEach (fn) {
|
||||
this.doneEachHooks.push(fn)
|
||||
}
|
||||
|
||||
init (fn) {
|
||||
this.initHooks.push(fn)
|
||||
}
|
||||
|
||||
ready (fn) {
|
||||
this.readyHooks.push(fn)
|
||||
}
|
||||
|
||||
emit (name, data, next) {
|
||||
let newData = data
|
||||
const queue = this[name + 'Hooks']
|
||||
const step = function (index) {
|
||||
const hook = queue[index]
|
||||
if (index >= queue.length) {
|
||||
next && next(newData)
|
||||
} else {
|
||||
if (typeof hook === 'function') {
|
||||
if (hook.length === 2) {
|
||||
hook(data, result => {
|
||||
newData = result
|
||||
step(index + 1)
|
||||
})
|
||||
} else {
|
||||
const result = hook(data)
|
||||
newData = result !== undefined ? result : newData
|
||||
step(index + 1)
|
||||
}
|
||||
} else {
|
||||
step(index + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
step(0)
|
||||
}
|
||||
}
|
||||
-146
@@ -1,146 +0,0 @@
|
||||
import * as utils from './util'
|
||||
import { scrollIntoView, activeLink } from './event'
|
||||
import * as render from './render'
|
||||
import Hook from './hook'
|
||||
|
||||
const OPTIONS = utils.merge({
|
||||
el: '#app',
|
||||
repo: '',
|
||||
maxLevel: 6,
|
||||
subMaxLevel: 0,
|
||||
loadSidebar: null,
|
||||
loadNavbar: null,
|
||||
homepage: 'README.md',
|
||||
coverpage: '',
|
||||
basePath: '',
|
||||
auto2top: false,
|
||||
name: '',
|
||||
themeColor: '',
|
||||
nameLink: window.location.pathname,
|
||||
ga: ''
|
||||
}, window.$docsify)
|
||||
const script = document.currentScript || [].slice.call(document.getElementsByTagName('script')).pop()
|
||||
|
||||
// load configuration for script attribute
|
||||
if (script) {
|
||||
for (const prop in OPTIONS) {
|
||||
const val = script.getAttribute('data-' + utils.camel2kebab(prop))
|
||||
OPTIONS[prop] = utils.isNil(val) ? OPTIONS[prop] : (val || true)
|
||||
}
|
||||
if (OPTIONS.loadSidebar === true) OPTIONS.loadSidebar = '_sidebar.md'
|
||||
if (OPTIONS.loadNavbar === true) OPTIONS.loadNavbar = '_navbar.md'
|
||||
if (OPTIONS.coverpage === true) OPTIONS.coverpage = '_coverpage.md'
|
||||
if (OPTIONS.repo === true) OPTIONS.repo = ''
|
||||
if (OPTIONS.name === true) OPTIONS.name = ''
|
||||
}
|
||||
|
||||
const hook = new Hook()
|
||||
|
||||
// utils
|
||||
window.$docsify = OPTIONS
|
||||
window.Docsify = {
|
||||
installed: true,
|
||||
utils: utils.merge({}, utils),
|
||||
hook
|
||||
}
|
||||
|
||||
// load options
|
||||
render.init()
|
||||
|
||||
let cacheRoute = null
|
||||
let cacheXhr = null
|
||||
|
||||
const getAlias = function (route) {
|
||||
if (OPTIONS.alias[route]) {
|
||||
return getAlias(OPTIONS.alias[route])
|
||||
} else {
|
||||
return route
|
||||
}
|
||||
}
|
||||
|
||||
const mainRender = function (cb) {
|
||||
let page
|
||||
let route = utils.getRoute()
|
||||
if (cacheRoute === route) return cb()
|
||||
|
||||
let basePath = cacheRoute = OPTIONS.basePath + route
|
||||
|
||||
if (!/\//.test(basePath)) {
|
||||
basePath = ''
|
||||
} else if (basePath && !/\/$/.test(basePath)) {
|
||||
basePath = basePath.match(/(\S*\/)[^\/]+$/)[1]
|
||||
}
|
||||
|
||||
// replace route
|
||||
route = '/' + route
|
||||
if (OPTIONS.alias && OPTIONS.alias[route]) {
|
||||
route = getAlias(route)
|
||||
} else {
|
||||
route = (OPTIONS.basePath + route).replace(/\/+/, '/')
|
||||
}
|
||||
|
||||
if (!route) {
|
||||
page = OPTIONS.homepage || 'README.md'
|
||||
} else if (/\.md$/.test(route)) {
|
||||
page = route
|
||||
} else if (/\/$/.test(route)) {
|
||||
page = `${route}README.md`
|
||||
} else {
|
||||
page = `${route}.md`
|
||||
}
|
||||
|
||||
// Render Cover page
|
||||
if (OPTIONS.coverpage && page === ('/' + OPTIONS.homepage).replace(/\/+/, '/')) {
|
||||
utils.load(OPTIONS.coverpage).then(render.renderCover)
|
||||
}
|
||||
|
||||
cacheXhr && cacheXhr.abort && cacheXhr.abort()
|
||||
// Render markdown file
|
||||
cacheXhr = utils.load(page, 'GET', render.renderLoading)
|
||||
cacheXhr.then(result => {
|
||||
render.renderArticle(result)
|
||||
// clear cover
|
||||
if (OPTIONS.coverpage && page !== OPTIONS.homepage) render.renderCover()
|
||||
// render sidebar
|
||||
if (OPTIONS.loadSidebar) {
|
||||
const renderSidebar = result => { render.renderSidebar(result); cb() }
|
||||
|
||||
utils.load(basePath + OPTIONS.loadSidebar).then(renderSidebar,
|
||||
_ => utils.load(OPTIONS.loadSidebar).then(renderSidebar))
|
||||
} else {
|
||||
cb()
|
||||
}
|
||||
}, _ => render.renderArticle(null))
|
||||
|
||||
// Render navbar
|
||||
if (OPTIONS.loadNavbar) {
|
||||
utils.load(basePath + OPTIONS.loadNavbar).then(render.renderNavbar,
|
||||
_ => utils.load(OPTIONS.loadNavbar).then(render.renderNavbar))
|
||||
}
|
||||
}
|
||||
|
||||
const Docsify = function () {
|
||||
setTimeout(_ => {
|
||||
;[].concat(OPTIONS.plugins).forEach(fn => typeof fn === 'function' && fn(hook))
|
||||
window.Docsify.hook.emit('init')
|
||||
|
||||
const dom = document.querySelector(OPTIONS.el) || document.body
|
||||
const replace = dom !== document.body
|
||||
const main = function () {
|
||||
mainRender(_ => {
|
||||
scrollIntoView()
|
||||
activeLink('nav')
|
||||
window.Docsify.hook.emit('doneEach')
|
||||
})
|
||||
}
|
||||
|
||||
// Render app
|
||||
render.renderApp(dom, replace)
|
||||
main()
|
||||
if (!/^#\//.test(window.location.hash)) window.location.hash = '#/'
|
||||
window.addEventListener('hashchange', main)
|
||||
window.Docsify.hook.emit('ready')
|
||||
}, 0)
|
||||
}
|
||||
|
||||
export default Docsify()
|
||||
@@ -0,0 +1,153 @@
|
||||
const AllGithubEmoji = ['+1', '100', '1234', '8ball', 'a', 'ab', 'abc', 'abcd',
|
||||
'accept', 'aerial_tramway', 'airplane', 'alarm_clock', 'alien', 'ambulance',
|
||||
'anchor', 'angel', 'anger', 'angry', 'anguished', 'ant', 'apple', 'aquarius',
|
||||
'aries', 'arrow_backward', 'arrow_double_down', 'arrow_double_up', 'arrow_down',
|
||||
'arrow_down_small', 'arrow_forward', 'arrow_heading_down', 'arrow_heading_up',
|
||||
'arrow_left', 'arrow_lower_left', 'arrow_lower_right', 'arrow_right',
|
||||
'arrow_right_hook', 'arrow_up', 'arrow_up_down', 'arrow_up_small', 'arrow_upper_left',
|
||||
'arrow_upper_right', 'arrows_clockwise', 'arrows_counterclockwise', 'art',
|
||||
'articulated_lorry', 'astonished', 'athletic_shoe', 'atm', 'b', 'baby', 'baby_bottle',
|
||||
'baby_chick', 'baby_symbol', 'back', 'baggage_claim', 'balloon', 'ballot_box_with_check',
|
||||
'bamboo', 'banana', 'bangbang', 'bank', 'bar_chart', 'barber', 'baseball', 'basketball',
|
||||
'bath', 'bathtub', 'battery', 'bear', 'bee', 'beer', 'beers', 'beetle', 'beginner',
|
||||
'bell', 'bento', 'bicyclist', 'bike', 'bikini', 'bird', 'birthday', 'black_circle',
|
||||
'black_joker', 'black_large_square', 'black_medium_small_square', 'black_medium_square',
|
||||
'black_nib', 'black_small_square', 'black_square_button', 'blossom', 'blowfish',
|
||||
'blue_book', 'blue_car', 'blue_heart', 'blush', 'boar', 'boat', 'bomb', 'book',
|
||||
'bookmark', 'bookmark_tabs', 'books', 'boom', 'boot', 'bouquet', 'bow', 'bowling',
|
||||
'bowtie', 'boy', 'bread', 'bride_with_veil', 'bridge_at_night', 'briefcase',
|
||||
'broken_heart', 'bug', 'bulb', 'bullettrain_front', 'bullettrain_side', 'bus',
|
||||
'busstop', 'bust_in_silhouette', 'busts_in_silhouette', 'cactus', 'cake', 'calendar',
|
||||
'calling', 'camel', 'camera', 'cancer', 'candy', 'capital_abcd', 'capricorn', 'car',
|
||||
'card_index', 'carousel_horse', 'cat', 'cat2', 'cd', 'chart', 'chart_with_downwards_trend',
|
||||
'chart_with_upwards_trend', 'checkered_flag', 'cherries', 'cherry_blossom', 'chestnut',
|
||||
'chicken', 'children_crossing', 'chocolate_bar', 'christmas_tree', 'church', 'cinema',
|
||||
'circus_tent', 'city_sunrise', 'city_sunset', 'cl', 'clap', 'clapper', 'clipboard',
|
||||
'clock1', 'clock10', 'clock1030', 'clock11', 'clock1130', 'clock12', 'clock1230',
|
||||
'clock130', 'clock2', 'clock230', 'clock3', 'clock330', 'clock4', 'clock430',
|
||||
'clock5', 'clock530', 'clock6', 'clock630', 'clock7', 'clock730', 'clock8', 'clock830',
|
||||
'clock9', 'clock930', 'closed_book', 'closed_lock_with_key', 'closed_umbrella',
|
||||
'cloud', 'clubs', 'cn', 'cocktail', 'coffee', 'cold_sweat', 'collision', 'computer',
|
||||
'confetti_ball', 'confounded', 'confused', 'congratulations', 'construction',
|
||||
'construction_worker', 'convenience_store', 'cookie', 'cool', 'cop', 'copyright',
|
||||
'corn', 'couple', 'couple_with_heart', 'couplekiss', 'cow', 'cow2', 'credit_card',
|
||||
'crescent_moon', 'crocodile', 'crossed_flags', 'crown', 'cry', 'crying_cat_face',
|
||||
'crystal_ball', 'cupid', 'curly_loop', 'currency_exchange', 'curry', 'custard',
|
||||
'customs', 'cyclone', 'dancer', 'dancers', 'dango', 'dart', 'dash', 'date', 'de',
|
||||
'deciduous_tree', 'department_store', 'diamond_shape_with_a_dot_inside', 'diamonds',
|
||||
'disappointed', 'disappointed_relieved', 'dizzy', 'dizzy_face', 'do_not_litter',
|
||||
'dog', 'dog2', 'dollar', 'dolls', 'dolphin', 'door', 'doughnut', 'dragon',
|
||||
'dragon_face', 'dress', 'dromedary_camel', 'droplet', 'dvd', 'e-mail', 'ear',
|
||||
'ear_of_rice', 'earth_africa', 'earth_americas', 'earth_asia', 'egg', 'eggplant',
|
||||
'eight', 'eight_pointed_black_star', 'eight_spoked_asterisk', 'electric_plug',
|
||||
'elephant', 'email', 'end', 'envelope', 'envelope_with_arrow', 'es', 'euro',
|
||||
'european_castle', 'european_post_office', 'evergreen_tree', 'exclamation',
|
||||
'expressionless', 'eyeglasses', 'eyes', 'facepunch', 'factory', 'fallen_leaf',
|
||||
'family', 'fast_forward', 'fax', 'fearful', 'feelsgood', 'feet', 'ferris_wheel',
|
||||
'file_folder', 'finnadie', 'fire', 'fire_engine', 'fireworks', 'first_quarter_moon',
|
||||
'first_quarter_moon_with_face', 'fish', 'fish_cake', 'fishing_pole_and_fish',
|
||||
'fist', 'five', 'flags', 'flashlight', 'flipper', 'floppy_disk', 'flower_playing_cards',
|
||||
'flushed', 'foggy', 'football', 'footprints', 'fork_and_knife', 'fountain',
|
||||
'four', 'four_leaf_clover', 'fr', 'free', 'fried_shrimp', 'fries', 'frog',
|
||||
'frowning', 'fu', 'fuelpump', 'full_moon', 'full_moon_with_face', 'game_die',
|
||||
'gb', 'gem', 'gemini', 'ghost', 'gift', 'gift_heart', 'girl', 'globe_with_meridians',
|
||||
'goat', 'goberserk', 'godmode', 'golf', 'grapes', 'green_apple', 'green_book',
|
||||
'green_heart', 'grey_exclamation', 'grey_question', 'grimacing', 'grin',
|
||||
'grinning', 'guardsman', 'guitar', 'gun', 'haircut', 'hamburger', 'hammer',
|
||||
'hamster', 'hand', 'handbag', 'hankey', 'hash', 'hatched_chick', 'hatching_chick',
|
||||
'headphones', 'hear_no_evil', 'heart', 'heart_decoration', 'heart_eyes',
|
||||
'heart_eyes_cat', 'heartbeat', 'heartpulse', 'hearts', 'heavy_check_mark',
|
||||
'heavy_division_sign', 'heavy_dollar_sign', 'heavy_exclamation_mark', 'heavy_minus_sign',
|
||||
'heavy_multiplication_x', 'heavy_plus_sign', 'helicopter', 'herb', 'hibiscus',
|
||||
'high_brightness', 'high_heel', 'hocho', 'honey_pot', 'honeybee', 'horse',
|
||||
'horse_racing', 'hospital', 'hotel', 'hotsprings', 'hourglass', 'hourglass_flowing_sand',
|
||||
'house', 'house_with_garden', 'hurtrealbad', 'hushed', 'ice_cream', 'icecream',
|
||||
'id', 'ideograph_advantage', 'imp', 'inbox_tray', 'incoming_envelope',
|
||||
'information_desk_person', 'information_source', 'innocent', 'interrobang',
|
||||
'iphone', 'it', 'izakaya_lantern', 'jack_o_lantern', 'japan', 'japanese_castle',
|
||||
'japanese_goblin', 'japanese_ogre', 'jeans', 'joy', 'joy_cat', 'jp', 'key',
|
||||
'keycap_ten', 'kimono', 'kiss', 'kissing', 'kissing_cat', 'kissing_closed_eyes',
|
||||
'kissing_heart', 'kissing_smiling_eyes', 'koala', 'koko', 'kr', 'lantern',
|
||||
'large_blue_circle', 'large_blue_diamond', 'large_orange_diamond', 'last_quarter_moon',
|
||||
'last_quarter_moon_with_face', 'laughing', 'leaves', 'ledger', 'left_luggage',
|
||||
'left_right_arrow', 'leftwards_arrow_with_hook', 'lemon', 'leo', 'leopard',
|
||||
'libra', 'light_rail', 'link', 'lips', 'lipstick', 'lock', 'lock_with_ink_pen',
|
||||
'lollipop', 'loop', 'loud_sound', 'loudspeaker', 'love_hotel', 'love_letter',
|
||||
'low_brightness', 'm', 'mag', 'mag_right', 'mahjong', 'mailbox', 'mailbox_closed',
|
||||
'mailbox_with_mail', 'mailbox_with_no_mail', 'man', 'man_with_gua_pi_mao',
|
||||
'man_with_turban', 'mans_shoe', 'maple_leaf', 'mask', 'massage', 'meat_on_bone',
|
||||
'mega', 'melon', 'memo', 'mens', 'metal', 'metro', 'microphone', 'microscope',
|
||||
'milky_way', 'minibus', 'minidisc', 'mobile_phone_off', 'money_with_wings',
|
||||
'moneybag', 'monkey', 'monkey_face', 'monorail', 'moon', 'mortar_board', 'mount_fuji',
|
||||
'mountain_bicyclist', 'mountain_cableway', 'mountain_railway', 'mouse', 'mouse2',
|
||||
'movie_camera', 'moyai', 'muscle', 'mushroom', 'musical_keyboard', 'musical_note',
|
||||
'musical_score', 'mute', 'nail_care', 'name_badge', 'neckbeard', 'necktie',
|
||||
'negative_squared_cross_mark', 'neutral_face', 'new', 'new_moon', 'new_moon_with_face',
|
||||
'newspaper', 'ng', 'night_with_stars', 'nine', 'no_bell', 'no_bicycles', 'no_entry',
|
||||
'no_entry_sign', 'no_good', 'no_mobile_phones', 'no_mouth', 'no_pedestrians',
|
||||
'no_smoking', 'non-potable_water', 'nose', 'notebook', 'notebook_with_decorative_cover',
|
||||
'notes', 'nut_and_bolt', 'o', 'o2', 'ocean', 'octocat', 'octopus', 'oden', 'office',
|
||||
'ok', 'ok_hand', 'ok_woman', 'older_man', 'older_woman', 'on', 'oncoming_automobile',
|
||||
'oncoming_bus', 'oncoming_police_car', 'oncoming_taxi', 'one', 'open_book',
|
||||
'open_file_folder', 'open_hands', 'open_mouth', 'ophiuchus', 'orange_book',
|
||||
'outbox_tray', 'ox', 'package', 'page_facing_up', 'page_with_curl', 'pager',
|
||||
'palm_tree', 'panda_face', 'paperclip', 'parking', 'part_alternation_mark',
|
||||
'partly_sunny', 'passport_control', 'paw_prints', 'peach', 'pear', 'pencil',
|
||||
'pencil2', 'penguin', 'pensive', 'performing_arts', 'persevere', 'person_frowning',
|
||||
'person_with_blond_hair', 'person_with_pouting_face', 'phone', 'pig', 'pig2',
|
||||
'pig_nose', 'pill', 'pineapple', 'pisces', 'pizza', 'point_down', 'point_left',
|
||||
'point_right', 'point_up', 'point_up_2', 'police_car', 'poodle', 'poop',
|
||||
'post_office', 'postal_horn', 'postbox', 'potable_water', 'pouch', 'poultry_leg',
|
||||
'pound', 'pouting_cat', 'pray', 'princess', 'punch', 'purple_heart', 'purse',
|
||||
'pushpin', 'put_litter_in_its_place', 'question', 'rabbit', 'rabbit2', 'racehorse',
|
||||
'radio', 'radio_button', 'rage', 'rage1', 'rage2', 'rage3', 'rage4', 'railway_car',
|
||||
'rainbow', 'raised_hand', 'raised_hands', 'raising_hand', 'ram', 'ramen', 'rat',
|
||||
'recycle', 'red_car', 'red_circle', 'registered', 'relaxed', 'relieved', 'repeat',
|
||||
'repeat_one', 'restroom', 'revolving_hearts', 'rewind', 'ribbon', 'rice',
|
||||
'rice_ball', 'rice_cracker', 'rice_scene', 'ring', 'rocket', 'roller_coaster',
|
||||
'rooster', 'rose', 'rotating_light', 'round_pushpin', 'rowboat', 'ru', 'rugby_football',
|
||||
'runner', 'running', 'running_shirt_with_sash', 'sa', 'sagittarius', 'sailboat',
|
||||
'sake', 'sandal', 'santa', 'satellite', 'satisfied', 'saxophone', 'school',
|
||||
'school_satchel', 'scissors', 'scorpius', 'scream', 'scream_cat', 'scroll',
|
||||
'seat', 'secret', 'see_no_evil', 'seedling', 'seven', 'shaved_ice', 'sheep',
|
||||
'shell', 'ship', 'shipit', 'shirt', 'shit', 'shoe', 'shower', 'signal_strength',
|
||||
'six', 'six_pointed_star', 'ski', 'skull', 'sleeping', 'sleepy', 'slot_machine',
|
||||
'small_blue_diamond', 'small_orange_diamond', 'small_red_triangle',
|
||||
'small_red_triangle_down', 'smile', 'smile_cat', 'smiley', 'smiley_cat',
|
||||
'smiling_imp', 'smirk', 'smirk_cat', 'smoking', 'snail', 'snake', 'snowboarder',
|
||||
'snowflake', 'snowman', 'sob', 'soccer', 'soon', 'sos', 'sound', 'space_invader',
|
||||
'spades', 'spaghetti', 'sparkle', 'sparkler', 'sparkles', 'sparkling_heart',
|
||||
'speak_no_evil', 'speaker', 'speech_balloon', 'speedboat', 'squirrel', 'star',
|
||||
'star2', 'stars', 'station', 'statue_of_liberty', 'steam_locomotive', 'stew',
|
||||
'straight_ruler', 'strawberry', 'stuck_out_tongue', 'stuck_out_tongue_closed_eyes',
|
||||
'stuck_out_tongue_winking_eye', 'sun_with_face', 'sunflower', 'sunglasses',
|
||||
'sunny', 'sunrise', 'sunrise_over_mountains', 'surfer', 'sushi', 'suspect',
|
||||
'suspension_railway', 'sweat', 'sweat_drops', 'sweat_smile', 'sweet_potato',
|
||||
'swimmer', 'symbols', 'syringe', 'tada', 'tanabata_tree', 'tangerine', 'taurus',
|
||||
'taxi', 'tea', 'telephone', 'telephone_receiver', 'telescope', 'tennis', 'tent',
|
||||
'thought_balloon', 'three', 'thumbsdown', 'thumbsup', 'ticket', 'tiger', 'tiger2',
|
||||
'tired_face', 'tm', 'toilet', 'tokyo_tower', 'tomato', 'tongue', 'top', 'tophat',
|
||||
'tractor', 'traffic_light', 'train', 'train2', 'tram', 'triangular_flag_on_post',
|
||||
'triangular_ruler', 'trident', 'triumph', 'trolleybus', 'trollface', 'trophy',
|
||||
'tropical_drink', 'tropical_fish', 'truck', 'trumpet', 'tshirt', 'tulip',
|
||||
'turtle', 'tv', 'twisted_rightwards_arrows', 'two', 'two_hearts', 'two_men_holding_hands',
|
||||
'two_women_holding_hands', 'u5272', 'u5408', 'u55b6', 'u6307', 'u6708', 'u6709',
|
||||
'u6e80', 'u7121', 'u7533', 'u7981', 'u7a7a', 'uk', 'umbrella', 'unamused',
|
||||
'underage', 'unlock', 'up', 'us', 'v', 'vertical_traffic_light', 'vhs',
|
||||
'vibration_mode', 'video_camera', 'video_game', 'violin', 'virgo', 'volcano',
|
||||
'vs', 'walking', 'waning_crescent_moon', 'waning_gibbous_moon', 'warning',
|
||||
'watch', 'water_buffalo', 'watermelon', 'wave', 'wavy_dash', 'waxing_crescent_moon',
|
||||
'waxing_gibbous_moon', 'wc', 'weary', 'wedding', 'whale', 'whale2', 'wheelchair',
|
||||
'white_check_mark', 'white_circle', 'white_flower', 'white_large_square',
|
||||
'white_medium_small_square', 'white_medium_square', 'white_small_square',
|
||||
'white_square_button', 'wind_chime', 'wine_glass', 'wink', 'wolf', 'woman',
|
||||
'womans_clothes', 'womans_hat', 'womens', 'worried', 'wrench', 'x', 'yellow_heart',
|
||||
'yen', 'yum', 'zap', 'zero', 'zzz']
|
||||
|
||||
// emoji from All-Github-Emoji-Icons
|
||||
// https://github.com/scotch-io/All-Github-Emoji-Icons
|
||||
window.emojify = function (match, $1) {
|
||||
return AllGithubEmoji.indexOf($1) === -1
|
||||
? match
|
||||
: '<img class="emoji" src="https://assets-cdn.github.com/images/icons/emoji/' + $1 + '.png" alt="' + $1 + '" />'
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
function handleExternalScript () {
|
||||
const container = Docsify.dom.getNode('#main')
|
||||
const script = Docsify.dom.find(container, 'script')
|
||||
|
||||
if (script && script.src) {
|
||||
const newScript = document.createElement('script')
|
||||
|
||||
;['src', 'async', 'defer'].forEach(attribute => {
|
||||
newScript[attribute] = script[attribute]
|
||||
})
|
||||
|
||||
script.parentNode.removeChild(script)
|
||||
container.appendChild(newScript)
|
||||
}
|
||||
}
|
||||
|
||||
const install = function (hook) {
|
||||
hook.doneEach(handleExternalScript)
|
||||
}
|
||||
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins)
|
||||
@@ -0,0 +1,13 @@
|
||||
import parser from './parser'
|
||||
|
||||
const install = function (hook, vm) {
|
||||
hook.beforeEach(content => {
|
||||
const { attributes, body } = parser(content)
|
||||
|
||||
Docsify.util.merge(vm.config, attributes.config)
|
||||
|
||||
return body
|
||||
})
|
||||
}
|
||||
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins)
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Fork https://github.com/egoist/docute/blob/master/src/utils/front-matter.js
|
||||
*/
|
||||
/* eslint-disable */
|
||||
import parser from './yaml'
|
||||
|
||||
var optionalByteOrderMark = '\\ufeff?'
|
||||
var pattern = '^(' +
|
||||
optionalByteOrderMark +
|
||||
'(= yaml =|---)' +
|
||||
'$([\\s\\S]*?)' +
|
||||
'(?:\\2|\\.\\.\\.)' +
|
||||
'$' +
|
||||
'' +
|
||||
'(?:\\n)?)'
|
||||
// NOTE: If this pattern uses the 'g' flag the `regex` variable definition will
|
||||
// need to be moved down into the functions that use it.
|
||||
var regex = new RegExp(pattern, 'm')
|
||||
|
||||
function extractor (string) {
|
||||
string = string || ''
|
||||
|
||||
var lines = string.split(/(\r?\n)/)
|
||||
if (lines[0] && /= yaml =|---/.test(lines[0])) {
|
||||
return parse(string)
|
||||
} else {
|
||||
return { attributes: {}, body: string }
|
||||
}
|
||||
}
|
||||
|
||||
function parse (string) {
|
||||
var match = regex.exec(string)
|
||||
|
||||
if (!match) {
|
||||
return {
|
||||
attributes: {},
|
||||
body: string
|
||||
}
|
||||
}
|
||||
|
||||
var yaml = match[match.length - 1].replace(/^\s+|\s+$/g, '')
|
||||
var attributes = parser(yaml) || {}
|
||||
var body = string.replace(match[0], '')
|
||||
|
||||
return { attributes: attributes, body: body, frontmatter: yaml }
|
||||
}
|
||||
|
||||
function test (string) {
|
||||
string = string || ''
|
||||
|
||||
return regex.test(string)
|
||||
}
|
||||
|
||||
export default extractor
|
||||
@@ -0,0 +1,469 @@
|
||||
/**
|
||||
* Fork https://github.com/egoist/docute/blob/master/src/utils/yaml.js
|
||||
*/
|
||||
/* eslint-disable */
|
||||
/*
|
||||
YAML parser for Javascript
|
||||
Author: Diogo Costa
|
||||
This program is released under the MIT License as follows:
|
||||
Copyright (c) 2011 Diogo Costa (costa.h4evr@gmail.com)
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name YAML
|
||||
* @namespace
|
||||
*/
|
||||
|
||||
|
||||
var errors = [],
|
||||
reference_blocks = [],
|
||||
processing_time = 0,
|
||||
regex =
|
||||
{
|
||||
"regLevel" : new RegExp("^([\\s\\-]+)"),
|
||||
"invalidLine" : new RegExp("^\\-\\-\\-|^\\.\\.\\.|^\\s*#.*|^\\s*$"),
|
||||
"dashesString" : new RegExp("^\\s*\\\"([^\\\"]*)\\\"\\s*$"),
|
||||
"quotesString" : new RegExp("^\\s*\\\'([^\\\']*)\\\'\\s*$"),
|
||||
"float" : new RegExp("^[+-]?[0-9]+\\.[0-9]+(e[+-]?[0-9]+(\\.[0-9]+)?)?$"),
|
||||
"integer" : new RegExp("^[+-]?[0-9]+$"),
|
||||
"array" : new RegExp("\\[\\s*(.*)\\s*\\]"),
|
||||
"map" : new RegExp("\\{\\s*(.*)\\s*\\}"),
|
||||
"key_value" : new RegExp("([a-z0-9_-][ a-z0-9_-]*):( .+)", "i"),
|
||||
"single_key_value" : new RegExp("^([a-z0-9_-][ a-z0-9_-]*):( .+?)$", "i"),
|
||||
"key" : new RegExp("([a-z0-9_-][ a-z0-9_-]+):( .+)?", "i"),
|
||||
"item" : new RegExp("^-\\s+"),
|
||||
"trim" : new RegExp("^\\s+|\\s+$"),
|
||||
"comment" : new RegExp("([^\\\'\\\"#]+([\\\'\\\"][^\\\'\\\"]*[\\\'\\\"])*)*(#.*)?")
|
||||
};
|
||||
|
||||
/**
|
||||
* @class A block of lines of a given level.
|
||||
* @param {int} lvl The block's level.
|
||||
* @private
|
||||
*/
|
||||
function Block(lvl) {
|
||||
return {
|
||||
/* The block's parent */
|
||||
parent: null,
|
||||
/* Number of children */
|
||||
length: 0,
|
||||
/* Block's level */
|
||||
level: lvl,
|
||||
/* Lines of code to process */
|
||||
lines: [],
|
||||
/* Blocks with greater level */
|
||||
children : [],
|
||||
/* Add a block to the children collection */
|
||||
addChild : function(obj) {
|
||||
this.children.push(obj);
|
||||
obj.parent = this;
|
||||
++this.length;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// function to create an XMLHttpClient in a cross-browser manner
|
||||
function createXMLHTTPRequest() {
|
||||
var xmlhttp;
|
||||
|
||||
try {
|
||||
// Mozilla / Safari / IE7
|
||||
xmlhttp = new XMLHttpRequest();
|
||||
} catch (e) {
|
||||
// IE
|
||||
var XMLHTTP_IDS = new Array('MSXML2.XMLHTTP.5.0',
|
||||
'MSXML2.XMLHTTP.4.0',
|
||||
'MSXML2.XMLHTTP.3.0',
|
||||
'MSXML2.XMLHTTP',
|
||||
'Microsoft.XMLHTTP' );
|
||||
var success = false;
|
||||
for (var i=0;i < XMLHTTP_IDS.length && !success; i++) {
|
||||
try {
|
||||
xmlhttp = new ActiveXObject(XMLHTTP_IDS[i]);
|
||||
success = true;
|
||||
} catch (e) {}
|
||||
}
|
||||
if (!success) {
|
||||
throw new Error('Unable to create XMLHttpRequest.');
|
||||
}
|
||||
}
|
||||
|
||||
return xmlhttp;
|
||||
}
|
||||
|
||||
function parser(str) {
|
||||
var regLevel = regex["regLevel"];
|
||||
var invalidLine = regex["invalidLine"];
|
||||
var lines = str.split("\n");
|
||||
var m;
|
||||
var level = 0, curLevel = 0;
|
||||
|
||||
var blocks = [];
|
||||
|
||||
var result = new Block(-1);
|
||||
var currentBlock = new Block(0);
|
||||
result.addChild(currentBlock);
|
||||
var levels = [];
|
||||
var line = "";
|
||||
|
||||
blocks.push(currentBlock);
|
||||
levels.push(level);
|
||||
|
||||
for(var i = 0, len = lines.length; i < len; ++i) {
|
||||
line = lines[i];
|
||||
|
||||
if(line.match(invalidLine)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(m = regLevel.exec(line)) {
|
||||
level = m[1].length;
|
||||
} else
|
||||
level = 0;
|
||||
|
||||
if(level > curLevel) {
|
||||
var oldBlock = currentBlock;
|
||||
currentBlock = new Block(level);
|
||||
oldBlock.addChild(currentBlock);
|
||||
blocks.push(currentBlock);
|
||||
levels.push(level);
|
||||
} else if(level < curLevel) {
|
||||
var added = false;
|
||||
|
||||
var k = levels.length - 1;
|
||||
for(; k >= 0; --k) {
|
||||
if(levels[k] == level) {
|
||||
currentBlock = new Block(level);
|
||||
blocks.push(currentBlock);
|
||||
levels.push(level);
|
||||
if(blocks[k].parent!= null)
|
||||
blocks[k].parent.addChild(currentBlock);
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!added) {
|
||||
errors.push("Error: Invalid indentation at line " + i + ": " + line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
currentBlock.lines.push(line.replace(regex["trim"], ""));
|
||||
curLevel = level;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function processValue(val) {
|
||||
val = val.replace(regex["trim"], "");
|
||||
var m = null;
|
||||
|
||||
if(val == 'true') {
|
||||
return true;
|
||||
} else if(val == 'false') {
|
||||
return false;
|
||||
} else if(val == '.NaN') {
|
||||
return Number.NaN;
|
||||
} else if(val == 'null') {
|
||||
return null;
|
||||
} else if(val == '.inf') {
|
||||
return Number.POSITIVE_INFINITY;
|
||||
} else if(val == '-.inf') {
|
||||
return Number.NEGATIVE_INFINITY;
|
||||
} else if(m = val.match(regex["dashesString"])) {
|
||||
return m[1];
|
||||
} else if(m = val.match(regex["quotesString"])) {
|
||||
return m[1];
|
||||
} else if(m = val.match(regex["float"])) {
|
||||
return parseFloat(m[0]);
|
||||
} else if(m = val.match(regex["integer"])) {
|
||||
return parseInt(m[0]);
|
||||
} else if( !isNaN(m = Date.parse(val))) {
|
||||
return new Date(m);
|
||||
} else if(m = val.match(regex["single_key_value"])) {
|
||||
var res = {};
|
||||
res[m[1]] = processValue(m[2]);
|
||||
return res;
|
||||
} else if(m = val.match(regex["array"])){
|
||||
var count = 0, c = ' ';
|
||||
var res = [];
|
||||
var content = "";
|
||||
var str = false;
|
||||
for(var j = 0, lenJ = m[1].length; j < lenJ; ++j) {
|
||||
c = m[1][j];
|
||||
if(c == '\'' || c == '"') {
|
||||
if(str === false) {
|
||||
str = c;
|
||||
content += c;
|
||||
continue;
|
||||
} else if((c == '\'' && str == '\'') || (c == '"' && str == '"')) {
|
||||
str = false;
|
||||
content += c;
|
||||
continue;
|
||||
}
|
||||
} else if(str === false && (c == '[' || c == '{')) {
|
||||
++count;
|
||||
} else if(str === false && (c == ']' || c == '}')) {
|
||||
--count;
|
||||
} else if(str === false && count == 0 && c == ',') {
|
||||
res.push(processValue(content));
|
||||
content = "";
|
||||
continue;
|
||||
}
|
||||
|
||||
content += c;
|
||||
}
|
||||
|
||||
if(content.length > 0)
|
||||
res.push(processValue(content));
|
||||
return res;
|
||||
} else if(m = val.match(regex["map"])){
|
||||
var count = 0, c = ' ';
|
||||
var res = [];
|
||||
var content = "";
|
||||
var str = false;
|
||||
for(var j = 0, lenJ = m[1].length; j < lenJ; ++j) {
|
||||
c = m[1][j];
|
||||
if(c == '\'' || c == '"') {
|
||||
if(str === false) {
|
||||
str = c;
|
||||
content += c;
|
||||
continue;
|
||||
} else if((c == '\'' && str == '\'') || (c == '"' && str == '"')) {
|
||||
str = false;
|
||||
content += c;
|
||||
continue;
|
||||
}
|
||||
} else if(str === false && (c == '[' || c == '{')) {
|
||||
++count;
|
||||
} else if(str === false && (c == ']' || c == '}')) {
|
||||
--count;
|
||||
} else if(str === false && count == 0 && c == ',') {
|
||||
res.push(content);
|
||||
content = "";
|
||||
continue;
|
||||
}
|
||||
|
||||
content += c;
|
||||
}
|
||||
|
||||
if(content.length > 0)
|
||||
res.push(content);
|
||||
|
||||
var newRes = {};
|
||||
for(var j = 0, lenJ = res.length; j < lenJ; ++j) {
|
||||
if(m = res[j].match(regex["key_value"])) {
|
||||
newRes[m[1]] = processValue(m[2]);
|
||||
}
|
||||
}
|
||||
|
||||
return newRes;
|
||||
} else
|
||||
return val;
|
||||
}
|
||||
|
||||
function processFoldedBlock(block) {
|
||||
var lines = block.lines;
|
||||
var children = block.children;
|
||||
var str = lines.join(" ");
|
||||
var chunks = [str];
|
||||
for(var i = 0, len = children.length; i < len; ++i) {
|
||||
chunks.push(processFoldedBlock(children[i]));
|
||||
}
|
||||
return chunks.join("\n");
|
||||
}
|
||||
|
||||
function processLiteralBlock(block) {
|
||||
var lines = block.lines;
|
||||
var children = block.children;
|
||||
var str = lines.join("\n");
|
||||
for(var i = 0, len = children.length; i < len; ++i) {
|
||||
str += processLiteralBlock(children[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function processBlock(blocks) {
|
||||
var m = null;
|
||||
var res = {};
|
||||
var lines = null;
|
||||
var children = null;
|
||||
var currentObj = null;
|
||||
|
||||
var level = -1;
|
||||
|
||||
var processedBlocks = [];
|
||||
|
||||
var isMap = true;
|
||||
|
||||
for(var j = 0, lenJ = blocks.length; j < lenJ; ++j) {
|
||||
|
||||
if(level != -1 && level != blocks[j].level)
|
||||
continue;
|
||||
|
||||
processedBlocks.push(j);
|
||||
|
||||
level = blocks[j].level;
|
||||
lines = blocks[j].lines;
|
||||
children = blocks[j].children;
|
||||
currentObj = null;
|
||||
|
||||
for(var i = 0, len = lines.length; i < len; ++i) {
|
||||
var line = lines[i];
|
||||
|
||||
if(m = line.match(regex["key"])) {
|
||||
var key = m[1];
|
||||
|
||||
if(key[0] == '-') {
|
||||
key = key.replace(regex["item"], "");
|
||||
if (isMap) {
|
||||
isMap = false;
|
||||
if (typeof(res.length) === "undefined") {
|
||||
res = [];
|
||||
}
|
||||
}
|
||||
if(currentObj != null) res.push(currentObj);
|
||||
currentObj = {};
|
||||
isMap = true;
|
||||
}
|
||||
|
||||
if(typeof m[2] != "undefined") {
|
||||
var value = m[2].replace(regex["trim"], "");
|
||||
if(value[0] == '&') {
|
||||
var nb = processBlock(children);
|
||||
if(currentObj != null) currentObj[key] = nb;
|
||||
else res[key] = nb;
|
||||
reference_blocks[value.substr(1)] = nb;
|
||||
} else if(value[0] == '|') {
|
||||
if(currentObj != null) currentObj[key] = processLiteralBlock(children.shift());
|
||||
else res[key] = processLiteralBlock(children.shift());
|
||||
} else if(value[0] == '*') {
|
||||
var v = value.substr(1);
|
||||
var no = {};
|
||||
|
||||
if(typeof reference_blocks[v] == "undefined") {
|
||||
errors.push("Reference '" + v + "' not found!");
|
||||
} else {
|
||||
for(var k in reference_blocks[v]) {
|
||||
no[k] = reference_blocks[v][k];
|
||||
}
|
||||
|
||||
if(currentObj != null) currentObj[key] = no;
|
||||
else res[key] = no;
|
||||
}
|
||||
} else if(value[0] == '>') {
|
||||
if(currentObj != null) currentObj[key] = processFoldedBlock(children.shift());
|
||||
else res[key] = processFoldedBlock(children.shift());
|
||||
} else {
|
||||
if(currentObj != null) currentObj[key] = processValue(value);
|
||||
else res[key] = processValue(value);
|
||||
}
|
||||
} else {
|
||||
if(currentObj != null) currentObj[key] = processBlock(children);
|
||||
else res[key] = processBlock(children);
|
||||
}
|
||||
} else if(line.match(/^-\s*$/)) {
|
||||
if (isMap) {
|
||||
isMap = false;
|
||||
if (typeof(res.length) === "undefined") {
|
||||
res = [];
|
||||
}
|
||||
}
|
||||
if(currentObj != null) res.push(currentObj);
|
||||
currentObj = {};
|
||||
isMap = true;
|
||||
continue;
|
||||
} else if(m = line.match(/^-\s*(.*)/)) {
|
||||
if(currentObj != null)
|
||||
currentObj.push(processValue(m[1]));
|
||||
else {
|
||||
if (isMap) {
|
||||
isMap = false;
|
||||
if (typeof(res.length) === "undefined") {
|
||||
res = [];
|
||||
}
|
||||
}
|
||||
res.push(processValue(m[1]));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(currentObj != null) {
|
||||
if (isMap) {
|
||||
isMap = false;
|
||||
if (typeof(res.length) === "undefined") {
|
||||
res = [];
|
||||
}
|
||||
}
|
||||
res.push(currentObj);
|
||||
}
|
||||
}
|
||||
|
||||
for(var j = processedBlocks.length - 1; j >= 0; --j) {
|
||||
blocks.splice.call(blocks, processedBlocks[j], 1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function semanticAnalysis(blocks) {
|
||||
var res = processBlock(blocks.children);
|
||||
return res;
|
||||
}
|
||||
|
||||
function preProcess(src) {
|
||||
var m;
|
||||
var lines = src.split("\n");
|
||||
|
||||
var r = regex["comment"];
|
||||
|
||||
for(var i in lines) {
|
||||
if(m = lines[i].match(r)) {
|
||||
/* var cmt = "";
|
||||
if(typeof m[3] != "undefined")
|
||||
lines[i] = m[1];
|
||||
else if(typeof m[3] != "undefined")
|
||||
lines[i] = m[3];
|
||||
else
|
||||
lines[i] = "";
|
||||
*/
|
||||
if(typeof m[3] !== "undefined") {
|
||||
lines[i] = m[0].substr(0, m[0].length - m[3].length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
function load(str) {
|
||||
errors = [];
|
||||
reference_blocks = [];
|
||||
processing_time = (new Date()).getTime();
|
||||
var pre = preProcess(str)
|
||||
var doc = parser(pre);
|
||||
var res = semanticAnalysis(doc);
|
||||
processing_time = (new Date()).getTime() - processing_time;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
export default load
|
||||
+3
-10
@@ -1,5 +1,4 @@
|
||||
// From https://github.com/egoist/vue-ga/blob/master/src/index.js
|
||||
|
||||
function appendScript () {
|
||||
const script = document.createElement('script')
|
||||
script.async = true
|
||||
@@ -24,19 +23,13 @@ function collect () {
|
||||
window.ga('send', 'pageview')
|
||||
}
|
||||
|
||||
const install = function () {
|
||||
if (install.installed) return
|
||||
install.installed = true
|
||||
|
||||
const install = function (hook) {
|
||||
if (!window.$docsify.ga) {
|
||||
console.error('[Docsify] ga is required.')
|
||||
return
|
||||
}
|
||||
|
||||
window.$docsify.plugins = [].concat(function (hook) {
|
||||
hook.init(collect)
|
||||
hook.beforeEach(collect)
|
||||
}, window.$docsify.plugins)
|
||||
hook.beforeEach(collect)
|
||||
}
|
||||
|
||||
export default install()
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins)
|
||||
|
||||
@@ -1,349 +0,0 @@
|
||||
let INDEXS = {}
|
||||
const CONFIG = {
|
||||
placeholder: 'Type to search',
|
||||
paths: 'auto',
|
||||
maxAge: 86400000 // 1 day
|
||||
}
|
||||
|
||||
const isObj = function (obj) {
|
||||
return Object.prototype.toString.call(obj) === '[object Object]'
|
||||
}
|
||||
|
||||
const escapeHtml = function (string) {
|
||||
const entityMap = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'/': '/'
|
||||
}
|
||||
|
||||
return String(string).replace(/[&<>"'\/]/g, s => entityMap[s])
|
||||
}
|
||||
|
||||
/**
|
||||
* find all filepath from A tag
|
||||
*/
|
||||
const getAllPaths = function () {
|
||||
const paths = []
|
||||
|
||||
;[].slice.call(document.querySelectorAll('a'))
|
||||
.map(node => {
|
||||
const href = node.href
|
||||
if (/#\/[^#]*?$/.test(href)) {
|
||||
const path = href.replace(/^[^#]+#/, '')
|
||||
|
||||
if (paths.indexOf(path) <= 0) paths.push(path)
|
||||
}
|
||||
})
|
||||
|
||||
return paths
|
||||
}
|
||||
|
||||
/**
|
||||
* return file path
|
||||
*/
|
||||
const genFilePath = function (path, basePath = window.$docsify.basePath) {
|
||||
let filePath = /\/$/.test(path) ? `${path}README.md` : `${path}.md`
|
||||
|
||||
filePath = basePath + filePath
|
||||
|
||||
return filePath.replace(/\/+/g, '/')
|
||||
}
|
||||
|
||||
/**
|
||||
* generate index
|
||||
*/
|
||||
const genIndex = function (path, content = '') {
|
||||
INDEXS[path] = { slug: '', title: '', body: '' }
|
||||
let slug
|
||||
|
||||
content
|
||||
// remove PRE and TEMPLATE tag
|
||||
.replace(/<template[^>]*?>[\s\S]+?<\/template>/g, '')
|
||||
// find all html tag
|
||||
.replace(/<(\w+)([^>]*?)>([\s\S]+?)<\//g, (match, tag, attr, html) => {
|
||||
// remove all html tag
|
||||
const text = html.replace(/<[^>]+>/g, '')
|
||||
|
||||
// tag is headline
|
||||
if (/^h\d$/.test(tag)) {
|
||||
// <h1 id="xxx"></h1>
|
||||
const id = attr.match(/id="(\S+)"/)[1]
|
||||
|
||||
slug = `#/${path}#${id}`.replace(/\/+/, '/')
|
||||
INDEXS[slug] = { slug, title: text, body: '' }
|
||||
} else {
|
||||
if (!slug) return
|
||||
// other html tag
|
||||
if (!INDEXS[slug]) {
|
||||
INDEXS[slug] = {}
|
||||
} else {
|
||||
if (INDEXS[slug].body && INDEXS[slug].body.length) {
|
||||
INDEXS[slug].body += '\n' + text
|
||||
} else {
|
||||
INDEXS[slug].body = text
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* component
|
||||
*/
|
||||
class SearchComponent {
|
||||
constructor () {
|
||||
if (this.rendered) return
|
||||
|
||||
this.style()
|
||||
|
||||
const el = document.createElement('div')
|
||||
const aside = document.querySelector('aside')
|
||||
|
||||
el.classList.add('search')
|
||||
aside.insertBefore(el, aside.children[0])
|
||||
this.render(el)
|
||||
this.rendered = true
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
style () {
|
||||
const code = `
|
||||
.sidebar {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.search {
|
||||
margin-bottom: 20px;
|
||||
padding: 6px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.search .results-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search .results-panel.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.search input {
|
||||
outline: none;
|
||||
border: none;
|
||||
width: 100%;
|
||||
padding: 7px;
|
||||
line-height: 22px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.search h2 {
|
||||
font-size: 17px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.search a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.search .matching-post {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.search .matching-post:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.search p {
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.search p.empty {
|
||||
text-align: center;
|
||||
}
|
||||
`
|
||||
const style = document.createElement('style')
|
||||
|
||||
style.innerHTML = code
|
||||
document.head.appendChild(style)
|
||||
}
|
||||
|
||||
render (dom) {
|
||||
dom.innerHTML = `<input type="search" placeholder="${CONFIG.placeholder}" /><div class="results-panel"></div>`
|
||||
}
|
||||
|
||||
bindEvent () {
|
||||
const search = document.querySelector('.search')
|
||||
const input = search.querySelector('.search input')
|
||||
const panel = search.querySelector('.results-panel')
|
||||
|
||||
search.addEventListener('click', e => e.target.tagName !== 'A' && e.stopPropagation())
|
||||
input.addEventListener('input', e => {
|
||||
const target = e.target
|
||||
|
||||
if (target.value.trim() !== '') {
|
||||
const matchingPosts = this.search(target.value)
|
||||
let html = ''
|
||||
|
||||
matchingPosts.forEach(function (post, index) {
|
||||
html += `
|
||||
<div class="matching-post">
|
||||
<h2><a href="${post.url}">${post.title}</a></h2>
|
||||
<p>${post.content}</p>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
if (panel.classList.contains('results-panel')) {
|
||||
panel.classList.add('show')
|
||||
panel.innerHTML = html || '<p class="empty">No Results!</p>'
|
||||
}
|
||||
} else {
|
||||
if (panel.classList.contains('results-panel')) {
|
||||
panel.classList.remove('show')
|
||||
panel.innerHTML = ''
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// From [weex website] https://weex-project.io/js/common.js
|
||||
search (keywords) {
|
||||
const matchingResults = []
|
||||
const data = Object.keys(INDEXS).map(key => INDEXS[key])
|
||||
|
||||
keywords = keywords.trim().split(/[\s\-\,\\/]+/)
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const post = data[i]
|
||||
let isMatch = false
|
||||
let resultStr = ''
|
||||
const postTitle = post.title && post.title.trim()
|
||||
const postContent = post.body && post.body.trim()
|
||||
const postUrl = post.slug || ''
|
||||
|
||||
if (postTitle !== '' && postContent !== '') {
|
||||
keywords.forEach((keyword, i) => {
|
||||
const regEx = new RegExp(keyword, 'gi')
|
||||
let indexTitle = -1
|
||||
let indexContent = -1
|
||||
|
||||
indexTitle = postTitle.search(regEx)
|
||||
indexContent = postContent.search(regEx)
|
||||
|
||||
if (indexTitle < 0 && indexContent < 0) {
|
||||
isMatch = false
|
||||
} else {
|
||||
isMatch = true
|
||||
if (indexContent < 0) indexContent = 0
|
||||
|
||||
let start = 0
|
||||
let end = 0
|
||||
|
||||
start = indexContent < 11 ? 0 : indexContent - 10
|
||||
end = start === 0 ? 70 : indexContent + keyword.length + 60
|
||||
|
||||
if (end > postContent.length) end = postContent.length
|
||||
|
||||
const matchContent = '...' +
|
||||
postContent
|
||||
.substring(start, end)
|
||||
.replace(regEx, `<em class="search-keyword">${keyword}</em>`) +
|
||||
'...'
|
||||
|
||||
resultStr += matchContent
|
||||
}
|
||||
})
|
||||
|
||||
if (isMatch) {
|
||||
const matchingPost = {
|
||||
title: escapeHtml(postTitle),
|
||||
content: resultStr,
|
||||
url: postUrl
|
||||
}
|
||||
|
||||
matchingResults.push(matchingPost)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matchingResults
|
||||
}
|
||||
}
|
||||
|
||||
const searchPlugin = function () {
|
||||
const isAuto = CONFIG.paths === 'auto'
|
||||
const isExpired = localStorage.getItem('docsify.search.expires') < Date.now()
|
||||
|
||||
INDEXS = JSON.parse(localStorage.getItem('docsify.search.index'))
|
||||
|
||||
if (isExpired) {
|
||||
INDEXS = {}
|
||||
} else if (!isAuto) {
|
||||
return
|
||||
}
|
||||
|
||||
let count = 0
|
||||
const paths = isAuto ? getAllPaths() : CONFIG.paths
|
||||
const len = paths.length
|
||||
const { load, marked, slugify } = window.Docsify.utils
|
||||
const alias = window.$docsify.alias
|
||||
const done = () => {
|
||||
localStorage.setItem('docsify.search.expires', Date.now() + CONFIG.maxAge)
|
||||
localStorage.setItem('docsify.search.index', JSON.stringify(INDEXS))
|
||||
}
|
||||
|
||||
paths.forEach(path => {
|
||||
if (INDEXS[path]) return count++
|
||||
let route
|
||||
|
||||
// replace route
|
||||
if (alias && alias[path]) {
|
||||
route = genFilePath(alias[path] || path, '')
|
||||
} else {
|
||||
route = genFilePath(path)
|
||||
}
|
||||
|
||||
load(route).then(content => {
|
||||
genIndex(path, marked(content))
|
||||
slugify.clear()
|
||||
count++
|
||||
|
||||
if (len === count) done()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const install = function () {
|
||||
if (install.installed) return
|
||||
install.installed = true
|
||||
|
||||
const userConfig = window.$docsify.search
|
||||
const isNil = window.Docsify.utils.isNil
|
||||
|
||||
if (Array.isArray(userConfig)) {
|
||||
CONFIG.paths = userConfig
|
||||
} else if (isObj(userConfig)) {
|
||||
CONFIG.paths = Array.isArray(userConfig.paths) ? userConfig.paths : 'auto'
|
||||
CONFIG.maxAge = isNil(userConfig.maxAge) ? CONFIG.maxAge : userConfig.maxAge
|
||||
CONFIG.placeholder = userConfig.placeholder || CONFIG.placeholder
|
||||
}
|
||||
|
||||
window.$docsify.plugins = [].concat(hook => {
|
||||
const isAuto = CONFIG.paths === 'auto'
|
||||
|
||||
hook.ready(() => {
|
||||
new SearchComponent()
|
||||
!isAuto && searchPlugin()
|
||||
})
|
||||
isAuto && hook.doneEach(searchPlugin)
|
||||
}, window.$docsify.plugins)
|
||||
}
|
||||
|
||||
export default install()
|
||||
@@ -0,0 +1,146 @@
|
||||
import { search } from './search'
|
||||
|
||||
let dom
|
||||
let NO_DATA_TEXT = ''
|
||||
|
||||
function style () {
|
||||
const code = `
|
||||
.sidebar {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.search {
|
||||
margin-bottom: 20px;
|
||||
padding: 6px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.search .results-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search .results-panel.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.search input {
|
||||
outline: none;
|
||||
border: none;
|
||||
width: 100%;
|
||||
padding: 7px;
|
||||
line-height: 22px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.search h2 {
|
||||
font-size: 17px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.search a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.search .matching-post {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.search .matching-post:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.search p {
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.search p.empty {
|
||||
text-align: center;
|
||||
}`
|
||||
const style = dom.create('style', code)
|
||||
dom.appendTo(dom.head, style)
|
||||
}
|
||||
|
||||
function tpl (opts) {
|
||||
const html =
|
||||
`<input type="search" />` +
|
||||
'<div class="results-panel"></div>' +
|
||||
'</div>'
|
||||
const el = dom.create('div', html)
|
||||
const aside = dom.find('aside')
|
||||
|
||||
dom.toggleClass(el, 'search')
|
||||
dom.before(aside, el)
|
||||
}
|
||||
|
||||
function bindEvents () {
|
||||
const $search = dom.find('div.search')
|
||||
const $input = dom.find($search, 'input')
|
||||
const $panel = dom.find($search, '.results-panel')
|
||||
const doSearch = function (value) {
|
||||
if (!value) {
|
||||
$panel.classList.remove('show')
|
||||
$panel.innerHTML = ''
|
||||
return
|
||||
}
|
||||
const matchs = search(value)
|
||||
|
||||
let html = ''
|
||||
matchs.forEach(post => {
|
||||
html += `<div class="matching-post">
|
||||
<h2><a href="${post.url}">${post.title}</a></h2>
|
||||
<p>${post.content}</p>
|
||||
</div>`
|
||||
})
|
||||
|
||||
$panel.classList.add('show')
|
||||
$panel.innerHTML = html || `<p class="empty">${NO_DATA_TEXT}</p>`
|
||||
}
|
||||
|
||||
let timeId
|
||||
// Prevent to Fold sidebar
|
||||
dom.on($search, 'click',
|
||||
e => e.target.tagName !== 'A' && e.stopPropagation())
|
||||
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"]')
|
||||
|
||||
if (typeof text === 'string') {
|
||||
$input.placeholder = text
|
||||
} else {
|
||||
const match = Object.keys(text).find(key => path.indexOf(key) > -1)
|
||||
$input.placeholder = text[match]
|
||||
}
|
||||
}
|
||||
|
||||
function updateNoData (text, path) {
|
||||
if (typeof text === 'string') {
|
||||
NO_DATA_TEXT = text
|
||||
} else {
|
||||
const match = Object.keys(text).find(key => path.indexOf(key) > -1)
|
||||
NO_DATA_TEXT = text[match]
|
||||
}
|
||||
}
|
||||
|
||||
export function init (opts) {
|
||||
dom = Docsify.dom
|
||||
style()
|
||||
tpl(opts)
|
||||
bindEvents()
|
||||
}
|
||||
|
||||
export function update (opts, vm) {
|
||||
updatePlaceholder(opts.placeholder, vm.route.path)
|
||||
updateNoData(opts.noData, vm.route.path)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { init as initComponet, update as updateComponent } from './component'
|
||||
import { init as initSearch } from './search'
|
||||
|
||||
const CONFIG = {
|
||||
placeholder: 'Type to search',
|
||||
noData: 'No Results!',
|
||||
paths: 'auto',
|
||||
maxAge: 86400000 // 1 day
|
||||
}
|
||||
|
||||
const install = function (hook, vm) {
|
||||
const util = Docsify.util
|
||||
const opts = vm.config.search || CONFIG
|
||||
|
||||
if (Array.isArray(opts)) {
|
||||
CONFIG.paths = opts
|
||||
} else if (typeof opts === 'object') {
|
||||
CONFIG.paths = Array.isArray(opts.paths) ? opts.paths : 'auto'
|
||||
CONFIG.maxAge = util.isPrimitive(opts.maxAge) ? opts.maxAge : CONFIG.maxAge
|
||||
CONFIG.placeholder = opts.placeholder || CONFIG.placeholder
|
||||
CONFIG.noData = opts.noData || CONFIG.noData
|
||||
}
|
||||
|
||||
const isAuto = CONFIG.paths === 'auto'
|
||||
|
||||
hook.mounted(_ => {
|
||||
initComponet(CONFIG)
|
||||
!isAuto && initSearch(CONFIG, vm)
|
||||
})
|
||||
hook.doneEach(_ => {
|
||||
updateComponent(CONFIG, vm)
|
||||
isAuto && initSearch(CONFIG, vm)
|
||||
})
|
||||
}
|
||||
|
||||
window.$docsify.plugins = [].concat(install, window.$docsify.plugins)
|
||||
@@ -0,0 +1,163 @@
|
||||
let INDEXS = {}
|
||||
let helper
|
||||
|
||||
function escapeHtml (string) {
|
||||
const entityMap = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
'\'': ''',
|
||||
'/': '/'
|
||||
}
|
||||
|
||||
return String(string).replace(/[&<>"'\/]/g, s => entityMap[s])
|
||||
}
|
||||
|
||||
function getAllPaths () {
|
||||
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
|
||||
|
||||
if (path &&
|
||||
paths.indexOf(path) === -1 &&
|
||||
!helper.route.isAbsolutePath(originHref)) {
|
||||
paths.push(path)
|
||||
}
|
||||
})
|
||||
|
||||
return paths
|
||||
}
|
||||
|
||||
function saveData (maxAge) {
|
||||
localStorage.setItem('docsify.search.expires', Date.now() + maxAge)
|
||||
localStorage.setItem('docsify.search.index', JSON.stringify(INDEXS))
|
||||
}
|
||||
|
||||
export function genIndex (path, content = '') {
|
||||
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) })
|
||||
index[slug] = { slug, title: token.text, body: '' }
|
||||
} else {
|
||||
if (!slug) return
|
||||
if (!index[slug]) {
|
||||
index[slug] = { slug, title: '', body: '' }
|
||||
} else {
|
||||
if (index[slug].body) {
|
||||
index[slug].body += '\n' + (token.text || '')
|
||||
} else {
|
||||
index[slug].body = token.text
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
slugify.clear()
|
||||
return index
|
||||
}
|
||||
|
||||
export function search (keywords) {
|
||||
const matchingResults = []
|
||||
let data = []
|
||||
Object.keys(INDEXS).forEach(key => {
|
||||
data = data.concat(Object.keys(INDEXS[key]).map(page => INDEXS[key][page]))
|
||||
})
|
||||
|
||||
keywords = keywords.trim().split(/[\s\-\,\\/]+/)
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const post = data[i]
|
||||
let isMatch = false
|
||||
let resultStr = ''
|
||||
const postTitle = post.title && post.title.trim()
|
||||
const postContent = post.body && post.body.trim()
|
||||
const postUrl = post.slug || ''
|
||||
|
||||
if (postTitle && postContent) {
|
||||
keywords.forEach((keyword, i) => {
|
||||
const regEx = new RegExp(keyword, 'gi')
|
||||
let indexTitle = -1
|
||||
let indexContent = -1
|
||||
|
||||
indexTitle = postTitle && postTitle.search(regEx)
|
||||
indexContent = postContent && postContent.search(regEx)
|
||||
|
||||
if (indexTitle < 0 && indexContent < 0) {
|
||||
isMatch = false
|
||||
} else {
|
||||
isMatch = true
|
||||
if (indexContent < 0) indexContent = 0
|
||||
|
||||
let start = 0
|
||||
let end = 0
|
||||
|
||||
start = indexContent < 11 ? 0 : indexContent - 10
|
||||
end = start === 0 ? 70 : indexContent + keyword.length + 60
|
||||
|
||||
if (end > postContent.length) end = postContent.length
|
||||
|
||||
const matchContent = '...' +
|
||||
escapeHtml(postContent)
|
||||
.substring(start, end)
|
||||
.replace(regEx, `<em class="search-keyword">${keyword}</em>`) +
|
||||
'...'
|
||||
|
||||
resultStr += matchContent
|
||||
}
|
||||
})
|
||||
|
||||
if (isMatch) {
|
||||
const matchingPost = {
|
||||
title: escapeHtml(postTitle),
|
||||
content: resultStr,
|
||||
url: postUrl
|
||||
}
|
||||
|
||||
matchingResults.push(matchingPost)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matchingResults
|
||||
}
|
||||
|
||||
export function init (config, vm) {
|
||||
helper = Docsify
|
||||
|
||||
const isAuto = config.paths === 'auto'
|
||||
const isExpired = localStorage.getItem('docsify.search.expires') < Date.now()
|
||||
|
||||
INDEXS = JSON.parse(localStorage.getItem('docsify.search.index'))
|
||||
|
||||
if (isExpired) {
|
||||
INDEXS = {}
|
||||
} else if (!isAuto) {
|
||||
return
|
||||
}
|
||||
|
||||
const paths = isAuto ? getAllPaths() : config.paths
|
||||
const len = paths.length
|
||||
let count = 0
|
||||
|
||||
paths.forEach(path => {
|
||||
if (INDEXS[path]) return count++
|
||||
|
||||
helper
|
||||
.get(vm.$getFile(path))
|
||||
.then(result => {
|
||||
INDEXS[path] = genIndex(path, result)
|
||||
len === ++count && saveData(config.maxAge)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import zoom from 'zoom-image'
|
||||
import style from 'zoom-image/css/zoom-image.css'
|
||||
|
||||
function install (hook) {
|
||||
const dom = Docsify.dom
|
||||
let destroys
|
||||
|
||||
// add style
|
||||
dom.appendTo(dom.head, dom.create('style', style))
|
||||
|
||||
hook.doneEach(_ => {
|
||||
const images = dom.findAll('img:not(.emoji)')
|
||||
|
||||
if (Array.isArray(destroys) && destroys.length) {
|
||||
destroys.forEach(o => o())
|
||||
destroys = []
|
||||
}
|
||||
|
||||
destroys = images.map(zoom)
|
||||
})
|
||||
}
|
||||
|
||||
$docsify.plugins = [].concat(install, $docsify.plugins)
|
||||
@@ -1,30 +0,0 @@
|
||||
import { load } from './util'
|
||||
|
||||
function replaceVar (block) {
|
||||
block.innerHTML = block.innerHTML.replace(/var\(\s*--theme-color.*?\)/g, $docsify.themeColor)
|
||||
}
|
||||
|
||||
export function cssVars () {
|
||||
// variable support
|
||||
if (window.CSS && window.CSS.supports && window.CSS.supports('(--foo: red)')) return
|
||||
|
||||
const styleBlocks = document.querySelectorAll('style:not(.inserted),link')
|
||||
|
||||
;[].forEach.call(styleBlocks, block => {
|
||||
if (block.nodeName === 'STYLE') {
|
||||
replaceVar(block)
|
||||
} else if (block.nodeName === 'LINK') {
|
||||
const href = block.getAttribute('href')
|
||||
|
||||
if (!/\.css$/.test(href)) return
|
||||
|
||||
load(href).then(res => {
|
||||
const style = document.createElement('style')
|
||||
|
||||
style.innerHTML = res
|
||||
document.head.appendChild(style)
|
||||
replaceVar(style)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
-270
@@ -1,270 +0,0 @@
|
||||
import marked from 'marked'
|
||||
import Prism from 'prismjs'
|
||||
import * as tpl from './tpl'
|
||||
import * as event from './event'
|
||||
import * as polyfill from './polyfill'
|
||||
import { genTree, getRoute, isMobile, slugify, merge, emojify } from './util'
|
||||
|
||||
let markdown = marked
|
||||
let toc = []
|
||||
const CACHE = {}
|
||||
const originTitle = document.title
|
||||
|
||||
const renderTo = function (dom, content) {
|
||||
dom = typeof dom === 'object' ? dom : document.querySelector(dom)
|
||||
dom.innerHTML = content
|
||||
slugify.clear()
|
||||
|
||||
return dom
|
||||
}
|
||||
|
||||
/**
|
||||
* init render
|
||||
*/
|
||||
export function init () {
|
||||
const renderer = new marked.Renderer()
|
||||
/**
|
||||
* render anchor tag
|
||||
* @link https://github.com/chjj/marked#overriding-renderer-methods
|
||||
*/
|
||||
renderer.heading = function (text, level) {
|
||||
const slug = slugify(text)
|
||||
let route = ''
|
||||
|
||||
route = `#/${getRoute()}`
|
||||
toc.push({ level, slug: `${route}#${encodeURIComponent(slug)}`, title: text })
|
||||
|
||||
return `<h${level} id="${slug}"><a href="${route}#${slug}" 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) {
|
||||
if (!/:|(\/{2})/.test(href)) {
|
||||
href = `#/${href}`.replace(/\/+/g, '/')
|
||||
}
|
||||
return `<a href="${href}" title="${title || ''}">${text}</a>`
|
||||
}
|
||||
renderer.paragraph = function (text) {
|
||||
if (/^!>/.test(text)) {
|
||||
return tpl.helper('tip', text)
|
||||
} else if (/^\?>/.test(text)) {
|
||||
return tpl.helper('warn', text)
|
||||
}
|
||||
return `<p>${text}</p>`
|
||||
}
|
||||
renderer.image = function (href, title, text) {
|
||||
const url = /:|(\/{2})/.test(href) ? href : ($docsify.basePath + href).replace(/\/+/g, '/')
|
||||
const titleHTML = title ? ` title="${title}"` : ''
|
||||
|
||||
return `<img src="${url}" alt="${text}"${titleHTML} />`
|
||||
}
|
||||
|
||||
if (typeof $docsify.markdown === 'function') {
|
||||
markdown = $docsify.markdown.call(this, markdown, renderer)
|
||||
} else {
|
||||
if ($docsify.markdown && $docsify.markdown.renderer) {
|
||||
$docsify.markdown.renderer = merge(renderer, $docsify.markdown.renderer)
|
||||
}
|
||||
markdown.setOptions(merge({ renderer }, $docsify.markdown))
|
||||
}
|
||||
|
||||
const md = markdown
|
||||
|
||||
markdown = text => emojify(md(text))
|
||||
|
||||
window.Docsify.utils.marked = text => {
|
||||
const result = markdown(text)
|
||||
toc = []
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* App
|
||||
*/
|
||||
export function renderApp (dom, replace) {
|
||||
const nav = document.querySelector('nav') || document.createElement('nav')
|
||||
const body = document.body
|
||||
const head = document.head
|
||||
|
||||
if (!$docsify.repo) nav.classList.add('no-badge')
|
||||
|
||||
dom[replace ? 'outerHTML' : 'innerHTML'] = tpl.corner($docsify.repo) +
|
||||
($docsify.coverpage ? tpl.cover() : '') +
|
||||
tpl.main()
|
||||
body.insertBefore(nav, body.children[0])
|
||||
|
||||
// theme color
|
||||
if ($docsify.themeColor) {
|
||||
head.innerHTML += tpl.theme($docsify.themeColor)
|
||||
polyfill.cssVars()
|
||||
}
|
||||
|
||||
// render name
|
||||
if ($docsify.name) {
|
||||
const aside = document.querySelector('.sidebar')
|
||||
aside.innerHTML = `<h1><a href="${$docsify.nameLink}">${$docsify.name}</a></h1>` + aside.innerHTML
|
||||
}
|
||||
|
||||
// bind toggle
|
||||
event.bindToggle('button.sidebar-toggle')
|
||||
// bind sticky effect
|
||||
if ($docsify.coverpage) {
|
||||
!isMobile() && window.addEventListener('scroll', event.sticky)
|
||||
} else {
|
||||
body.classList.add('sticky')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* article
|
||||
*/
|
||||
export function renderArticle (content) {
|
||||
const hook = window.Docsify.hook
|
||||
const renderFn = function (data) {
|
||||
renderTo('article', data)
|
||||
if (!$docsify.loadSidebar) renderSidebar()
|
||||
|
||||
if (data && typeof Vue !== 'undefined') {
|
||||
CACHE.vm && CACHE.vm.$destroy()
|
||||
|
||||
const script = [].slice.call(
|
||||
document.body.querySelectorAll('article>script'))
|
||||
.filter(script => !/template/.test(script.type)
|
||||
)[0]
|
||||
const code = script ? script.innerText.trim() : null
|
||||
|
||||
script && script.remove()
|
||||
CACHE.vm = code
|
||||
? new Function(`return ${code}`)()
|
||||
: new Vue({ el: 'main' }) // eslint-disable-line
|
||||
CACHE.vm && CACHE.vm.$nextTick(_ => event.scrollActiveSidebar())
|
||||
}
|
||||
if ($docsify.auto2top) setTimeout(() => event.scroll2Top($docsify.auto2top), 0)
|
||||
}
|
||||
|
||||
hook.emit('before', content, result => {
|
||||
const html = result ? markdown(result) : ''
|
||||
|
||||
hook.emit('after', html, result => renderFn(result || 'not found'))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* navbar
|
||||
*/
|
||||
export function renderNavbar (content) {
|
||||
if (CACHE.navbar && CACHE.navbar === content) return
|
||||
CACHE.navbar = content
|
||||
|
||||
if (content) renderTo('nav', markdown(content))
|
||||
event.activeLink('nav')
|
||||
}
|
||||
|
||||
/**
|
||||
* sidebar
|
||||
*/
|
||||
export function renderSidebar (content) {
|
||||
let html
|
||||
|
||||
if (content) {
|
||||
html = markdown(content)
|
||||
// find url tag
|
||||
html = html.match(/<ul[^>]*>([\s\S]+)<\/ul>/g)[0]
|
||||
} else {
|
||||
html = tpl.tree(genTree(toc, $docsify.maxLevel), '<ul>')
|
||||
}
|
||||
|
||||
renderTo('.sidebar-nav', html)
|
||||
|
||||
if (toc[0] && toc[0].level === 1) {
|
||||
document.title = `${toc[0].title}${originTitle ? ' - ' + originTitle : ''}`
|
||||
}
|
||||
|
||||
const target = event.activeLink('.sidebar-nav', true)
|
||||
if (target) renderSubSidebar(target)
|
||||
|
||||
toc = []
|
||||
event.scrollActiveSidebar()
|
||||
}
|
||||
|
||||
export function renderSubSidebar (target) {
|
||||
if (!$docsify.subMaxLevel) return
|
||||
toc[0] && toc[0].level === 1 && toc.shift()
|
||||
target.parentNode.innerHTML += tpl.tree(genTree(toc, $docsify.subMaxLevel), '<ul>')
|
||||
}
|
||||
|
||||
/**
|
||||
* Cover Page
|
||||
*/
|
||||
export function renderCover (content) {
|
||||
renderCover.dom = renderCover.dom || document.querySelector('section.cover')
|
||||
if (!content) {
|
||||
renderCover.dom.classList.remove('show')
|
||||
return
|
||||
}
|
||||
renderCover.dom.classList.add('show')
|
||||
if (renderCover.rendered) return event.sticky()
|
||||
|
||||
// render cover
|
||||
const cacheToc = toc.slice()
|
||||
let html = markdown(content)
|
||||
const match = html.trim().match('<p><img[^s]+src="(.*?)"[^a]+alt="(.*?)">([^<]*?)</p>$')
|
||||
|
||||
toc = cacheToc.slice()
|
||||
|
||||
// render background
|
||||
if (match) {
|
||||
const coverEl = document.querySelector('section.cover')
|
||||
|
||||
if (match[2] === 'color') {
|
||||
coverEl.style.background = match[1] + (match[3] || '')
|
||||
} else {
|
||||
coverEl.classList.add('has-mask')
|
||||
coverEl.style.backgroundImage = `url(${match[1]})`
|
||||
}
|
||||
html = html.replace(match[0], '')
|
||||
}
|
||||
|
||||
renderTo('.cover-main', html)
|
||||
renderCover.rendered = true
|
||||
|
||||
event.sticky()
|
||||
}
|
||||
|
||||
/**
|
||||
* render loading bar
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
export function renderLoading ({ loaded, total, step }) {
|
||||
let num
|
||||
|
||||
if (!CACHE.loading) {
|
||||
const div = document.createElement('div')
|
||||
|
||||
div.classList.add('progress')
|
||||
document.body.appendChild(div)
|
||||
CACHE.loading = div
|
||||
}
|
||||
if (step) {
|
||||
num = parseInt(CACHE.loading.style.width, 10) + step
|
||||
num = num > 80 ? 80 : num
|
||||
} else {
|
||||
num = Math.floor(loaded / total * 100)
|
||||
}
|
||||
|
||||
CACHE.loading.style.opacity = 1
|
||||
CACHE.loading.style.width = num >= 95 ? '100%' : num + '%'
|
||||
|
||||
if (num >= 95) {
|
||||
clearTimeout(renderLoading.cacheTimeout)
|
||||
renderLoading.cacheTimeout = setTimeout(_ => {
|
||||
CACHE.loading.style.opacity = 0
|
||||
CACHE.loading.style.width = '0%'
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
@@ -11,16 +11,16 @@ section.cover {
|
||||
}
|
||||
|
||||
&.has-mask .mask {
|
||||
position: absolute;
|
||||
size: 100%;
|
||||
background-color: $color-bg;
|
||||
opacity: .8;
|
||||
position: absolute;
|
||||
size: 100%;
|
||||
}
|
||||
|
||||
.cover-main {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
margin: -20px 16px 0;
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@@ -34,65 +34,65 @@ section.cover {
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 1em 0;
|
||||
line-height: 1.5rem;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 2.5rem;
|
||||
position: relative;
|
||||
margin: .625rem 0 2.5rem;
|
||||
font-weight: 300;
|
||||
color: inherit;
|
||||
font-size: 2.5rem;
|
||||
font-weight: 300;
|
||||
margin: .625rem 0 2.5rem;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
small {
|
||||
position: absolute;
|
||||
bottom: -.4375rem;
|
||||
font-size: 1rem;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
text-align: center;
|
||||
font-size: 1.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ul {
|
||||
max-width: 500px;
|
||||
line-height: 1.8;
|
||||
list-style-type: none;
|
||||
margin: 1em auto;
|
||||
max-width: 500px;
|
||||
padding: 0;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.cover-main p:last-child a {
|
||||
border-radius: 2em;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
.cover-main > p:last-child a {
|
||||
border-color: var(--theme-color, $color-primary);
|
||||
border-radius: 2em;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
box-sizing: border-box;
|
||||
color: var(--theme-color, $color-primary);
|
||||
display: inline-block;
|
||||
font-size: 1.05em;
|
||||
letter-spacing: 0.1em;
|
||||
margin-right: 1em;
|
||||
padding: 0.75em 2em;
|
||||
text-decoration: none;
|
||||
transition: all 0.15s ease;
|
||||
margin-right: 1em;
|
||||
display: inline-block;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
background-color: var(--theme-color, $color-primary);
|
||||
color: #fff;
|
||||
margin-right: 0;
|
||||
|
||||
&:hover {
|
||||
opacity: .8;
|
||||
color: inherit;
|
||||
opacity: .8;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,4 +100,13 @@ section.cover {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote > p > a {
|
||||
border-bottom: 2px solid var(--theme-color, $color-primary);
|
||||
transition: color .3s;
|
||||
|
||||
&:hover {
|
||||
color: var(--theme-color, $color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
-webkit-text-size-adjust: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body:not(.ready) {
|
||||
overflow: hidden;
|
||||
|
||||
[data-cloak], nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
div#app {
|
||||
font-size: 30px;
|
||||
font-weight: lighter;
|
||||
margin: 40vh auto;
|
||||
text-align: center;
|
||||
|
||||
&:empty::before {
|
||||
content: "Loading...";
|
||||
}
|
||||
}
|
||||
|
||||
.emoji {
|
||||
@@ -40,12 +59,12 @@ html, body {
|
||||
body {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
color: $color-text;
|
||||
font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
|
||||
font-size: 15px;
|
||||
letter-spacing: 0;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
color: $color-text;
|
||||
}
|
||||
|
||||
img {
|
||||
@@ -53,24 +72,24 @@ img {
|
||||
}
|
||||
|
||||
kbd {
|
||||
display: inline-block;
|
||||
padding: 3px 5px;
|
||||
margin-bottom : 3px;
|
||||
font-size: 12px !important;
|
||||
line-height: 12px;
|
||||
vertical-align: middle;
|
||||
border: solid 1px #ccc;
|
||||
border-radius: 3px;
|
||||
display: inline-block;
|
||||
font-size: 12px !important;
|
||||
line-height: 12px;
|
||||
margin-bottom : 3px;
|
||||
padding: 3px 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* navbar */
|
||||
nav {
|
||||
nav.app-nav {
|
||||
left: 0;
|
||||
margin: 25px 60px 0 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
margin: 25px 60px 0 0;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
|
||||
&.no-badge {
|
||||
margin-right: 25px;
|
||||
@@ -86,15 +105,15 @@ nav {
|
||||
}
|
||||
|
||||
ul, li {
|
||||
list-style: none;
|
||||
display: inline-block;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
font-size: 16px;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: color .3s;
|
||||
|
||||
&:hover {
|
||||
@@ -102,41 +121,41 @@ nav {
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: var(--theme-color, $color-primary);
|
||||
border-bottom: 2px solid var(--theme-color, $color-primary);
|
||||
color: var(--theme-color, $color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
/* navbar dropdown */
|
||||
li {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin: 0 1em;
|
||||
padding: 5px 0;
|
||||
position: relative;
|
||||
|
||||
ul {
|
||||
display: none;
|
||||
box-sizing: border-box;
|
||||
max-height: calc(100vh - 61px);
|
||||
overflow-y: scroll;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: -15px;
|
||||
background-color: #fff;
|
||||
padding: 10px 0;
|
||||
border: 1px solid #ddd;
|
||||
border-bottom-color: #ccc;
|
||||
text-align: left;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
display: none;
|
||||
max-height: calc(100vh - 61px);
|
||||
overflow-y: scroll;
|
||||
padding: 10px 0;
|
||||
position: absolute;
|
||||
right: -15px;
|
||||
text-align: left;
|
||||
top: 100%;
|
||||
white-space: nowrap;
|
||||
|
||||
li {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
line-height: 1em;
|
||||
margin: 0;
|
||||
margin: 8px 14px;
|
||||
white-space: nowrap;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -159,12 +178,12 @@ nav {
|
||||
|
||||
/* github corner */
|
||||
.github-corner {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
text-decoration: none;
|
||||
border-bottom: 0;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
text-decoration: none;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
|
||||
&:hover .octo-arm {
|
||||
animation:octocat-wave 560ms ease-in-out;
|
||||
@@ -172,23 +191,23 @@ nav {
|
||||
|
||||
svg {
|
||||
color: $color-bg;
|
||||
fill: var(--theme-color, $color-primary);
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
fill: var(--theme-color, $color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
/* main */
|
||||
main {
|
||||
display: block;
|
||||
size: 100vw 100%;
|
||||
position: relative;
|
||||
size: 100vw 100%;
|
||||
}
|
||||
|
||||
.anchor {
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
transition: all .3s;
|
||||
display: inline-block;
|
||||
|
||||
span {
|
||||
color: $color-text;
|
||||
@@ -201,19 +220,19 @@ main {
|
||||
|
||||
/* sidebar */
|
||||
.sidebar {
|
||||
border-right: 1px solid rgba(0, 0, 0, .07);
|
||||
overflow-y: auto;
|
||||
padding: 40px 0;
|
||||
position: absolute 0 * 0 0;
|
||||
transition: transform 250ms ease-out;
|
||||
width: $sidebar-width;
|
||||
z-index: 20;
|
||||
border-right: 1px solid rgba(0, 0, 0, .07);
|
||||
|
||||
> h1 {
|
||||
text-align: center;
|
||||
margin: 0 auto 1em;
|
||||
font-size: 1.5em;
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
@@ -236,8 +255,8 @@ main {
|
||||
}
|
||||
|
||||
ul li a {
|
||||
display: block;
|
||||
border-bottom: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
ul li ul {
|
||||
@@ -265,17 +284,17 @@ main {
|
||||
/* sidebar toggle */
|
||||
.sidebar-toggle {
|
||||
background-color: transparent;
|
||||
background-color: rgba($color-bg, .8);
|
||||
border: 0;
|
||||
outline: none;
|
||||
outline: none;
|
||||
padding: 10px;
|
||||
position: absolute * * 0 0;
|
||||
text-align: center;
|
||||
transition: opacity .3s;
|
||||
width: 30px;
|
||||
z-index: 30;
|
||||
outline: none;
|
||||
width: calc($sidebar-width - 16px);
|
||||
padding: 10px;
|
||||
background-color: rgba($color-bg, .8);
|
||||
z-index: 30;
|
||||
|
||||
.sidebar-toggle-button:hover {
|
||||
opacity: .4;
|
||||
@@ -284,8 +303,8 @@ main {
|
||||
span {
|
||||
background-color: var(--theme-color, $color-primary);
|
||||
display: block;
|
||||
size: 16px 2px;
|
||||
margin-bottom: 4px;
|
||||
size: 16px 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,17 +316,17 @@ body.sticky {
|
||||
|
||||
/* main content */
|
||||
.content {
|
||||
position: absolute 0 0 0 $sidebar-width;
|
||||
padding-top: 20px;
|
||||
position: absolute 0 0 0 $sidebar-width;
|
||||
transition: left 250ms ease;
|
||||
}
|
||||
|
||||
/* markdown content found on pages */
|
||||
.markdown-section {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
max-width: 800px;
|
||||
padding: 20px 15px 40px 15px;
|
||||
position: relative;
|
||||
|
||||
> * {
|
||||
box-sizing: border-box;
|
||||
@@ -321,28 +340,28 @@ body.sticky {
|
||||
|
||||
.markdown-section hr {
|
||||
border: none;
|
||||
margin: 2em 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin: 2em 0;
|
||||
}
|
||||
|
||||
.markdown-section table {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
display: block;
|
||||
margin-bottom: 1em;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.markdown-section th {
|
||||
border: 1px solid #ddd;
|
||||
font-weight: bold;
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.markdown-section td {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #ddd;
|
||||
padding: 6px 13px;
|
||||
}
|
||||
|
||||
.markdown-section tr {
|
||||
@@ -353,28 +372,28 @@ body.sticky {
|
||||
}
|
||||
|
||||
.markdown-section p.tip {
|
||||
padding: 12px 24px 12px 30px;
|
||||
margin: 2em 0;
|
||||
border-left: 4px solid #f66;
|
||||
background-color: #f8f8f8;
|
||||
position: relative;
|
||||
border-bottom-right-radius: 2px;
|
||||
border-left: 4px solid #f66;
|
||||
border-top-right-radius: 2px;
|
||||
margin: 2em 0;
|
||||
padding: 12px 24px 12px 30px;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
left: -12px;
|
||||
background-color: #f66;
|
||||
border-radius: 100%;
|
||||
color: $color-bg;
|
||||
content: "!";
|
||||
size: 20px;
|
||||
border-radius: 100%;
|
||||
text-align: center;
|
||||
line-height: 20px;
|
||||
font-weight: bold;
|
||||
font-family: 'Dosis', 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
left: -12px;
|
||||
line-height: 20px;
|
||||
position: absolute;
|
||||
size: 20px;
|
||||
text-align: center;
|
||||
top: 14px;
|
||||
}
|
||||
|
||||
code {
|
||||
@@ -387,9 +406,9 @@ body.sticky {
|
||||
}
|
||||
|
||||
.markdown-section p.warn {
|
||||
padding: 1em;
|
||||
background: rgba($color-primary, 0.1);
|
||||
border-radius: 2px;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
body.close {
|
||||
@@ -441,8 +460,8 @@ body.close {
|
||||
}
|
||||
|
||||
.sidebar-toggle {
|
||||
width: auto;
|
||||
background-color: transparent;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
body.close {
|
||||
@@ -451,9 +470,9 @@ body.close {
|
||||
}
|
||||
|
||||
.sidebar-toggle {
|
||||
width: calc($sidebar-width - 16px);
|
||||
background-color: rgba($color-bg, .8);
|
||||
transition: 1s background-color;
|
||||
width: calc($sidebar-width - 16px);
|
||||
}
|
||||
|
||||
.content {
|
||||
|
||||
+26
-27
@@ -20,8 +20,8 @@ $sidebar-width: 16em;
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
padding: 0.2em 0 0.2em 1em;
|
||||
margin: 0;
|
||||
padding: 0.2em 0 0.2em 1em;
|
||||
}
|
||||
|
||||
ul li ul {
|
||||
@@ -29,11 +29,11 @@ $sidebar-width: 16em;
|
||||
}
|
||||
|
||||
li.active {
|
||||
background-color: #eee;
|
||||
|
||||
a {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,8 +42,8 @@ $sidebar-width: 16em;
|
||||
.markdown-section h3,
|
||||
.markdown-section h4,
|
||||
.markdown-section strong {
|
||||
font-weight: 400;
|
||||
color: #333;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.markdown-section a {
|
||||
@@ -54,30 +54,29 @@ $sidebar-width: 16em;
|
||||
.markdown-section p,
|
||||
.markdown-section ul,
|
||||
.markdown-section ol {
|
||||
word-spacing: 0.05em;
|
||||
line-height: 1.6em;
|
||||
margin: 0 0 1em 0;
|
||||
word-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.markdown-section h1 {
|
||||
margin: 0 0 1em;
|
||||
font-size: 2em;
|
||||
font-weight: 500;
|
||||
margin: 0 0 1em;
|
||||
}
|
||||
|
||||
.markdown-section h2 {
|
||||
padding: 1rem 0 0 0;
|
||||
margin: 0 0 1rem 0;
|
||||
font-size: 1.8em;
|
||||
font-weight: 400;
|
||||
margin: 0 0 1rem 0;
|
||||
padding: 1rem 0 0 0;
|
||||
}
|
||||
|
||||
.markdown-section h3 {
|
||||
margin: 52px 0 1.2em;
|
||||
font-size: 1.5em;
|
||||
margin: 52px 0 1.2em;
|
||||
}
|
||||
|
||||
|
||||
.markdown-section h4 {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
@@ -87,8 +86,8 @@ $sidebar-width: 16em;
|
||||
}
|
||||
|
||||
.markdown-section h6 {
|
||||
font-size: 1em;
|
||||
color: #777;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.markdown-section figure,
|
||||
@@ -104,13 +103,13 @@ $sidebar-width: 16em;
|
||||
}
|
||||
|
||||
.markdown-section li {
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.markdown-section blockquote {
|
||||
color: #858585;
|
||||
border-left: 4px solid var(--theme-color, $color-primary);
|
||||
color: #858585;
|
||||
margin: 2em 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
@@ -130,29 +129,29 @@ $sidebar-width: 16em;
|
||||
|
||||
.markdown-section code {
|
||||
background-color: #f9f9f9;
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 3px;
|
||||
white-space: pre;
|
||||
font-family: Inconsolata;
|
||||
padding: 0.2em 0.4em;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.markdown-section pre {
|
||||
background-color: #f9f9f9;
|
||||
border-left: 2px solid #eee;
|
||||
padding: 8px;
|
||||
margin: 0 0 1em 0;
|
||||
font-family: Inconsolata;
|
||||
padding: 0 10px 12px 0;
|
||||
font-size: 16px;
|
||||
margin: 0 0 1em 0;
|
||||
padding: 8px;
|
||||
padding: 0 10px 12px 0;
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
/* code highlight */
|
||||
.token.cdata,
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
.token.prolog {
|
||||
color: #93a1a1; /* base1 */
|
||||
}
|
||||
|
||||
@@ -218,15 +217,15 @@ $sidebar-width: 16em;
|
||||
}
|
||||
|
||||
.markdown-section pre>code {
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 2px;
|
||||
display: block;
|
||||
font-family: Inconsolata;
|
||||
overflow: inherit;
|
||||
max-width: inherit;
|
||||
position: relative;
|
||||
background-color: #f8f8f8;
|
||||
padding: 20px 0.8em 20px;
|
||||
line-height: 1.1em;
|
||||
border-radius: 2px;
|
||||
max-width: inherit;
|
||||
overflow: inherit;
|
||||
padding: 20px 0.8em 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.markdown-section code::after, .markdown-section code::before {
|
||||
@@ -234,7 +233,7 @@ $sidebar-width: 16em;
|
||||
}
|
||||
|
||||
code .token {
|
||||
min-height: 1.5em;
|
||||
-webkit-font-smoothing: initial;
|
||||
-moz-osx-font-smoothing: initial;
|
||||
min-height: 1.5em;
|
||||
}
|
||||
|
||||
+18
-18
@@ -14,8 +14,8 @@ body {
|
||||
|
||||
/* sidebar */
|
||||
.sidebar {
|
||||
color: #c8c8c8;
|
||||
background-color: $color-bg;
|
||||
color: #c8c8c8;
|
||||
|
||||
li {
|
||||
margin: 6px 15px;
|
||||
@@ -23,11 +23,11 @@ body {
|
||||
|
||||
ul li a {
|
||||
color: #c8c8c8;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
@@ -50,8 +50,8 @@ body {
|
||||
.markdown-section h3,
|
||||
.markdown-section h4,
|
||||
.markdown-section strong {
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown-section a {
|
||||
@@ -60,8 +60,8 @@ body {
|
||||
}
|
||||
|
||||
.markdown-section h1 {
|
||||
margin: 0 0 1em;
|
||||
font-size: 2em;
|
||||
margin: 0 0 1em;
|
||||
}
|
||||
|
||||
.markdown-section h2 {
|
||||
@@ -70,8 +70,8 @@ body {
|
||||
}
|
||||
|
||||
.markdown-section h3 {
|
||||
margin: 40px 0 .6em;
|
||||
font-size: 1.5em;
|
||||
margin: 40px 0 .6em;
|
||||
}
|
||||
|
||||
.markdown-section h4 {
|
||||
@@ -83,8 +83,8 @@ body {
|
||||
}
|
||||
|
||||
.markdown-section h6 {
|
||||
font-size: 1em;
|
||||
color: #777;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.markdown-section figure,
|
||||
@@ -107,8 +107,8 @@ body {
|
||||
}
|
||||
|
||||
.markdown-section blockquote {
|
||||
color: #858585;
|
||||
border-left: 4px solid var(--theme-color, $color-primary);
|
||||
color: #858585;
|
||||
margin: 2em 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
@@ -127,14 +127,14 @@ body {
|
||||
}
|
||||
|
||||
.markdown-section code {
|
||||
background-color: #282828;
|
||||
border-radius: 2px;
|
||||
color: #657b83;
|
||||
font-family: 'Roboto Mono', Monaco, courier, monospace;
|
||||
font-size: 0.8em;
|
||||
margin: 0 2px;
|
||||
padding: 3px 5px;
|
||||
white-space: nowrap;
|
||||
font-size: 0.8em;
|
||||
font-family: 'Roboto Mono', Monaco, courier, monospace;
|
||||
background-color: #282828;
|
||||
}
|
||||
|
||||
.markdown-section pre {
|
||||
@@ -144,9 +144,9 @@ body {
|
||||
font-family: 'Roboto Mono', Monaco, courier, monospace;
|
||||
line-height: 1.5em;
|
||||
margin: 1.2em 0;
|
||||
overflow: auto;
|
||||
padding: 0 1.4em;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
@@ -257,10 +257,10 @@ body {
|
||||
font-size: 0.8em;
|
||||
line-height: inherit;
|
||||
margin: 0 2px;
|
||||
max-width: inherit;
|
||||
overflow: inherit;
|
||||
padding: 2.2em 5px;
|
||||
white-space: inherit;
|
||||
max-width: inherit;
|
||||
}
|
||||
|
||||
.markdown-section code::after, .markdown-section code::before {
|
||||
@@ -268,9 +268,9 @@ body {
|
||||
}
|
||||
|
||||
code .token {
|
||||
min-height: 1.5em;
|
||||
-webkit-font-smoothing: initial;
|
||||
-moz-osx-font-smoothing: initial;
|
||||
-webkit-font-smoothing: initial;
|
||||
min-height: 1.5em;
|
||||
}
|
||||
|
||||
pre::after {
|
||||
@@ -293,7 +293,7 @@ pre::after {
|
||||
}
|
||||
|
||||
input[type="search"] {
|
||||
border-color: #4f4f4f;
|
||||
background: #4f4f4f;
|
||||
border-color: #4f4f4f;
|
||||
color: #c8c8c8;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user