diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
new file mode 100644
index 000000000..ad6203270
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -0,0 +1,53 @@
+name: 🛠æäº¤ Bug
+description: 请æäº¤ä½ çš„ Bug
+body:
+ - type: markdown
+ attributes:
+ value: |
+ 谢谢帮忙æäº¤ Bug 这会让简悦å˜å¾—更好。
+ - type: textarea
+ id: what-happened
+ attributes:
+ label: æè¿°è¿™ä¸ªé”™è¯¯
+ description: 请尽é‡è¯¦ç»†æè¿°ä½ 的错误
+ validations:
+ required: true
+ - type: textarea
+ id: repro-steps
+ attributes:
+ label: å¤çްæ¥éª¤
+ description: 请尽é‡ç”¨æ¸…æ™°çš„æ¥éª¤ï¼ˆå“ªæ€•比较多)的æè¿°ä½ 的问题,最好å¯ä»¥çš„è¯ï¼Œè¯·æˆªå›¾æˆ–者视频说明。
+ placeholder: |
+ 1. æ¥éª¤1
+ 2. æ¥éª¤2
+ 3. æ¥éª¤3
+ validations:
+ required: true
+ - type: textarea
+ id: others
+ attributes:
+ label: 其他相关说明
+ description: 如果有需è¦ï¼Œå¯ä»¥åœ¨è¿™é‡Œç»§ç»è¯´æ˜Ž
+ validations:
+ required: false
+ - type: input
+ id: os
+ attributes:
+ label: æ“作系统
+ placeholder: macOS
+ validations:
+ required: true
+ - type: input
+ id: browser
+ attributes:
+ label: æµè§ˆå™¨
+ placeholder: 请说明æµè§ˆå™¨ä»¥åŠå°½é‡è¯´æ˜Žæµè§ˆå™¨ç‰ˆæœ¬
+ validations:
+ required: true
+ - type: input
+ id: website
+ attributes:
+ label: å‘生问题的网å€
+ placeholder: 如果任æ„网站å‡å¯çš„è¯ï¼Œè¯·éšä¾¿ç•™ä¸‹ä¸€ä¸ªä½ é‡åˆ°é—®é¢˜çš„地å€
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 000000000..62f9bcd32
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,68 @@
+blank_issues_enabled: false
+contact_links:
+ - name: 🆘 当å‡çº§ Chrome åŽæ— 法使用简悦的解决方案
+ url: https://www.yuque.com/kenshin/simpread/fxszlhpp1iht441s
+ about: |
+ 当 Chrome 应用商店æç¤ºã€æ¤æ‰©å±•ç¨‹åºæœªéµå¾ª Chrome 扩展程åºçš„æœ€ä½³å®žè·µï¼Œå› æ¤å·²æ— 法å†ä½¿ç”¨ã€‘的解决方案
+ - name: 📮 订阅ä¸å¿ƒ
+ url: https://simpread.pro/subscribe
+ about: |
+ 我æ¯å‘¨éƒ½ä¼šæŽ¨ 3 ~ 4 篇关于简悦的新功能ã€è”动ç‰å†…容,建议简悦用户(尤其是ç»å¸¸ä½¿ç”¨ç®€æ‚¦é«˜çº§åŠŸèƒ½çš„ç”¨æˆ·ï¼‰è®¢é˜…ã€å‘布汇总】。
+ - name: 📚 简悦手册
+ url: https://www.yuque.com/kenshin/simpread/
+ about: |
+ 简悦的阅读模å¼ç›¸å…³åŠŸèƒ½æ˜¯ä¸éœ€è¦è®¾ç½®çš„。
+ å¦‚æžœä½ ä½¿ç”¨äº†æ›´é«˜çº§çš„åŠŸèƒ½ï¼Œå¦‚ï¼šåŒæ¥åŠ©æ‰‹ï¼Œæˆ–è€…ä½ æ˜¯ Obsidian / Logseq ç‰åŒé“¾ç¬”è®°ç”¨æˆ·ï¼Œæˆ–è€…ä½ æœ¬åœ°å¿«ç…§ç‰åŠŸèƒ½çš„è¯ï¼Œåˆ™éœ€è¦é…置。
+ 简悦官方已ç»å‡†å¤‡å¥½äº†ç›¸å…³çš„æ•™ç¨‹ã€‚
+ - name: 📦 é…置库(强烈建议åŒé“¾ç¬”è®°ç”¨æˆ·ä½¿ç”¨æ¤æ–¹å¼ï¼‰
+ url: https://www.yuque.com/kenshin/simpread/ds8zk0
+ about: |
+ 这是简悦官方推出的å…é…置包方案,包括:Notion / Obsidian / Logseq ç‰ç”¨æ³•。
+ - name: 📗 Notion é…置库
+ url: https://www.yuque.com/kenshin/simpread/mwda8s
+ about: |
+ 通过简悦导入到 Notion 的内容包括:Notion 图床ã€é¢˜å›¾ã€Faviconã€æ ‡ç¾ç‰è¯¸å¤šåŠŸèƒ½ã€‚
+ - name: 📘 Obsidian é…置库
+ url: https://www.yuque.com/kenshin/simpread/psugef
+ about: |
+ 简悦与 Obsidian çš„è”动å¯ä»¥å°†ç®€æ‚¦çš„æ ‡æ³¨ç³»ç»Ÿå†…置到 Obsidian ä¸ã€‚
+ - name: 🖥 如何é…ç½®åŒæ¥åŠ©æ‰‹
+ url: https://www.yuque.com/kenshin/simpread/pwpnsx
+ about: |
+ åŒæ¥åŠ©æ‰‹ç›¸å½“äºŽä¸€ä¸ªåŸºäºŽç”¨æˆ·ç³»ç»Ÿçš„æœåŠ¡å™¨ï¼Œå¯ä»¥å®žçŽ°è¯¸å¤šé«˜çº§åŠŸèƒ½ï¼ˆå¦‚æžœä½ åªæ˜¯é˜…读模å¼ç”¨æˆ·ï¼Œä¸éœ€è¦è¿™äº›ï¼‰
+ - name: 💾 如何é…置本地快照系统
+ url: https://www.yuque.com/kenshin/simpread/wkswh7
+ about: |
+ ç®€æ‚¦æœ€å¤§çš„ä¼˜åŠ¿åœ¨äºŽï¼šç”¨æˆ·æ‹¥æœ‰å…¨éƒ¨çš„æ•°æ®æ‰€æœ‰æƒï¼Œåªéœ€è¦ç®€å•çš„å‡ æ¥å°±èƒ½å®žçŽ°ä¸€ä¸ªåŸºäºŽæœ¬åœ°çš„å¿«ç…§ç³»ç»Ÿã€‚
+ - name: 📓 ä¸€ç«™å¼æ•™ç¨‹
+ url: https://www.yuque.com/kenshin/simpread/pn4bbg
+ about: |
+ 如果ä¸éœ€è¦é…置库方案的è¯ï¼Œä¹Ÿå¯ä»¥ç›´æŽ¥æŸ¥çœ‹ Notion / Obsidian / Logseq çš„ä¸€ç«™å¼æ•™ç¨‹ï¼Œé€‚åˆå–œæ¬¢æ›´çµæ´»æ–¹æ¡ˆçš„用户。
+ - name: 👤 高级账户相关功能
+ url: https://www.yuque.com/kenshin/simpread/xs0gp0
+ about: |
+ 这是简悦的高级账户相关æ“ä½œï¼ŒåŸºæœ¬ä¸Šä½ å‡ºçŽ°çš„é—®é¢˜å¤§éƒ¨åˆ†éƒ½å¯ä»¥é€šè¿‡æ¤æ–¹å¼è§£å†³ã€‚
+ - name: 🔒 首次绑定高级账户ä»å‡ºçŽ°å¸¦ðŸ”’çš„é—®é¢˜
+ url: https://www.yuque.com/kenshin/simpread/xs0gp0
+ about: |
+ 首次å‡çº§ä¸ºé«˜çº§è´¦æˆ·åŽï¼Œè¯·é‡å¯æµè§ˆå™¨ï¼Œå¦‚果没有é‡å¯çš„è¯ï¼Œè¯·ä½¿ç”¨æ¤é“¾æŽ¥è§£å†³ã€‚
+ - name: 1ï¸âƒ£ 如何找回丢失的 UID ï¼ˆé«˜çº§è´¦æˆ·èµ„æ ¼ï¼‰
+ url: https://www.yuque.com/kenshin/simpread/bvcunx
+ about: |
+ 如果ä¸å°å¿ƒä¸¢å¤±äº† UID è¯·é€šè¿‡æ¤æ•™ç¨‹æ‰¾å›žã€‚
+ - name: 2ï¸âƒ£ 找回 UID åŽå¦‚何æ¢å¤é«˜çº§è´¦æˆ·èµ„æ ¼
+ url: https://www.yuque.com/kenshin/simpread/pkq3d1
+ about: |
+ 找回 UID åŽå¯ä½¿ç”¨æ¤æ•™ç¨‹æ¢å¤ä½ çš„é«˜çº§è´¦æˆ·èµ„æ ¼ã€‚
+ - name: 3ï¸âƒ£ 在哪里å¯ä»¥é‡æ–°æ‰¾åˆ° License(兑æ¢ç )
+ url: https://www.yuque.com/kenshin/simpread/hgvw56
+ about: |
+ 找回 UID å‰éœ€è¦çŸ¥é“ä½ çš„ License,一般æ¥è¯´å½“å‡çº§é«˜çº§è´¦æˆ·åŽä¼šè‡ªåŠ¨ä¸‹è½½å«æœ‰é«˜çº§è´¦æˆ· UID 与 License 到本地。
+ - name: 📗 Notion 相关问题
+ url: https://www.yuque.com/kenshin/simpread/wwk65u
+ about: |
+ å¦‚ï¼šæ— æ³•æŽˆæƒåˆ° Notion,使用导入到 Notion 辅助增强æ’件失败ç‰å¸¸è§„性问题。
+ - name: 🆘 æ— æ³•æ‰“å¼€ç®€æ‚¦çš„é€‰é¡¹é¡µæˆ–ç¨åŽè¯»
+ url: https://www.yuque.com/kenshin/simpread/lwuterg3u83sq0b2
+ about: |
+ 如:一般æ¥è¯´åªæœ‰ä½¿ç”¨äº†åŒæ¥åŠ©æ‰‹åŽæ‰ä¼šé‡åˆ°æ¤ç±»é—®é¢˜ï¼Œå¯é€šè¿‡æ¤é“¾æŽ¥è§£å†³ã€‚
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 000000000..0b9f04e6e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,19 @@
+name: ✨ 功能建议或改善
+description: ä½ çš„å»ºè®®ä¼šè®©ç®€æ‚¦å˜å¾—更好
+body:
+ - type: markdown
+ attributes:
+ value: |
+ ä½ çš„æ¯ä¸ªæƒ³æ³•都是对简悦最大的支æŒï¼Œç®€æ‚¦ 60% 的功能都æ¥è‡ªç”¨æˆ·çš„简悦。
+ - type: textarea
+ id: feature
+ attributes:
+ label: 请æè¿°ä½ 的建议或任何内容
+ description: 如有å¯èƒ½è¯·è¯¦ç»†è¯´æ˜Žå®ƒ
+ validations:
+ required: true
+ - type: textarea
+ id: context
+ attributes:
+ label: 补充说明
+ description: 如有å¯èƒ½è¯·è¯´æ˜Žä¸‹è¿™ä¸ªå»ºè®®å…·ä½“使用场景(或如果有这个功能åŽï¼Œä¼šæ”¹å–„ä½ çš„ä»€ä¹ˆæµç¨‹ï¼Ÿ
diff --git a/.github/ISSUE_TEMPLATE/new_site.yml b/.github/ISSUE_TEMPLATE/new_site.yml
new file mode 100644
index 000000000..700ab7bc4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/new_site.yml
@@ -0,0 +1,22 @@
+name: 🔗 新站适é…
+description: æäº¤éœ€è¦é€‚é…的站点
+labels: ["new site"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ 大部分网页都å¯ä»¥æ£å¸¸ä½¿ç”¨ç®€æ‚¦çš„阅读模å¼ï¼Œç®€æ‚¦å®˜æ–¹æ”¶å½•的新站具有大众类型的网站。
+ - type: textarea
+ id: website
+ attributes:
+ label: 需è¦é€‚é…的新站
+ placeholder: 请输入这个站点的 URL,如果这个站的规则比较多,请多帮忙æä¾›ä¸€äº› URL 作为å‚考
+ validations:
+ required: true
+ - type: textarea
+ id: what-happened
+ attributes:
+ label: 有需è¦è¯·æè¿°è¿™ä¸ªç«™çš„æ€§è´¨
+ description: 尤其是英文类型的网站,我需è¦åˆ¤æ–这个站是å¦å…·æœ‰é€‚é…的必è¦ã€‚
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/yinxiang_code.yml b/.github/ISSUE_TEMPLATE/yinxiang_code.yml
new file mode 100644
index 000000000..7aa5ec668
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/yinxiang_code.yml
@@ -0,0 +1,22 @@
+name: 🚑 å°è±¡ç¬”记或代ç 高亮问题
+description: 关于å°è±¡ç¬”记或代ç 高亮的集ä¸åé¦ˆæ¸ é“
+body:
+ - type: markdown
+ attributes:
+ value: |
+ 谢谢帮忙æäº¤ Bug 这会让简悦å˜å¾—更好。
+ - type: dropdown
+ id: browsers
+ attributes:
+ label: 请选择
+ multiple: false
+ options:
+ - å°è±¡ç¬”è®°
+ - 代ç 高亮
+ - type: input
+ id: website
+ attributes:
+ label: å‘生问题的网å€
+ placeholder: 如果任æ„网站å‡å¯çš„è¯ï¼Œè¯·éšä¾¿ç•™ä¸‹ä¸€ä¸ªä½ é‡åˆ°é—®é¢˜çš„地å€
+ validations:
+ required: true
diff --git a/.gitignore b/.gitignore
index eb1c3f38e..1758fbaff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
# for common
node_modules/**
publish/**
+.vscode/**
# for chrome
src/bundle/**
diff --git a/LICENSE b/LICENSE
index 3b3e49cb8..a662e6ee5 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,674 @@
-MIT License
-
-Copyright (c) 2016 kenshin
-
-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.
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.


è®©ä½ çž¬é—´è¿›å…¥æ²‰æµ¸å¼é˜…读的扩展,还原阅读的本质,æå‡ä½ 的阅读体验。
-为了达到完美的阅读模å¼è¿™ä¸ªå°ç›®æ ‡ ,我适é…了 数百ç§ç±»åž‹ çš„ç½‘ç«™ï¼Œå› æ¤è¯žç”Ÿäº†ç®€æ‚¦ã€‚
+为了达到完美的阅读模å¼è¿™ä¸ªå°ç›®æ ‡ ,我适é…了 数百ç§ç±»åž‹ çš„ç½‘ç«™ï¼Œå› æ¤è¯žç”Ÿäº†ç®€æ‚¦ã€‚
+
-- 多ç§ä¸»é¢˜ï¼š
- `白练ã€ç™½ç£ã€å¯ä¹‹èŠ±è‰²ã€ä¸å色ã€å¨Ÿé¼ ã€æœˆç™½ã€ç™¾åˆã€ç´ºé¼ ã€é»’鸢` ç‰
+> 在 1.0.0 版上线之åˆå°±å·²ç»æž„想了æ¤åŠŸèƒ½ï¼Œæ‰€ä»¥åœ¨æž„ç‘æ¤åŠŸèƒ½æ—¶ï¼ŒåŠ å…¥äº†å¾ˆå¤šåªæœ‰ **简悦 · æ ‡æ³¨** æ‰å…·æœ‰çš„功能。
-- 丰富的导出功能,包括:
+- äº”ç§æ ‡æ³¨é¢œè‰²
- - 导出 [Markdown](https://github.com/Kenshin/simpread#感谢) · `HTML` · `PNG` · `PDF` · [epub](https://github.com/Kenshin/simpread/wiki/å‘é€åˆ°-epub)
+- å››ç§æ ‡æ³¨æ ·å¼
- - å‘é€é˜…读模å¼ä¼˜åŒ–åŽçš„页é¢åˆ° `Kindle`,详细é…ç½® [请看这里](https://github.com/Kenshin/simpread/wiki/å‘é€åˆ°-Kindle)
+- 自动识别 **æ–‡å—** · **图片** · **ä»£ç æ®µ**
- - 导出到 `Pocket` `Linnk` `Instapaper` 的功能,包括:`当å‰é¡µé¢çš„链接` `ç¨åŽè¯»`
+- **æ— é™å±‚级** çš„æ ‡ç¾ç³»ç»Ÿ
- - 导出到生产力工具,包括:`Dropbox` `Onenote` `Google Drive` `å°è±¡ç¬”è®° / Evernote`,详细请看 [æŽˆæƒæœåŠ¡](https://github.com/Kenshin/simpread/wiki/æŽˆæƒæœåŠ¡)
+- æ¯ä¸ªæ ‡ç¾å‡æ”¯æŒå¤‡æ³¨ä¸Žæ ‡ç¾ç³»ç»Ÿ
-- åŒæ¥ · ä¸Šä¼ /下载 é…ç½® · åŒæ¥é€‚é…列表 · [å¿«æ·é”®æ”¯æŒ](https://github.com/kenshin/simpread/wiki/å¿«æ·é”®) ç‰ï¼›
+- 结åˆç®€æ‚¦å¼ºå¤§çš„å‘é€åˆ°ç”Ÿäº§åŠ›å·¥å…·çš„åŠŸèƒ½ï¼Œå¯å°†å½“剿 ‡æ³¨å‘é€åˆ°ç®€æ‚¦æ”¯æŒçš„å„ç§ç”Ÿäº§åЛ工具
-- 高级定制,包括:`å³é”®èœå•` `控制æ å¯éšè—` `阅读进度å¯éšè—` `自动进入阅读模å¼` [白åå•](https://github.com/kenshin/simpread/wiki/faq#白åå•) ä»¥åŠ [排除列表](https://github.com/kenshin/simpread/wiki/faq#排除列表) ç‰
+- è¿žç»æ ‡æ³¨
-- ç¨åŽè¯»
+- [æµ®åŠ¨æ ‡æ³¨æ ](http://ksria.com/simpread/docs/#/æ ‡æ³¨?id=浮动工具æ )
-#### 截图:
-
-
-
+- [æ ‡æ³¨ä¾§æ ](http://ksria.com/simpread/docs/#/æ ‡æ³¨?id=æ ‡æ³¨ä¾§æ )
-#### 照片集:
-> 包å«äº† `ç¨åŽè¯»` `é˜…è¯»æ¨¡å¼ Â· 设置界é¢` `导出到生产力工具` `å‘é€åˆ° Kindle` `è‡ªå®šä¹‰æ ·å¼` `åŒæ¥é…ç½®` `论å›ç±»é¡µé¢ · 分页` ç‰åŠŸèƒ½çš„æˆªå›¾ï¼ˆåŠ¨å›¾ï¼‰
+> 如何使用以åŠè¯¦ç»†å†…容 [请看这里](http://ksria.com/simpread/docs/#/æ ‡æ³¨)
-*
-`简悦`会自动检测当å‰é¡µé¢æ˜¯å¦å·²ç»é€‚é…,如适é…则在æµè§ˆå™¨å³ä¸Šè§’显示  ï¼Œä½¿ç”¨ä»¥ä¸‹ä¸‰ç§æ–¹å¼å¯åŠ¨ï¼š
+> 简悦的ç¨åŽè¯»å€Ÿé‰´äº† ZK 笔记法的一些特点,专门针对信æ¯çš„æ•´åˆå¢žåŠ äº†å¦‚ä¸‹ä¸€äº›æ–°åŠŸèƒ½ï¼š
+
+- [**åŒå‘链接**](http://ksria.com/simpread/docs/#/åŒå‘链接)
+- [**知识图谱**](http://ksria.com/simpread/docs/#/åŒå‘链接?id=图谱)
+- [**Mindmap**](http://ksria.com/simpread/docs/#/ç¨åŽè¯»?id=Mindmap)
+- **多ç§ä¿¡æ¯å±•示方å¼ï¼ˆå¸ƒå±€ï¼‰**:[Evergreen](http://ksria.com/simpread/docs/#/ç¨åŽè¯»-多ç§å¸ƒå±€?id=Evergreen) · [Workflowy](http://ksria.com/simpread/docs/#/ç¨åŽè¯»-多ç§å¸ƒå±€?id=Workflowy) · [Kanban](http://ksria.com/simpread/docs/#/ç¨åŽè¯»-多ç§å¸ƒå±€?id=Kanban)
+- [**è¯»å–æœ¬åœ° HTML**](https://github.com/Kenshin/simpread/discussions/2146)
+
+
+
+
+
+#### åŒæ¥åŠ©æ‰‹  
+
+
+
+> [简悦 · åŒæ¥åŠ©æ‰‹](http://ksria.com/simpread/docs/#/Sync) 是 **éšç€ç®€æ‚¦ 2.1.0 å‘布的一个全新的 Desktop App**,用于对简悦已知功能的补充,以åŠä¼š **æŒç»æä¾›æ›´å¤š** çš„å¯çŽ©æ€§ï¼ŒåŒ…æ‹¬ï¼š
+
+1. **[è‡ªåŠ¨åŒæ¥](http://ksria.com/simpread/docs/#/è‡ªåŠ¨åŒæ¥)**
+2. **å°ä¹¦ç¾**
+3. 导出到文件 **本地的任æ„ä½ç½®**
+4. **原生 PDF · Epub** 导出
+5. **直接å‘é€åˆ°ä½ çš„ Kindle**
+6. 内置解æž
+7. **邮件å‘é€**
+
+åŒæ¥åŠ©æ‰‹çš„ Logo 自于社区用户 [Shawn](https://shawnan.design/) 的设计。
+
+#### æ’件系统 
+
+ > 使用 JavaScript 编写基于 `简悦` çš„æ’件了,请看 [æ’ä»¶ä¸å¿ƒ](https://simpread.ksria.cn/plugins/)
+
+## 全部功能
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+ å¤§å®¶å¥½ï¼Œæˆ‘å« Kenshin,简悦的作者。
å¯ç¼–程 支æŒï¼š {
"name" : "qdaily.com",
@@ -82,8 +82,9 @@ è¡¨æ ¼æ ·å¼ï¼š
å¦‚ä½•è‡ªå®šä¹‰æ ·å¼ï¼Œè¯¦ç»† 请看这里
+
å¦‚ä½•è‡ªå®šä¹‰æ ·å¼ï¼Œè¯¦ç»† 请看这里
独ä¹ä¹ä¸å¦‚ä¼—ä¹ä¹ï¼ åˆ†äº«ä½ çš„ä¸»é¢˜
本文由 简悦 SimpRead 转ç ï¼ŒåŽŸæ–‡åœ°å€ ${url}
本文由 简悦 SimpRead 转ç ${href}
/ig, "" ) //
||
||
- .replace( /
本文由 简悦 SimpRead 转ç ${href}
'+t.innerHTML+"")}),t&&e.find(".syntaxhighlighter").map(function(e,t){var r="";$(t).find(".container div").map(function(e,t){r+=t.innerText+"\n"}),$(t).replaceWith('
'+r+"")}),t&&e.find("table pre").length>0&&e.find("table").map(function(e,t){var r=$(t);if(2==r.find("pre").length){var a=r.find("td pre")[1].outerText.replace(//gi,">").trim();r.replaceWith('
'+a+"")}}),t&&e.find("pre:not(.sr-rd-content-nobeautify)").each(function(e,t){var r="",a=!1,n=!1;1==$(t).find("code").length&&$(t).find("li").length>0&&$(t).find("code").each(function(e,t){a=!0,n=!0,r+=t.outerText.replace(//gi,">")}),0==a&&0==n&&$(t).find("li").each(function(e,n){$(t).find("code").length>0&&(a=!0),""!=n.outerText.trim()&&(r+=n.outerText.replace(/\n/gi,"").replace(//gi,">")+"\n")}),0==a&&$(t).find("code").each(function(e,t){n=!0,""!=t.outerText.trim()&&(r+=t.outerText.replace(//gi,">")+"\n")}),a||n||(r=t.outerText.replace(//gi,">")+"\n"),$(t).removeAttr("style").removeAttr("class").removeAttr("id").html(r)});var a,n,i=e.html();"readability-page-1"==$(e.children()).attr("id")&&1==e.children().children().length?i=e.children().children().html():1==e.children().length&&(i=e.children().html()),i=i.replace(//gi,""),e.html((a=i,n="",$.parseHTML(a).forEach(function(e,a){var i=e.tagName,o=e.outerText,s=e.outerHTML;void 0==i?n+="
"+e.textContent.replace(//gi,">").replace(/^\n|\n$/gi,"").trim()+"
":"PRE"==i?n+=s:"sr-blocks"==i.toLowerCase()?n+=s:(""!=o||s.includes("[^\r]+?<\/pre>)/gm,function(e,t){var r=t;return(r=r.replace(/^ /gm,"¨0")).replace(/¨0/g,"")}),i.subParser("hashBlock")("\n"+e+"\n
",t,r)}),r.converter._dispatch("blockQuotes.after",e,t,r)}),i.subParser("codeBlocks",function(e,t,r){return e=r.converter._dispatch("codeBlocks.before",e,t,r),e=(e=(e+="¨0").replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=¨0))/g,function(e,a,n){var o=a,s=n,l="\n";return o=i.subParser("outdent")(o,t,r),o=i.subParser("encodeCode")(o,t,r),o=(o=(o=i.subParser("detab")(o,t,r)).replace(/^\n+/g,"")).replace(/\n+$/g,""),t.omitExtraWLInCodeBlocks&&(l=""),o=""+o+l+"
",i.subParser("hashBlock")(o,t,r)+s})).replace(/¨0/,""),r.converter._dispatch("codeBlocks.after",e,t,r)}),i.subParser("codeSpans",function(e,t,r){return void 0===(e=r.converter._dispatch("codeSpans.before",e,t,r))&&(e=""),e=e.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(e,a,n,o){var s=o;return s=(s=s.replace(/^([ \t]*)/g,"")).replace(/[ \t]*$/g,""),s=a+""+(s=i.subParser("encodeCode")(s,t,r))+"",i.subParser("hashHTMLSpans")(s,t,r)}),r.converter._dispatch("codeSpans.after",e,t,r)}),i.subParser("completeHTMLDocument",function(e,t,r){if(!t.completeHTMLDocument)return e;e=r.converter._dispatch("completeHTMLDocument.before",e,t,r);var a="html",n="\n",i="",o='\n',s="",l="";for(var c in void 0!==r.metadata.parsed.doctype&&(n="\n","html"!==(a=r.metadata.parsed.doctype.toString().toLowerCase())&&"html5"!==a||(o='')),r.metadata.parsed)if(r.metadata.parsed.hasOwnProperty(c))switch(c.toLowerCase()){case"doctype":break;case"title":i=""+r.metadata.parsed.title+" \n";break;case"charset":o="html"===a||"html5"===a?'\n':'\n';break;case"language":case"lang":s=' lang="'+r.metadata.parsed[c]+'"',l+='\n';break;default:l+='\n'}return e=n+"\n\n"+i+o+l+"\n\n"+e.trim()+"\n\n",r.converter._dispatch("completeHTMLDocument.after",e,t,r)}),i.subParser("detab",function(e,t,r){return e=(e=(e=(e=(e=(e=r.converter._dispatch("detab.before",e,t,r)).replace(/\t(?=\t)/g," ")).replace(/\t/g,"¨A¨B")).replace(/¨B(.+?)¨A/g,function(e,t){for(var r=t,a=4-r.length%4,n=0;n/g,">"),r.converter._dispatch("encodeAmpsAndAngles.after",e,t,r)}),i.subParser("encodeBackslashEscapes",function(e,t,r){return e=(e=(e=r.converter._dispatch("encodeBackslashEscapes.before",e,t,r)).replace(/\\(\\)/g,i.helper.escapeCharactersCallback)).replace(/\\([`*_{}\[\]()>#+.!~=|-])/g,i.helper.escapeCharactersCallback),r.converter._dispatch("encodeBackslashEscapes.after",e,t,r)}),i.subParser("encodeCode",function(e,t,r){return e=(e=r.converter._dispatch("encodeCode.before",e,t,r)).replace(/&/g,"&").replace(/"+o+s+"",o=i.subParser("hashBlock")(o,t,r),"\n\n¨G"+(r.ghCodeBlocks.push({text:e,codeblock:o})-1)+"G\n\n"})).replace(/¨0/,""),r.converter._dispatch("githubCodeBlocks.after",e,t,r)):e}),i.subParser("hashBlock",function(e,t,r){return e=(e=r.converter._dispatch("hashBlock.before",e,t,r)).replace(/(^\n+|\n+$)/g,""),e="\n\n¨K"+(r.gHtmlBlocks.push(e)-1)+"K\n\n",r.converter._dispatch("hashBlock.after",e,t,r)}),i.subParser("hashCodeTags",function(e,t,r){return e=r.converter._dispatch("hashCodeTags.before",e,t,r),e=i.helper.replaceRecursiveRegExp(e,function(e,a,n,o){var s=n+i.subParser("encodeCode")(a,t,r)+o;return"¨C"+(r.gHtmlSpans.push(s)-1)+"C"},"]*>","","gim"),r.converter._dispatch("hashCodeTags.after",e,t,r)}),i.subParser("hashElement",function(e,t,r){return function(e,t){var a=t;return a=(a=(a=a.replace(/\n\n/g,"\n")).replace(/^\n/,"")).replace(/\n+$/g,""),"\n\n¨K"+(r.gHtmlBlocks.push(a)-1)+"K\n\n"}}),i.subParser("hashHTMLBlocks",function(e,t,r){e=r.converter._dispatch("hashHTMLBlocks.before",e,t,r);var a=["pre","div","h1","h2","h3","h4","h5","h6","blockquote","table","dl","ol","ul","script","noscript","form","fieldset","iframe","math","style","section","header","footer","nav","article","aside","address","audio","canvas","figure","hgroup","output","video","p"],n=function(e,t,a,n){var i=e;return-1!==a.search(/\bmarkdown\b/)&&(i=a+r.converter.makeHtml(t)+n),"\n\n¨K"+(r.gHtmlBlocks.push(i)-1)+"K\n\n"};t.backslashEscapesHTMLTags&&(e=e.replace(/\\<(\/?[^>]+?)>/g,function(e,t){return"<"+t+">"}));for(var o=0;o]*>","^ {0,3}\\s*","gim"),r.converter._dispatch("hashPreCodeTags.after",e,t,r)}),i.subParser("headers",function(e,t,r){function a(e){var a,n;if(t.customizedHeaderId){var o=e.match(/\{([^{]+?)}\s*$/);o&&o[1]&&(e=o[1])}return a=e,n=i.helper.isString(t.prefixHeaderId)?t.prefixHeaderId:!0===t.prefixHeaderId?"section-":"",t.rawPrefixHeaderId||(a=n+a),a=t.ghCompatibleHeaderId?a.replace(/ /g,"-").replace(/&/g,"").replace(/¨T/g,"").replace(/¨D/g,"").replace(/[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g,"").toLowerCase():t.rawHeaderId?a.replace(/ /g,"-").replace(/&/g,"&").replace(/¨T/g,"¨").replace(/¨D/g,"$").replace(/["']/g,"-").toLowerCase():a.replace(/[^\w]/g,"").toLowerCase(),t.rawPrefixHeaderId&&(a=n+a),r.hashLinkCounts[a]?a=a+"-"+r.hashLinkCounts[a]++:r.hashLinkCounts[a]=1,a}e=r.converter._dispatch("headers.before",e,t,r);var n=isNaN(parseInt(t.headerLevelStart))?1:parseInt(t.headerLevelStart),o=t.smoothLivePreview?/^(.+)[ \t]*\n={2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n=+[ \t]*\n+/gm,s=t.smoothLivePreview?/^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n-+[ \t]*\n+/gm;e=(e=e.replace(o,function(e,o){var s=i.subParser("spanGamut")(o,t,r),l=t.noHeaderId?"":' id="'+a(o)+'"',c=""),l+="
",n.push(l))}for(o=n.length,s=0;s]*>/.test(u)&&(d=!0)}n[s]=u}return e=(e=(e=n.join("\n")).replace(/^\n+/g,"")).replace(/\n+$/g,""),r.converter._dispatch("paragraphs.after",e,t,r)}),i.subParser("runExtension",function(e,t,r,a){if(e.filter)t=e.filter(t,a.converter,r);else if(e.regex){var n=e.regex;n instanceof RegExp||(n=new RegExp(n,"g")),t=t.replace(n,e.replace)}return t}),i.subParser("spanGamut",function(e,t,r){return e=r.converter._dispatch("spanGamut.before",e,t,r),e=i.subParser("codeSpans")(e,t,r),e=i.subParser("escapeSpecialCharsWithinTagAttributes")(e,t,r),e=i.subParser("encodeBackslashEscapes")(e,t,r),e=i.subParser("images")(e,t,r),e=i.subParser("anchors")(e,t,r),e=i.subParser("autoLinks")(e,t,r),e=i.subParser("simplifiedAutoLinks")(e,t,r),e=i.subParser("emoji")(e,t,r),e=i.subParser("underline")(e,t,r),e=i.subParser("italicsAndBold")(e,t,r),e=i.subParser("strikethrough")(e,t,r),e=i.subParser("ellipsis")(e,t,r),e=i.subParser("hashHTMLSpans")(e,t,r),e=i.subParser("encodeAmpsAndAngles")(e,t,r),t.simpleLineBreaks?/\n\n¨K/.test(e)||(e=e.replace(/\n+/g,"
\n")):e=e.replace(/ +\n/g,"
\n"),r.converter._dispatch("spanGamut.after",e,t,r)}),i.subParser("strikethrough",function(e,t,r){return t.strikethrough&&(e=(e=r.converter._dispatch("strikethrough.before",e,t,r)).replace(/(?:~){2}([\s\S]+?)(?:~){2}/g,function(e,a){return function(e){return t.simplifiedAutoLink&&(e=i.subParser("simplifiedAutoLinks")(e,t,r)),""+e+""}(a)}),e=r.converter._dispatch("strikethrough.after",e,t,r)),e}),i.subParser("stripLinkDefinitions",function(e,t,r){var a=function(e,a,n,o,s,l,c){return a=a.toLowerCase(),n.match(/^data:.+?\/.+?;base64,/)?r.gUrls[a]=n.replace(/\s/g,""):r.gUrls[a]=i.subParser("encodeAmpsAndAngles")(n,t,r),l?l+c:(c&&(r.gTitles[a]=c.replace(/"|'/g,""")),t.parseImgDimensions&&o&&s&&(r.gDimensions[a]={width:o,height:s}),"")};return(e=(e=(e+="¨0").replace(/^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*(data:.+?\/.+?;base64,[A-Za-z0-9+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n\n|(?=¨0)|(?=\n\[))/gm,a)).replace(/^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*([^>\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=¨0))/gm,a)).replace(/¨0/,"")}),i.subParser("tables",function(e,t,r){function a(e){return/^:[ \t]*--*$/.test(e)?' style="text-align:left;"':/^--*[ \t]*:[ \t]*$/.test(e)?' style="text-align:right;"':/^:[ \t]*--*[ \t]*:$/.test(e)?' style="text-align:center;"':""}function n(e,a){var n="";return e=e.trim(),(t.tablesHeaderId||t.tableHeaderId)&&(n=' id="'+e.replace(/ /g,"_").toLowerCase()+'"'),""+(e=i.subParser("spanGamut")(e,t,r))+" \n"}function o(e,a){return""+i.subParser("spanGamut")(e,t,r)+" \n"}function s(e){var s,l=e.split("\n");for(s=0;s\n\n\n",n=0;n\n";for(var i=0;i\n"}return r+" \n\n"}(h,p)}return t.tables?(e=(e=(e=(e=r.converter._dispatch("tables.before",e,t,r)).replace(/\\(\|)/g,i.helper.escapeCharactersCallback)).replace(/^ {0,3}\|?.+\|.+\n {0,3}\|?[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:[-=]){2,}[\s\S]+?(?:\n\n|¨0)/gm,s)).replace(/^ {0,3}\|.+\|[ \t]*\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n( {0,3}\|.+\|[ \t]*\n)*(?:\n|¨0)/gm,s),r.converter._dispatch("tables.after",e,t,r)):e}),i.subParser("underline",function(e,t,r){return t.underline?(e=r.converter._dispatch("underline.before",e,t,r),e=(e=t.literalMidWordUnderscores?(e=e.replace(/\b___(\S[\s\S]*?)___\b/g,function(e,t){return""+t+""})).replace(/\b__(\S[\s\S]*?)__\b/g,function(e,t){return""+t+""}):(e=e.replace(/___(\S[\s\S]*?)___/g,function(e,t){return/\S$/.test(t)?""+t+"":e})).replace(/__(\S[\s\S]*?)__/g,function(e,t){return/\S$/.test(t)?""+t+"":e})).replace(/(_)/g,i.helper.escapeCharactersCallback),e=r.converter._dispatch("underline.after",e,t,r)):e}),i.subParser("unescapeSpecialChars",function(e,t,r){return e=(e=r.converter._dispatch("unescapeSpecialChars.before",e,t,r)).replace(/¨E(\d+)E/g,function(e,t){var r=parseInt(t);return String.fromCharCode(r)}),r.converter._dispatch("unescapeSpecialChars.after",e,t,r)}),i.subParser("makeMarkdown.blockquote",function(e,t){var r="";if(e.hasChildNodes())for(var a=e.childNodes,n=a.length,o=0;o "+(r=r.trim()).split("\n").join("\n> ")}),i.subParser("makeMarkdown.codeBlock",function(e,t){var r=e.getAttribute("language"),a=e.getAttribute("precodenum");return"```"+r+"\n"+t.preList[a]+"\n```"}),i.subParser("makeMarkdown.codeSpan",function(e){return"`"+e.innerHTML+"`"}),i.subParser("makeMarkdown.emphasis",function(e,t){var r="";if(e.hasChildNodes()){r+="*";for(var a=e.childNodes,n=a.length,o=0;o",e.hasAttribute("width")&&e.hasAttribute("height")&&(t+=" ="+e.getAttribute("width")+"x"+e.getAttribute("height")),e.hasAttribute("title")&&(t+=' "'+e.getAttribute("title")+'"'),t+=")"),t}),i.subParser("makeMarkdown.links",function(e,t){var r="";if(e.hasChildNodes()&&e.hasAttribute("href")){var a=e.childNodes,n=a.length;r="[";for(var o=0;o",e.hasAttribute("title")&&(r+=' "'+e.getAttribute("title")+'"'),r+=")"}return r}),i.subParser("makeMarkdown.list",function(e,t,r){var a="";if(!e.hasChildNodes())return"";for(var n=e.childNodes,o=n.length,s=e.getAttribute("start")||1,l=0;l"+t.preList[r]+""}),i.subParser("makeMarkdown.strikethrough",function(e,t){var r="";if(e.hasChildNodes()){r+="~~";for(var a=e.childNodes,n=a.length,o=0;otr>th"),l=e.querySelectorAll("tbody>tr");for(r=0;rp&&(p=g)}for(r=0;r/g,"\\$1>")).replace(/^#/gm,"\\#")).replace(/^(\s*)([-=]{3,})(\s*)$/,"$1\\$2$3")).replace(/^( {0,3}\d+)\./gm,"$1\\.")).replace(/^( {0,3})([+-])/gm,"$1\\$2")).replace(/]([\s]*)\(/g,"\\]$1\\(")).replace(/^ {0,3}\[([\S \t]*?)]:/gm,"\\[$1]:")}),e.exports?e.exports=i:this.showdown=i}).call(t)}),fe={pangu:n,minimatch:R,beautify:re,style:ce,rdability:de,markdown:Object.freeze({default:he,__moduleExports:he})};e.Plugin=function(e){return void 0==e?fe:fe[e]},Object.defineProperty(e,"__esModule",{value:!0})});
diff --git a/src/vender/puread/puread.js b/src/vender/puread/puread.js
deleted file mode 100644
index 21a126346..000000000
--- a/src/vender/puread/puread.js
+++ /dev/null
@@ -1,229 +0,0 @@
-console.log( "=== PureRead: PureRead load ===" )
-
-import * as util from './util';
-import AdapteSite from './adaptesite';
-
-export default class PureRead extends AdapteSite {
-
- constructor( sites ) {
- super( sites );
- this.version = "0.0.2";
- this.org_url = location.href;
- this.html = {}; // clone site, include: title, desc, include, avatar, paging
- this.plugin = {};
- }
-
- /**
- * Verify current puread is same
- *
- * @return {boolean} true: same; false: not same;
- */
- Exist() {
- return this.org_url == location.href;
- }
-
- /**
- * Add Plugin
- *
- * @param {object} plugin object
- */
- AddPlugin( plugin ) {
- this.plugin = {
- minimatch : plugin.minimatch,
- pangu : plugin.pangu,
- beautify : plugin.beautify,
- stylesheet: plugin.style,
- };
- super.SetMinimatch( this.plugin.minimatch );
- }
-
- /**
- * Create temp read mode
- *
- * @param {string} include: read, focus
- * @param {dom} html dom element
- */
- TempMode( mode, dom ) {
- this.state = "temp";
- this.dom = dom;
- this.Newsite( mode, dom.outerHTML );
- }
-
- /**
- * Get read mode html
- */
- ReadMode() {
- this.html = wrap( this.current.site );
- }
-
- /**
- * Get highlight( focus ) jquery, only usage focus mode
- *
- * @return {jquery} jquery object
- */
- Include() {
- let include = this.current.site.include,
- $focus = [];
- const target = util.selector( include );
- try {
- if ( util.specTest( target ) ) {
- const [ value, state ] = util.specAction( include );
- if ( state == 0 ) {
- include = include.replace( /\[\[{\$\(|}\]\]|\).html\(\)/g, "" );
- $focus = $( util.specAction( `[[[${include}]]]` )[0] );
- } else if ( state == 3 ) {
- $focus = value;
- }
- } else if ( target ) {
- $focus = $( "body" ).find( target );
- }
- } catch ( error ) {
- console.error( "Get $focus failed", error )
- }
- return $focus;
- }
-
- /**
- * Get exlcude jquery selector array list
- *
- * @param {jquery} jquery object
- * @return {array} jquery selector
- */
- Exclude( $target ) {
- return excludeSelector( $target, this.current.site.exclude );
- }
-
- /**
- * Beautify html
- *
- * @param {jquery} jquery
- */
- Beautify( $target ) {
- if ( this.plugin.beautify ) {
- this.plugin.beautify.specbeautify( this.current.site.name, $target );
- this.plugin.beautify.removeSpareTag( this.current.site.name, $target );
- this.plugin.beautify.htmlbeautify( $target );
- this.plugin.beautify.commbeautify( this.current.site.name, $target );
- }
- }
-
- /**
- * Format usage pangu plugin
- *
- * @param {string} class name
- */
- Format( cls ) {
- this.plugin.pangu &&
- this.plugin.pangu.spacingElementByClassName( cls );
- }
-}
-
-/**
- * Wrap storage.current.site object
- *
- * @param {object} storage.current.site object
- * @return {object} wrapper object
- */
-function wrap( site ) {
- const wrapper = util.clone( site ),
- title = util.selector( site.title == "" ? "" : site.title ),
- desc = util.selector( site.desc ),
- include = util.selector( site.include );
- wrapper.title = query( title );
- wrapper.desc = query( desc );
- wrapper.include = site.include == "" && site.html != "" ? site.html : query( include, "html" );
- wrapper.avatar && wrapper.avatar.length > 0 && wrapper.avatar[0].name == "" && delete wrapper.avatar;
- wrapper.paging && wrapper.paging.length > 0 && wrapper.paging[0].prev == "" && delete wrapper.paging;
- wrapper.avatar && wrapper.avatar.forEach( item => {
- const key = Object.keys( item ).join(),
- value = item[key];
- item[key] = query( util.selector( value ), "html" );
- });
- wrapper.paging && wrapper.paging.forEach( item => {
- const key = Object.keys( item ).join(),
- value = item[key];
- item[key] = query( util.selector( value ) );
- });
- return wrapper;
-}
-
-/**
- * Query content usage jquery
- *
- * @param {string} query content
- * @param {string} type, incldue: text, html and multi
- * @return {string} query result
- */
-function query( content, type = "text" ) {
- const $root = $( "html" );
- if ( util.specTest( content ) ) {
- const [ value, state ] = util.specAction( content );
- if ( state == 0 ) {
- content = value;
- } else if ( state == 3 ) {
- content = getcontent( $root.find( value ) );
- }
- } else if ( type == "html" ) {
- content = getcontent( $root.find( content ) );
- } else if ( type == "multi" ) {
- // TO-DO
- } else {
- content = $root.find( content ).text().trim();
- }
- return content;
-}
-
-/**
- * Get content from current.site.include
- *
- * @param {jquery} jquery object e.g. $root.find( content )
- * @return {string} $target html
- */
-function getcontent( $target ) {
- let html = "";
- switch ( $target.length ) {
- case 0:
- html = " ";
- break;
- case 1:
- html = $target.html().trim();
- break;
- default:
- html = $target.map( (index, item) => $(item).html() ).get().join( "
" );
- break;
- }
- return html;
-}
-
-/**
- * Get exclude tags list
- *
- * @param {jquery} jquery object
- * @param {array} hidden html
- * @return {string} tags list string
- */
-function excludeSelector( $target, exclude ) {
- let tags = [], tag = "";
- for ( let content of exclude ) {
- if ( util.specTest( content )) {
- const [ value, type ] = util.specAction( content );
- if ( type == 1 ) {
- tag = value;
- } else if ( type == 2 ) {
- const arr = $target.html().match( new RegExp( value, "g" ) );
- if ( arr && arr.length > 0 ) {
- const str = arr.join( "" );
- tag = `*[${str}]`;
- } else {
- tag = undefined;
- }
- } else if ( type == 3 ) {
- value.remove();
- }
- } else {
- tag = util.selector( content );
- }
- if ( tag ) tags.push( tag );
- }
- return tags.join( "," );
-}
\ No newline at end of file
diff --git a/src/vender/puread/puread.min.js b/src/vender/puread/puread.min.js
new file mode 100644
index 000000000..51a4be02d
--- /dev/null
+++ b/src/vender/puread/puread.min.js
@@ -0,0 +1 @@
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.PureRead=e()}(this,function(){"use strict";var t=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},e=function(){function t(t,e){for(var r=0;r?$|<[^/][-_a-zA-Z0-9]+>?$/gi);return e&&e.length>0?[1,e]:[-1,void 0]}function c(t){var e=s(t),r=a(e,2),n=r[0],i=r[1];if(2==n)return t;if(1==n){var o=i[0].trim().replace(/['"<>]/g,"").replace(/ /gi,"=").split("="),l=a(o,3),u=l[0],c=l[1],h=l[2];return c?"class"===c.toLowerCase()?c=u+"."+h:"id"===c.toLowerCase()&&(c=u+"#"+h):c=u,c}return null}function h(t){return/^(\[\[)[\[{`'/]{1}[ \S]+[}`'/\]]\]\]{1}($)/g.test(t)}function d(t){var e=[t.replace(/(^)\[\[|\]\]$/g,"")],r=e[0],n=e[1];switch(r[0]){case"{":r=r.replace(/^{|}$/g,""),t=new Function("return "+r)(),n=0;break;case"'":t=(t=r.replace(/^'|'$/g,"")).match(/^<[a-zA-Z0-9_-]+>/g).join("").replace(/<|>/g,"")+":contains("+t.replace(/<[/a-zA-Z0-9_-]+>/g,"")+")",n=1;break;case"/":t=r.replace(/^\/|\/$/g,"").replace(/\\{2}/g,"\\").replace(/'/g,'"'),n=2;break;case"[":r=r.replace(/^{|}$/g,""),t=new Function("return "+r)()[0],n=3;break;case"`":r=p(r=r.replace(/^`|`$/g,"")),t=$(r),n=4;break;default:n=-1}return[t,n]}function f(t){try{if(""!=t.id)return void 0==t.id?"":"//*[@id='"+t.id+"']";if(t===document.body)return"/html[1]/"+t.tagName.toLowerCase();for(var e=0,r=t.parentNode.childNodes,n=0;n0&&void 0!==arguments[0]?arguments[0]:{global:[],custom:[],local:[]};t(this,n),this.url=(r=(e="/"!=(e=window.location.pathname)&&e.endsWith("/")?e=e.replace(/\/$/,""):e).replace(/\/[%@#.~a-zA-Z0-9_-]+$|^\/$/g,""),window.location.protocol+"//"+window.location.hostname+r+"/"),this.sites=i,this.current={},this.state="none",this.origins=[],this.mathjax=void 0,b=location.href}return e(n,[{key:"SetURL",value:function(t){var e,r=u(t),n=(e="/"!=(e=r.pathname)&&e.endsWith("/")?e=e.replace(/\/$/,""):e).replace(/\/[%@#.~a-zA-Z0-9_-]+$|^\/$/g,"");this.url=r.protocol+"//"+r.hostname+n+"/",b=t}},{key:"SetMinimatch",value:function(t){v=t}},{key:"SetRdability",value:function(t){g=t}},{key:"SetMarkdown",value:function(t){y=t}},{key:"isMathJax",value:function(){var t=this;return void 0==this.mathjax&&(this.mathjax=!1,$("body").find("script").each(function(e,r){r.type.startsWith("math")&&(t.mathjax=!0)})),this.mathjax}},{key:"MathJaxMode",value:function(){var t=x();if(-1!=t)return this.Newsite("read",t[0].outerHTML),this.dom=t[0],this.state="temp",t;var e=k();if(e&&""!=e.content){var r=j(e.content),n=r.id,i=r.cls,a=r.tag;return""!=n?"<"+a+' id="'+n+'">':""!=i?"<"+a+' class="'+i+'">':void 0}}},{key:"Readability",value:function(){try{var t=k();if(!t||""==t.content)throw"Readability error";this.Newsite("read",t.content,t.excerpt);var e=j(t.wrap),r=e.id,n=e.cls,i=e.tag;this.dom=""!=r?$("body").find("#"+r)[0]:""!=n?$("body").find("."+n.replace(/ /gi,"."))[0]:$("body").find(""+i)[0],this.state="temp"}catch(t){var a=x();-1!=a?(this.Newsite("read",a[0].outerHTML),this.dom=a[0],this.state="temp"):this.current.site=l(m)}}},{key:"Getsite",value:function(t,e){return this.sites[t].find(function(t){return t[0]==e})}},{key:"Getsites",value:function(){var t=this,e=[],n=function(){if(v(location.href,"file://**/*.txt")||v(location.href,"http*://**/*.txt"))return function(){var t=location.pathname.split("/").pop(),e="file:"==location.protocol?"local":"remote",r={name:"txtread::"+e,title:"",desc:"",include:"",auto:!1,exclude:[]};"remote"==e&&(r.include="",r.html=$("body pre").html().replace(/\n/gi,"
"));return!$("title").html()&&$("head").append(""+decodeURI(t.replace(".txt",""))+" "),r}();if($($("body").children()[0]).is("pre")&&(v(location.href,"file://**/*.md")||v(location.href,"http*://**/*.md")))return function(){var t=location.pathname.split("/").pop(),e={name:"txtread::"+("file:"==location.protocol?"local":"remote"),title:"",desc:"",include:"",auto:!1,exclude:[]},r=(new y.default.Converter).makeHtml($("body pre").text());return e.html=r,!$("title").html()&&$("head").append(""+decodeURI(t.replace(".md",""))+" "),e}();var t=/<\S+ (class|id)=("|')?[\w-_=;:' ]+("|')?>?$|<[^/][-_a-zA-Z0-9]+>?$/gi,e={name:$("meta[name='simpread:name']").attr("content"),url:$("meta[name='simpread:url']").attr("content"),title:$("meta[name='simpread:title']").attr("content"),desc:$("meta[name='simpread:desc']").attr("content"),include:$("meta[name='simpread:include']").attr("content"),exp:$("meta[name='simpread:exclude']").attr("content"),auto:$("meta[name='simpread:auto']").attr("content"),exclude:[]};if(e.name&&e.include){if(e.url&&!v(location.href,e.url))return;!e.title&&(e.title=""),!e.desc&&(e.desc=""),!e.exp&&(e.exp=""),e.name="metaread::"+e.name,e.auto="true"==e.auto;var r=["title","desc","include","exp"].findIndex(function(r){return""!=e[r]&&!e[r].match(t)});return e.exclude.push(e.exp),delete e.exp,-1==r?e:void 0}return}();if(this.current.url=this.url,n)this.current.auto=n.auto,this.current.url=n.url,delete n.auto,delete n.url,this.current.site=r({},n),this.current.site.name.startsWith("metaread::")&&(this.state="meta"),this.current.site.name.startsWith("txtread::")&&(this.state="txt");else if(_("local",new Map(this.sites.local),this.url,e),_("global",new Map(this.sites.global),this.url,e),_("person",new Map(this.sites.person),this.url,e),_("custom",new Map(this.sites.custom),this.url,e),e.length>0){var i=void 0;if(e.forEach(function(e){e[1].active&&(i=e,t.current.url=i[0],t.current.site=t.Safesite(r({},i[1]),i[2],i[0]),t.state="adapter")}),!i){var a=e[0];a[1].active=!0,this.current.url=a[0],this.current.site=this.Safesite(r({},a[1]),a[2],a[0]),this.state="adapter"}}else{var o=function(){if(location.pathname.includes("thread")||location.pathname.includes("forum.php")){if($(".t_f").length>0&&$(".favatar").find(".authi").length>0&&$(".avatar").find("img").length>0)return{avatar:[{name:"[[{$('.favatar').find('.authi')}]]"},{url:"[[{$('.avatar').find('img')}]]"}],include:"[[{$('.t_f')}]]"}}else if(/\/t\/[\w-]+\/\d+/.test(location.pathname)&&$("meta[name=generator]").attr("content").includes("discourse"))return{avatar:[{name:"[[{$('.topic-avatar').find('.a[data-user-card]')}]]"},{url:"[[{$('.topic-avatar').find('img')}]]"}],include:"[[{$('.cooked')}]]"};return-1}();-1!=o?(this.Newmultisite("read",o),this.state="temp"):this.Readability()}this.current.site.matching=e}},{key:"Addsites",value:function(t){var e=0;if(0==this.sites.global.length)this.sites.global=this.Formatsites(t),e=this.sites.global.length;else{var r=function(t,e){var r=new Map(e),n=[].concat(o(r.keys())),i=0;return t.map(function(t){n.includes(t[0])?n.includes(t[0]):i++}),{count:i,newsites:t}}(this.Formatsites(t),this.sites.global);e=r.count,this.sites.global=r.newsites}return e}},{key:"Addlocalsites",value:function(t){return this.sites.local=[].concat(o(t)),this.sites.local}},{key:"Addallsites",value:function(t){return this.sites={global:[].concat(o(t.global)),person:[].concat(o(t.person)),custom:[].concat(o(t.custom)),local:[].concat(o(t.local))},this.sites}},{key:"Newsite",value:function(t,e,n){var i={mode:t,url:window.location.href,site:{name:"tempread::"+window.location.host,title:"",desc:"[[{$('meta[name=Description]').attr('content')||$('meta[name=description]').attr('content')}]]",include:"",exclude:[]}};e&&(i.site.html=e),this.current.mode=i.mode,this.current.url=i.url,this.current.site=this.Safesite(r({},i.site),"local",i.url),n&&(this.current.site.excerpt=n)}},{key:"Newmultisite",value:function(t,e){var n={mode:t,url:window.location.href,site:{name:"tempread::"+window.location.host,title:"",desc:"",include:e.include,exclude:[],avatar:e.avatar}};this.current.mode=n.mode,this.current.url=n.url,this.current.site=this.Safesite(r({},n.site),"local",n.url)}},{key:"Updatesite",value:function(t,e,r){var n=this.sites[t].findIndex(function(t){return t[0]==e});-1==n&&(n=this.sites[t].length),this.sites[t].splice(n,1,r)}},{key:"Deletesite",value:function(t,e,r){var n=this.sites[t].findIndex(function(t){return t[0]==e});-1!=n&&this.sites[t].splice(n,1),r(n)}},{key:"Safesite",value:function(t,e,r){return t.url=r,t.target=e,""==t.name&&(t.name="tempread::"),(!t.avatar||0==t.avatar.length)&&(t.avatar=[{name:""},{url:""}]),(!t.paging||0==t.paging.length)&&(t.paging=[{prev:""},{next:""}]),t}},{key:"Cleansite",value:function(t){return delete t.url,delete t.html,delete t.target,delete t.matching,t.avatar&&t.avatar.length>0&&""==t.avatar[0].name&&delete t.avatar,t.paging&&t.paging.length>0&&""==t.paging[0].prev&&delete t.paging,t}},{key:"Formatsites",value:function(t){var e=new Map,r=!0,n=!1,i=void 0;try{for(var a,l=t.sites[Symbol.iterator]();!(r=(a=l.next()).done);r=!0){var u=a.value;if(0==O(u)){var s=u.url;delete u.url,e.set(s,u)}}}catch(t){n=!0,i=t}finally{try{!r&&l.return&&l.return()}finally{if(n)throw i}}return[].concat(o(e))}},{key:"Clearsites",value:function(t){t?this.sites[t]=[]:this.sites={global:[],custom:[],local:[]}}},{key:"Origins",value:function(t){var e=t.origins.map(function(t){return t.url});return(e=new Set(this.origins.concat(e))).forEach(function(t){""!=t.trim()&&t.trim().startsWith("http")&&t.trim().endsWith(".json")||e.delete(t)}),this.origins=[].concat(o(e)),this.origins}},{key:"Addorigins",value:function(t){return this.sites.custom=[].concat(o(t)),this.sites.custom}},{key:"Clearorigins",value:function(){var t=this.sites.custom.length;return this.sites.custom=[],t}}]),n}();function x(){var t=$("body"),e=!0,r=!1,n=void 0;try{for(var i,a=["[itemprop='articleBody']","article",".post-content",".entry-content",".post-article",".content-post",".article-entry",".article-content",".article-body",".markdown-body",".post",".content"][Symbol.iterator]();!(e=(i=a.next()).done);e=!0){var o=i.value,l=t.find(o);if(l.length>0)return l}}catch(t){r=!0,n=t}finally{try{!e&&a.return&&a.return()}finally{if(r)throw n}}return-1}function k(){var t=document.location,e=(t.href,t.host,t.protocol,t.host,t.protocol.substr(0,t.protocol.indexOf(":")),t.protocol,t.host,t.pathname.substr(0,t.pathname.lastIndexOf("/")+1),new g.Readability(document.cloneNode(!0)).parse());return e}function _(t,e,r){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:[],i=function(t){var e=t.replace("www.","").match(/\.\S+\.\S+/g);return e?e[0].substr(1):t.replace("www.","")},a=u(b),s=[].concat(o(e.keys())),c=r.match(/[.a-zA-z0-9-_]+/g)[1].replace("www.",""),h=i(a.hostname),d=function(){return"/"==a.pathname||/\/(default|index|portal).[0-9a-zA-Z]+$/.test(a.pathname)},f=!0,p=!1,m=void 0;try{for(var g,y=s[Symbol.iterator]();!(f=(g=y.next()).done);f=!0){var w=g.value,x=e.get(w).name,$=i(x);w.startsWith("[[/")&&w.endsWith("/]]")&&new RegExp(w.replace(/^\[\[\/|\/\]\]/g,"")).test(location.href)?n.push([w,l(e.get(w)),t]):d()||w.endsWith("*")||w.replace(/^http[s]?:/,"")!=r.replace(/^http[s]?:/,"")?w.match(/\*/g)&&1==w.match(/\*/g).length&&!d()&&w.endsWith("*")&&c.includes($)&&h==$&&r.includes(x)?n.push([w,l(e.get(w)),t]):v(a.origin+a.pathname,w)&&n.push([w,l(e.get(w)),t]):n.push([w,l(e.get(w)),t])}}catch(t){p=!0,m=t}finally{try{!f&&y.return&&y.return()}finally{if(p)throw m}}}function O(t){if(!t.name||!t.url||!t.include)return-1;if(-1==s(t.title)[0]||-1==s(t.include)[0]||-1==s(t.desc)[0])return-2;if(t.paging){if(2!=t.paging.length)return-3;if(!t.paging[0].prev)return-4;if(!t.paging[1].next)return-5;if(-1==s(t.paging[0].prev)[0]||-1==s(t.paging[1].next)[0])return-6}if(t.avatar){if(2!=t.avatar.length)return-7;if(!t.avatar[0].name)return-8;if(!t.avatar[1].url)return-9;if(-1==s(t.avatar[0].name)[0]||-1==s(t.avatar[1].url)[0])return-10}return 0}function j(t){var e=t.replace('',""),r=$(e)[0],n=r.outerHTML.replace(r.innerHTML,""),i=$(n)[0],a=i.tagName.toLowerCase(),o=i.className;return{id:i.id,cls:o,tag:a}}function S(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"text",r=$("html");if(h(t)){var n=d(t),i=a(n,2),o=i[0],l=i[1];0==l?t=o:3==l?t=M(r.find(o)):4==l&&(t=o.html())}else"html"==e?t=M(r.find(t)):"multi"==e||(t=r.find(t).text().trim());return t}function M(t){var e="";switch(t.length){case 0:e=" ";break;case 1:e=t.html().trim();break;default:e=t.map(function(t,e){return $(e).html()}).get().join("
")}return e}return function(r){function o(e){t(this,o);var r=i(this,(o.__proto__||Object.getPrototypeOf(o)).call(this,e));return r.version="0.0.4 build 0111",r.org_url=location.href,r.html={},r.plugin={},r.pure=!1,r.cleanup=!1,r}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(o,w),e(o,[{key:"Exist",value:function(){return this.org_url==location.href}},{key:"AddPlugin",value:function(t){this.plugin={minimatch:t.minimatch,pangu:t.pangu,beautify:t.beautify,stylesheet:t.style,rdability:t.rdability,markdown:t.markdown},n(o.prototype.__proto__||Object.getPrototypeOf(o.prototype),"SetMinimatch",this).call(this,this.plugin.minimatch),n(o.prototype.__proto__||Object.getPrototypeOf(o.prototype),"SetRdability",this).call(this,this.plugin.rdability),n(o.prototype.__proto__||Object.getPrototypeOf(o.prototype),"SetMarkdown",this).call(this,this.plugin.markdown)}},{key:"ReadMode",value:function(){var t,e,r,n,i;this.html=(t=this.current.site,e=l(t),r=c(""==t.title?"":t.title),n=c(t.desc),i=c(t.include),e.title=""==t.title||""==t.title?$("head title").text():S(r),e.desc=function(t){if(void 0==t)return t;var e=t.length,r=t.indexOf("。")+1;return e>100&&(t=r>0?t.substr(0,r):t.substr(0,101)+"......"),t}(t.excerpt?t.excerpt:S(n)),e.include=""==t.include&&""!=t.html?t.html:S(i,"html"),e.avatar&&e.avatar.length>0&&""==e.avatar[0].name&&delete e.avatar,e.paging&&e.paging.length>0&&""==e.paging[0].prev&&delete e.paging,e.avatar&&e.avatar.forEach(function(t){var e=Object.keys(t).join(),r=t[e];t[e]=S(c(r),"html")}),e.paging&&e.paging.forEach(function(t){var e=Object.keys(t).join(),r=t[e];t[e]=S(c(r))}),e)}},{key:"TempMode",value:function(t,e){this.state="temp",this.dom=e,this.Newsite(t,e.outerHTML)}},{key:"GetDom",value:function(t,e){return S(c(t),e)}},{key:"Include",value:function(){var t=this.current.site.include,e=[],r=c(t);try{if(h(r)){var n=d(t),i=a(n,2),o=i[0],l=i[1];0==l?(t=t.replace(/\[\[{\$\(|}\]\]|\).html\(\)/g,""),e=$(d("[[["+t+"]]]")[0])):3==l&&(e=o)}else r&&(e=$("body").find(r))}catch(t){}return e}},{key:"Exclude",value:function(t){return function(t,e){var r=[],n="",i=!0,o=!1,l=void 0;try{for(var u,s=e[Symbol.iterator]();!(i=(u=s.next()).done);i=!0){var f=u.value;if(h(f)){var p=d(f),m=a(p,2),v=m[0],g=m[1];if(1==g)n=v;else if(2==g){var y=t.html().match(new RegExp(v,"g"));if(y&&y.length>0){var b=y.join("");n="*["+b+"]"}else n=void 0}else 3==g?v.remove():4==g&&v.remove()}else n=c(f);n&&r.push(n)}}catch(t){o=!0,l=t}finally{try{!i&&s.return&&s.return()}finally{if(o)throw l}}return r.join(",")}(t,this.current.site.exclude)}},{key:"Beautify",value:function(t){0!=t.children().length&&this.plugin.beautify&&(this.plugin.beautify.before(this.current.site.name,t),this.cleanup&&this.plugin.beautify.cleanHTML(t,this.pure,this.isMathJax()),this.plugin.beautify.specbeautify(this.current.site.name,t),this.plugin.beautify.removeSpareTag(this.current.site.name,t),this.plugin.beautify.htmlbeautify(t),this.plugin.beautify.commbeautify(this.current.site.name,t))}},{key:"Format",value:function(t){this.plugin.pangu&&this.plugin.pangu.spacingElementByClassName(t)}},{key:"Utils",value:function(){return{dom2Xpath:f,xPath2Dom:p}}}]),o}()});
diff --git a/src/vender/puread/util.js b/src/vender/puread/util.js
deleted file mode 100644
index 94116d2b3..000000000
--- a/src/vender/puread/util.js
+++ /dev/null
@@ -1,141 +0,0 @@
-console.log( "=== PureRead: Util load ===" )
-
-/**
- * Deep clone object
- *
- * @param {object} target object
- * @return {object} new target object
- */
-function clone( target ) {
- return $.extend( true, {}, target );
-}
-
-/**
- * Get URI
- *
- * @return {string} e.g. current site url is http://www.cnbeta.com/articles/1234.html return http://www.cnbeta.com/articles/
- */
-function getURI() {
- const name = (pathname) => {
- pathname = pathname != "/" && pathname.endsWith("/") ? pathname = pathname.replace( /\/$/, "" ) : pathname;
- return pathname.replace( /\/[%@#.~a-zA-Z0-9_-]+$|^\/$/g, "" );
- },
- path = name( window.location.pathname );
- return `${ window.location.protocol }//${ window.location.hostname }${ path }/`;
-}
-
-/**
- * Verify html
- *
- * @param {string} input include html tag, e.g.:
-
- *
- * @return {array} 0: int include ( -1: failï¼› 0: empty html; 1: success; 2: special tag )
- * 1: result
- */
-function verifyHtml( html ) {
- if ( html == "" ) return [ 0, html ];
- else if ( specTest( html )) return [ 2, html ];
- const item = html.match( /<\S+ (class|id)=("|')?[\w-_=;:' ]+("|')?>?$|<[^/][-_a-zA-Z0-9]+>?$/ig );
- if ( item && item.length > 0 ) {
- return [ 1, item ];
- } else {
- return [ -1, undefined ];
- }
-}
-
-/**
- * Conver html to jquery object
- *
- * @param {string} input include html tag, e.g.:
-
- *
- * @return {string} formatting e.g.:
- h2#news_title
- div.introduction
- div.content
- div.clearfix
- div.rating_box
- span
- special tag, @see specTest
- e.g. [['â–½']] [[[$('.article-btn')]]]
- [[/src=\\S+(342459.png)\\S+'/]] [[{$('.content').html()}]]
- *
- */
-function selector( html ) {
- const [ code, item ] = verifyHtml( html );
- if ( code == 2 ) return html;
- else if ( code == 1 ) {
- let [tag, prop, value] = item[0].trim().replace( /['"<>]/g, "" ).replace( / /ig, "=" ).split( "=" ); // ["h2", "class", "title"]
- if ( !prop ) prop = tag;
- else if ( prop.toLowerCase() === "class") prop = `${tag}.${value}`;
- else if ( prop.toLowerCase() === "id" ) prop = `${tag}#${value}`;
- return prop;
- } else {
- return null;
- }
-}
-
-/**
- * Verify special action, action include:
- - [[{juqery code}]] // new Function, e.g. $("xxx").xxx() return string
- - [['text']] // remove ''
- - [[/regexp/]] // regexp e.g. $("sr-rd-content").find( "*[src='http://ifanr-cdn.b0.upaiyun.com/wp-content/uploads/2016/09/AppSo-qrcode-signature.jpg']" )
- - [[[juqery code]]] // new Function, e.g. $("xxx").find() return jquery object
-
- *
- * @param {string} verify content
- * @return {boolen} verify result
- */
-function specTest( content ) {
- return /^(\[\[)[\[{'/]{1}[ \S]+[}'/\]]\]\]{1}($)/g.test( content );
-}
-
-/**
- * Exec special action, action include: @see specTest
- * type: 0, 3 - be chiefly used in include logic
- * type: 1, 2 - be chiefly used in exclude logic
- *
- * @param {string} content
- * @return {array} 0: result; 1: type( include: -1:error 0:{} 1:'' 2:// 3:[])
- */
-function specAction( content ) {
- let [ value, type ] = [ content.replace( /(^)\[\[|\]\]$/g, "" ) ];
- switch (value[0]) {
- case "{":
- value = value.replace( /^{|}$/g, "" );
- content = ( v=>new Function( `return ${v}` )() )(value);
- type = 0;
- break;
- case "'":
- content = value.replace( /^'|'$/g, "" );
- const name = content.match(/^<[a-zA-Z0-9_-]+>/g).join("").replace( /<|>/g, "" );
- const str = content.replace( /<[/a-zA-Z0-9_-]+>/g, "" );
- content = `${name}:contains(${str})`;
- type = 1;
- break;
- case "/":
- content = value.replace( /^\/|\/$/g, "" ).replace( /\\{2}/g, "\\" ).replace( /'/g, '"' );
- type = 2;
- break;
- case "[":
- value = value.replace( /^{|}$/g, "" );
- content = ( v=>new Function( `return ${v}` )() )(value)[0];
- type = 3;
- break;
- default:
- console.error( "Not support current action.", content )
- type = -1;
- break;
- }
- return [ content, type ];
-}
-
-export {
- clone,
- getURI,
- verifyHtml,
- selector,
- specTest,
- specAction
-}
\ No newline at end of file
diff --git a/src/vender/turndown/turndown-plugin-gfm.js b/src/vender/turndown/turndown-plugin-gfm.js
new file mode 100644
index 000000000..ed53990f8
--- /dev/null
+++ b/src/vender/turndown/turndown-plugin-gfm.js
@@ -0,0 +1,167 @@
+var turndownPluginGfm = (function (exports) {
+'use strict';
+
+var highlightRegExp = /highlight-(?:text|source)-([a-z0-9]+)/;
+
+function highlightedCodeBlock (turndownService) {
+ turndownService.addRule('highlightedCodeBlock', {
+ filter: function (node) {
+ var firstChild = node.firstChild;
+ return (
+ node.nodeName === 'DIV' &&
+ highlightRegExp.test(node.className) &&
+ firstChild &&
+ firstChild.nodeName === 'PRE'
+ )
+ },
+ replacement: function (content, node, options) {
+ var className = node.className || '';
+ var language = (className.match(highlightRegExp) || [null, ''])[1];
+
+ return (
+ '\n\n' + options.fence + language + '\n' +
+ node.firstChild.textContent +
+ '\n' + options.fence + '\n\n'
+ )
+ }
+ });
+}
+
+function strikethrough (turndownService) {
+ turndownService.addRule('strikethrough', {
+ filter: ['del', 's', 'strike'],
+ replacement: function (content) {
+ return '~' + content + '~'
+ }
+ });
+}
+
+var indexOf = Array.prototype.indexOf;
+var every = Array.prototype.every;
+var rules = {};
+
+rules.tableCell = {
+ filter: ['th', 'td'],
+ replacement: function (content, node) {
+ return cell(content, node)
+ }
+};
+
+rules.tableRow = {
+ filter: 'tr',
+ replacement: function (content, node) {
+ var borderCells = '';
+ var alignMap = { left: ':--', right: '--:', center: ':-:' };
+
+ if (isHeadingRow(node)) {
+ for (var i = 0; i < node.childNodes.length; i++) {
+ var border = '---';
+ var align = (
+ node.childNodes[i].getAttribute('align') || ''
+ ).toLowerCase();
+
+ if (align) border = alignMap[align] || border;
+
+ borderCells += cell(border, node.childNodes[i]);
+ }
+ }
+ return '\n' + content + (borderCells ? '\n' + borderCells : '')
+ }
+};
+
+rules.table = {
+ // Only convert tables with a heading row.
+ // Tables with no heading row are kept using `keep` (see below).
+ filter: function (node) {
+ return node.nodeName === 'TABLE' && isHeadingRow(node.rows[0])
+ },
+
+ replacement: function (content) {
+ // Ensure there are no blank lines
+ content = content.replace('\n\n', '\n');
+ return '\n\n' + content + '\n\n'
+ }
+};
+
+rules.tableSection = {
+ filter: ['thead', 'tbody', 'tfoot'],
+ replacement: function (content) {
+ return content
+ }
+};
+
+// A tr is a heading row if:
+// - the parent is a THEAD
+// - or if its the first child of the TABLE or the first TBODY (possibly
+// following a blank THEAD)
+// - and every cell is a TH
+function isHeadingRow (tr) {
+ var parentNode = tr.parentNode;
+ return (
+ parentNode.nodeName === 'THEAD' ||
+ (
+ parentNode.firstChild === tr &&
+ (parentNode.nodeName === 'TABLE' || isFirstTbody(parentNode)) &&
+ every.call(tr.childNodes, function (n) { return n.nodeName === 'TH' })
+ )
+ )
+}
+
+function isFirstTbody (element) {
+ var previousSibling = element.previousSibling;
+ return (
+ element.nodeName === 'TBODY' && (
+ !previousSibling ||
+ (
+ previousSibling.nodeName === 'THEAD' &&
+ /^\s*$/i.test(previousSibling.textContent)
+ )
+ )
+ )
+}
+
+function cell (content, node) {
+ var index = indexOf.call(node.parentNode.childNodes, node);
+ var prefix = ' ';
+ if (index === 0) prefix = '| ';
+ return prefix + content + ' |'
+}
+
+function tables (turndownService) {
+ turndownService.keep(function (node) {
+ return node.nodeName === 'TABLE' && !isHeadingRow(node.rows[0])
+ });
+ for (var key in rules) turndownService.addRule(key, rules[key]);
+}
+
+function taskListItems (turndownService) {
+ turndownService.addRule('taskListItems', {
+ filter: function (node) {
+ return node.type === 'checkbox' && node.parentNode.nodeName === 'LI'
+ },
+ replacement: function (content, node) {
+ return (node.checked ? '[x]' : '[ ]') + ' '
+ }
+ });
+}
+
+function gfm (turndownService) {
+ turndownService.use([
+ highlightedCodeBlock,
+ strikethrough,
+ tables,
+ taskListItems
+ ]);
+}
+
+exports.gfm = gfm;
+exports.highlightedCodeBlock = highlightedCodeBlock;
+exports.strikethrough = strikethrough;
+exports.tables = tables;
+exports.taskListItems = taskListItems;
+
+return exports;
+
+}({}));
+
+module.exports = turndownPluginGfm;
\ No newline at end of file
diff --git a/src/vender/turndown/turndown.js b/src/vender/turndown/turndown.js
new file mode 100644
index 000000000..c6411f9a1
--- /dev/null
+++ b/src/vender/turndown/turndown.js
@@ -0,0 +1,912 @@
+var TurndownService = (function () {
+'use strict';
+
+function extend (destination) {
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i];
+ for (var key in source) {
+ if (source.hasOwnProperty(key)) destination[key] = source[key];
+ }
+ }
+ return destination
+}
+
+function repeat (character, count) {
+ return Array(count + 1).join(character)
+}
+
+var blockElements = [
+ 'address', 'article', 'aside', 'audio', 'blockquote', 'body', 'canvas',
+ 'center', 'dd', 'dir', 'div', 'dl', 'dt', 'fieldset', 'figcaption',
+ 'figure', 'footer', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
+ 'header', 'hgroup', 'hr', 'html', 'isindex', 'li', 'main', 'menu', 'nav',
+ 'noframes', 'noscript', 'ol', 'output', 'p', 'pre', 'section', 'table',
+ 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'ul'
+];
+
+function isBlock (node) {
+ return blockElements.indexOf(node.nodeName.toLowerCase()) !== -1
+}
+
+var voidElements = [
+ 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input',
+ 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'
+];
+
+function isVoid (node) {
+ return voidElements.indexOf(node.nodeName.toLowerCase()) !== -1
+}
+
+var voidSelector = voidElements.join();
+function hasVoid (node) {
+ return node.querySelector && node.querySelector(voidSelector)
+}
+
+var rules = {};
+
+rules.paragraph = {
+ filter: 'p',
+
+ replacement: function (content) {
+ return '\n\n' + content + '\n\n'
+ }
+};
+
+rules.lineBreak = {
+ filter: 'br',
+
+ replacement: function (content, node, options) {
+ return options.br + '\n'
+ }
+};
+
+rules.heading = {
+ filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
+
+ replacement: function (content, node, options) {
+ var hLevel = Number(node.nodeName.charAt(1));
+
+ if (options.headingStyle === 'setext' && hLevel < 3) {
+ var underline = repeat((hLevel === 1 ? '=' : '-'), content.length);
+ return (
+ '\n\n' + content + '\n' + underline + '\n\n'
+ )
+ } else {
+ return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n'
+ }
+ }
+};
+
+rules.blockquote = {
+ filter: 'blockquote',
+
+ replacement: function (content) {
+ content = content.replace(/^\n+|\n+$/g, '');
+ content = content.replace(/^/gm, '> ');
+ return '\n\n' + content + '\n\n'
+ }
+};
+
+rules.list = {
+ filter: ['ul', 'ol'],
+
+ replacement: function (content, node) {
+ var parent = node.parentNode;
+ if (parent.nodeName === 'LI' && parent.lastElementChild === node) {
+ return '\n' + content
+ } else {
+ return '\n\n' + content + '\n\n'
+ }
+ }
+};
+
+rules.listItem = {
+ filter: 'li',
+
+ replacement: function (content, node, options) {
+ content = content
+ .replace(/^\n+/, '') // remove leading newlines
+ .replace(/\n+$/, '\n') // replace trailing newlines with just a single one
+ .replace(/\n/gm, '\n '); // indent
+ var prefix = options.bulletListMarker + ' ';
+ var parent = node.parentNode;
+ if (parent.nodeName === 'OL') {
+ var start = parent.getAttribute('start');
+ var index = Array.prototype.indexOf.call(parent.children, node);
+ prefix = (start ? Number(start) + index : index + 1) + '. ';
+ }
+ return (
+ prefix + content + (node.nextSibling && !/\n$/.test(content) ? '\n' : '')
+ )
+ }
+};
+
+rules.indentedCodeBlock = {
+ filter: function (node, options) {
+ return (
+ options.codeBlockStyle === 'indented' &&
+ node.nodeName === 'PRE' &&
+ node.firstChild &&
+ node.firstChild.nodeName === 'CODE'
+ )
+ },
+
+ replacement: function (content, node, options) {
+ return (
+ '\n\n ' +
+ node.firstChild.textContent.replace(/\n/g, '\n ') +
+ '\n\n'
+ )
+ }
+};
+
+rules.fencedCodeBlock = {
+ filter: function (node, options) {
+ return (
+ options.codeBlockStyle === 'fenced' &&
+ node.nodeName === 'PRE' &&
+ node.firstChild &&
+ node.firstChild.nodeName === 'CODE'
+ )
+ },
+
+ replacement: function (content, node, options) {
+ var className = node.firstChild.className || '';
+ var language = (className.match(/language-(\S+)/) || [null, ''])[1];
+
+ return (
+ '\n\n' + options.fence + language + '\n' +
+ node.firstChild.textContent +
+ '\n' + options.fence + '\n\n'
+ )
+ }
+};
+
+rules.horizontalRule = {
+ filter: 'hr',
+
+ replacement: function (content, node, options) {
+ return '\n\n' + options.hr + '\n\n'
+ }
+};
+
+rules.inlineLink = {
+ filter: function (node, options) {
+ return (
+ options.linkStyle === 'inlined' &&
+ node.nodeName === 'A' &&
+ node.getAttribute('href')
+ )
+ },
+
+ replacement: function (content, node) {
+ var href = node.getAttribute('href');
+ var title = node.title ? ' "' + node.title + '"' : '';
+ return '[' + content + '](' + href + title + ')'
+ }
+};
+
+rules.referenceLink = {
+ filter: function (node, options) {
+ return (
+ options.linkStyle === 'referenced' &&
+ node.nodeName === 'A' &&
+ node.getAttribute('href')
+ )
+ },
+
+ replacement: function (content, node, options) {
+ var href = node.getAttribute('href');
+ var title = node.title ? ' "' + node.title + '"' : '';
+ var replacement;
+ var reference;
+
+ switch (options.linkReferenceStyle) {
+ case 'collapsed':
+ replacement = '[' + content + '][]';
+ reference = '[' + content + ']: ' + href + title;
+ break
+ case 'shortcut':
+ replacement = '[' + content + ']';
+ reference = '[' + content + ']: ' + href + title;
+ break
+ default:
+ var id = this.references.length + 1;
+ replacement = '[' + content + '][' + id + ']';
+ reference = '[' + id + ']: ' + href + title;
+ }
+
+ this.references.push(reference);
+ return replacement
+ },
+
+ references: [],
+
+ append: function (options) {
+ var references = '';
+ if (this.references.length) {
+ references = '\n\n' + this.references.join('\n') + '\n\n';
+ this.references = []; // Reset references
+ }
+ return references
+ }
+};
+
+rules.emphasis = {
+ filter: ['em', 'i'],
+
+ replacement: function (content, node, options) {
+ if (!content.trim()) return ''
+ return options.emDelimiter + content + options.emDelimiter
+ }
+};
+
+rules.strong = {
+ filter: ['strong', 'b'],
+
+ replacement: function (content, node, options) {
+ if (!content.trim()) return ''
+ return options.strongDelimiter + content + options.strongDelimiter
+ }
+};
+
+rules.code = {
+ filter: function (node) {
+ var hasSiblings = node.previousSibling || node.nextSibling;
+ var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings;
+
+ return node.nodeName === 'CODE' && !isCodeBlock
+ },
+
+ replacement: function (content) {
+ if (!content.trim()) return ''
+
+ var delimiter = '`';
+ var leadingSpace = '';
+ var trailingSpace = '';
+ var matches = content.match(/`+/gm);
+ if (matches) {
+ if (/^`/.test(content)) leadingSpace = ' ';
+ if (/`$/.test(content)) trailingSpace = ' ';
+ while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`';
+ }
+
+ return delimiter + leadingSpace + content + trailingSpace + delimiter
+ }
+};
+
+rules.image = {
+ filter: 'img',
+
+ replacement: function (content, node) {
+ var alt = node.alt || '';
+ var src = node.getAttribute('src') || '';
+ var title = node.title || '';
+ var titlePart = title ? ' "' + title + '"' : '';
+ return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''
+ }
+};
+
+/**
+ * Manages a collection of rules used to convert HTML to Markdown
+ */
+
+function Rules (options) {
+ this.options = options;
+ this._keep = [];
+ this._remove = [];
+
+ this.blankRule = {
+ replacement: options.blankReplacement
+ };
+
+ this.keepReplacement = options.keepReplacement;
+
+ this.defaultRule = {
+ replacement: options.defaultReplacement
+ };
+
+ this.array = [];
+ for (var key in options.rules) this.array.push(options.rules[key]);
+}
+
+Rules.prototype = {
+ add: function (key, rule) {
+ this.array.unshift(rule);
+ },
+
+ keep: function (filter) {
+ this._keep.unshift({
+ filter: filter,
+ replacement: this.keepReplacement
+ });
+ },
+
+ remove: function (filter) {
+ this._remove.unshift({
+ filter: filter,
+ replacement: function () {
+ return ''
+ }
+ });
+ },
+
+ forNode: function (node) {
+ if (node.isBlank) return this.blankRule
+ var rule;
+
+ if ((rule = findRule(this.array, node, this.options))) return rule
+ if ((rule = findRule(this._keep, node, this.options))) return rule
+ if ((rule = findRule(this._remove, node, this.options))) return rule
+
+ return this.defaultRule
+ },
+
+ forEach: function (fn) {
+ for (var i = 0; i < this.array.length; i++) fn(this.array[i], i);
+ }
+};
+
+function findRule (rules, node, options) {
+ for (var i = 0; i < rules.length; i++) {
+ var rule = rules[i];
+ if (filterValue(rule, node, options)) return rule
+ }
+ return void 0
+}
+
+function filterValue (rule, node, options) {
+ var filter = rule.filter;
+ if (typeof filter === 'string') {
+ if (filter === node.nodeName.toLowerCase()) return true
+ } else if (Array.isArray(filter)) {
+ if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true
+ } else if (typeof filter === 'function') {
+ if (filter.call(rule, node, options)) return true
+ } else {
+ throw new TypeError('`filter` needs to be a string, array, or function')
+ }
+}
+
+/**
+ * The collapseWhitespace function is adapted from collapse-whitespace
+ * by Luc Thevenard.
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Luc Thevenard
+ *
+ * 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.
+ */
+
+/**
+ * collapseWhitespace(options) removes extraneous whitespace from an the given element.
+ *
+ * @param {Object} options
+ */
+function collapseWhitespace (options) {
+ var element = options.element;
+ var isBlock = options.isBlock;
+ var isVoid = options.isVoid;
+ var isPre = options.isPre || function (node) {
+ return node.nodeName === 'PRE'
+ };
+
+ if (!element.firstChild || isPre(element)) return
+
+ var prevText = null;
+ var prevVoid = false;
+
+ var prev = null;
+ var node = next(prev, element, isPre);
+
+ while (node !== element) {
+ if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE
+ var text = node.data.replace(/[ \r\n\t]+/g, ' ');
+
+ if ((!prevText || / $/.test(prevText.data)) &&
+ !prevVoid && text[0] === ' ') {
+ text = text.substr(1);
+ }
+
+ // `text` might be empty at this point.
+ if (!text) {
+ node = remove(node);
+ continue
+ }
+
+ node.data = text;
+
+ prevText = node;
+ } else if (node.nodeType === 1) { // Node.ELEMENT_NODE
+ if (isBlock(node) || node.nodeName === 'BR') {
+ if (prevText) {
+ prevText.data = prevText.data.replace(/ $/, '');
+ }
+
+ prevText = null;
+ prevVoid = false;
+ } else if (isVoid(node)) {
+ // Avoid trimming space around non-block, non-BR void elements.
+ prevText = null;
+ prevVoid = true;
+ }
+ } else {
+ node = remove(node);
+ continue
+ }
+
+ var nextNode = next(prev, node, isPre);
+ prev = node;
+ node = nextNode;
+ }
+
+ if (prevText) {
+ prevText.data = prevText.data.replace(/ $/, '');
+ if (!prevText.data) {
+ remove(prevText);
+ }
+ }
+}
+
+/**
+ * remove(node) removes the given node from the DOM and returns the
+ * next node in the sequence.
+ *
+ * @param {Node} node
+ * @return {Node} node
+ */
+function remove (node) {
+ var next = node.nextSibling || node.parentNode;
+
+ node.parentNode.removeChild(node);
+
+ return next
+}
+
+/**
+ * next(prev, current, isPre) returns the next node in the sequence, given the
+ * current and previous nodes.
+ *
+ * @param {Node} prev
+ * @param {Node} current
+ * @param {Function} isPre
+ * @return {Node}
+ */
+function next (prev, current, isPre) {
+ if ((prev && prev.parentNode === current) || isPre(current)) {
+ return current.nextSibling || current.parentNode
+ }
+
+ return current.firstChild || current.nextSibling || current.parentNode
+}
+
+/*
+ * Set up window for Node.js
+ */
+
+var root = (typeof window !== 'undefined' ? window : {});
+
+/*
+ * Parsing HTML strings
+ */
+
+function canParseHTMLNatively () {
+ var Parser = root.DOMParser;
+ var canParse = false;
+
+ // Adapted from https://gist.github.com/1129031
+ // Firefox/Opera/IE throw errors on unsupported types
+ try {
+ // WebKit returns null on unsupported types
+ if (new Parser().parseFromString('', 'text/html')) {
+ canParse = true;
+ }
+ } catch (e) {}
+
+ return canParse
+}
+
+function createHTMLParser () {
+ var Parser = function () {};
+
+ {
+ if (shouldUseActiveX()) {
+ Parser.prototype.parseFromString = function (string) {
+ var doc = new window.ActiveXObject('htmlfile');
+ doc.designMode = 'on'; // disable on-page scripts
+ doc.open();
+ doc.write(string);
+ doc.close();
+ return doc
+ };
+ } else {
+ Parser.prototype.parseFromString = function (string) {
+ var doc = document.implementation.createHTMLDocument('');
+ doc.open();
+ doc.write(string);
+ doc.close();
+ return doc
+ };
+ }
+ }
+ return Parser
+}
+
+function shouldUseActiveX () {
+ var useActiveX = false;
+ try {
+ document.implementation.createHTMLDocument('').open();
+ } catch (e) {
+ if (window.ActiveXObject) useActiveX = true;
+ }
+ return useActiveX
+}
+
+var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser();
+
+function RootNode (input) {
+ var root;
+ if (typeof input === 'string') {
+ var doc = htmlParser().parseFromString(
+ // DOM parsers arrange elements in the and .
+ // Wrapping in a custom element ensures elements are reliably arranged in
+ // a single element.
+ '' + input + ' ',
+ 'text/html'
+ );
+ root = doc.getElementById('turndown-root');
+ } else {
+ root = input.cloneNode(true);
+ }
+ collapseWhitespace({
+ element: root,
+ isBlock: isBlock,
+ isVoid: isVoid
+ });
+
+ return root
+}
+
+var _htmlParser;
+function htmlParser () {
+ _htmlParser = _htmlParser || new HTMLParser();
+ return _htmlParser
+}
+
+function Node (node) {
+ node.isBlock = isBlock(node);
+ node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode;
+ node.isBlank = isBlank(node);
+ node.flankingWhitespace = flankingWhitespace(node);
+ return node
+}
+
+function isBlank (node) {
+ return (
+ ['A', 'TH', 'TD', 'IFRAME', 'SCRIPT', 'AUDIO', 'VIDEO'].indexOf(node.nodeName) === -1 &&
+ /^\s*$/i.test(node.textContent) &&
+ !isVoid(node) &&
+ !hasVoid(node)
+ )
+}
+
+function flankingWhitespace (node) {
+ var leading = '';
+ var trailing = '';
+
+ if (!node.isBlock) {
+ var hasLeading = /^[ \r\n\t]/.test(node.textContent);
+ var hasTrailing = /[ \r\n\t]$/.test(node.textContent);
+
+ if (hasLeading && !isFlankedByWhitespace('left', node)) {
+ leading = ' ';
+ }
+ if (hasTrailing && !isFlankedByWhitespace('right', node)) {
+ trailing = ' ';
+ }
+ }
+
+ return { leading: leading, trailing: trailing }
+}
+
+function isFlankedByWhitespace (side, node) {
+ var sibling;
+ var regExp;
+ var isFlanked;
+
+ if (side === 'left') {
+ sibling = node.previousSibling;
+ regExp = / $/;
+ } else {
+ sibling = node.nextSibling;
+ regExp = /^ /;
+ }
+
+ if (sibling) {
+ if (sibling.nodeType === 3) {
+ isFlanked = regExp.test(sibling.nodeValue);
+ } else if (sibling.nodeType === 1 && !isBlock(sibling)) {
+ isFlanked = regExp.test(sibling.textContent);
+ }
+ }
+ return isFlanked
+}
+
+var reduce = Array.prototype.reduce;
+var leadingNewLinesRegExp = /^\n*/;
+var trailingNewLinesRegExp = /\n*$/;
+var escapes = [
+ [/\\/g, '\\\\'],
+ [/\*/g, '\\*'],
+ [/^-/g, '\\-'],
+ [/^\+ /g, '\\+ '],
+ [/^(=+)/g, '\\$1'],
+ [/^(#{1,6}) /g, '\\$1 '],
+ [/`/g, '\\`'],
+ [/^~~~/g, '\\~~~'],
+ [/\[/g, '\\['],
+ [/\]/g, '\\]'],
+ [/^>/g, '\\>'],
+ [/_/g, '\\_'],
+ [/^(\d+)\. /g, '$1\\. ']
+];
+escapes = [];
+
+function TurndownService (options) {
+ if (!(this instanceof TurndownService)) return new TurndownService(options)
+
+ var defaults = {
+ rules: rules,
+ headingStyle: 'setext',
+ hr: '* * *',
+ bulletListMarker: '*',
+ codeBlockStyle: 'indented',
+ fence: '```',
+ emDelimiter: '_',
+ strongDelimiter: '**',
+ linkStyle: 'inlined',
+ linkReferenceStyle: 'full',
+ br: ' ',
+ blankReplacement: function (content, node) {
+ return node.isBlock ? '\n\n' : ''
+ },
+ keepReplacement: function (content, node) {
+ return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML
+ },
+ defaultReplacement: function (content, node) {
+ return node.isBlock ? '\n\n' + content + '\n\n' : content
+ }
+ };
+ this.options = extend({}, defaults, options);
+ this.rules = new Rules(this.options);
+}
+
+TurndownService.prototype = {
+ /**
+ * The entry point for converting a string or DOM node to Markdown
+ * @public
+ * @param {String|HTMLElement} input The string or DOM node to convert
+ * @returns A Markdown representation of the input
+ * @type String
+ */
+
+ turndown: function (input) {
+ if (!canConvert(input)) {
+ throw new TypeError(
+ input + ' is not a string, or an element/document/fragment node.'
+ )
+ }
+
+ if (input === '') return ''
+
+ var output = process.call(this, new RootNode(input));
+ return postProcess.call(this, output)
+ },
+
+ /**
+ * Add one or more plugins
+ * @public
+ * @param {Function|Array} plugin The plugin or array of plugins to add
+ * @returns The Turndown instance for chaining
+ * @type Object
+ */
+
+ use: function (plugin) {
+ if (Array.isArray(plugin)) {
+ for (var i = 0; i < plugin.length; i++) this.use(plugin[i]);
+ } else if (typeof plugin === 'function') {
+ plugin(this);
+ } else {
+ throw new TypeError('plugin must be a Function or an Array of Functions')
+ }
+ return this
+ },
+
+ /**
+ * Adds a rule
+ * @public
+ * @param {String} key The unique key of the rule
+ * @param {Object} rule The rule
+ * @returns The Turndown instance for chaining
+ * @type Object
+ */
+
+ addRule: function (key, rule) {
+ this.rules.add(key, rule);
+ return this
+ },
+
+ /**
+ * Keep a node (as HTML) that matches the filter
+ * @public
+ * @param {String|Array|Function} filter The unique key of the rule
+ * @returns The Turndown instance for chaining
+ * @type Object
+ */
+
+ keep: function (filter) {
+ this.rules.keep(filter);
+ return this
+ },
+
+ /**
+ * Remove a node that matches the filter
+ * @public
+ * @param {String|Array|Function} filter The unique key of the rule
+ * @returns The Turndown instance for chaining
+ * @type Object
+ */
+
+ remove: function (filter) {
+ this.rules.remove(filter);
+ return this
+ },
+
+ /**
+ * Escapes Markdown syntax
+ * @public
+ * @param {String} string The string to escape
+ * @returns A string with Markdown syntax escaped
+ * @type String
+ */
+
+ escape: function (string) {
+ return escapes.reduce(function (accumulator, escape) {
+ return accumulator.replace(escape[0], escape[1])
+ }, string)
+ }
+};
+
+/**
+ * Reduces a DOM node down to its Markdown string equivalent
+ * @private
+ * @param {HTMLElement} parentNode The node to convert
+ * @returns A Markdown representation of the node
+ * @type String
+ */
+
+function process (parentNode) {
+ var self = this;
+ return reduce.call(parentNode.childNodes, function (output, node) {
+ node = new Node(node);
+
+ var replacement = '';
+ if (node.nodeType === 3) {
+ replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue);
+ } else if (node.nodeType === 1) {
+ replacement = replacementForNode.call(self, node);
+ }
+
+ return join(output, replacement)
+ }, '')
+}
+
+/**
+ * Appends strings as each rule requires and trims the output
+ * @private
+ * @param {String} output The conversion output
+ * @returns A trimmed version of the ouput
+ * @type String
+ */
+
+function postProcess (output) {
+ var self = this;
+ this.rules.forEach(function (rule) {
+ if (typeof rule.append === 'function') {
+ output = join(output, rule.append(self.options));
+ }
+ });
+
+ return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '')
+}
+
+/**
+ * Converts an element node to its Markdown equivalent
+ * @private
+ * @param {HTMLElement} node The node to convert
+ * @returns A Markdown representation of the node
+ * @type String
+ */
+
+function replacementForNode (node) {
+ var rule = this.rules.forNode(node);
+ var content = process.call(this, node);
+ var whitespace = node.flankingWhitespace;
+ if (whitespace.leading || whitespace.trailing) content = content.trim();
+ return (
+ whitespace.leading +
+ rule.replacement(content, node, this.options) +
+ whitespace.trailing
+ )
+}
+
+/**
+ * Determines the new lines between the current output and the replacement
+ * @private
+ * @param {String} output The current conversion output
+ * @param {String} replacement The string to append to the output
+ * @returns The whitespace to separate the current output and the replacement
+ * @type String
+ */
+
+function separatingNewlines (output, replacement) {
+ var newlines = [
+ output.match(trailingNewLinesRegExp)[0],
+ replacement.match(leadingNewLinesRegExp)[0]
+ ].sort();
+ var maxNewlines = newlines[newlines.length - 1];
+ return maxNewlines.length < 2 ? maxNewlines : '\n\n'
+}
+
+function join (string1, string2) {
+ var separator = separatingNewlines(string1, string2);
+
+ // Remove trailing/leading newlines and replace with separator
+ string1 = string1.replace(trailingNewLinesRegExp, '');
+ string2 = string2.replace(leadingNewLinesRegExp, '');
+
+ return string1 + separator + string2
+}
+
+/**
+ * Determines whether an input can be converted
+ * @private
+ * @param {String|HTMLElement} input Describe this parameter
+ * @returns Describe what it returns
+ * @type String|Object|Array|Boolean|Number
+ */
+
+function canConvert (input) {
+ return (
+ input != null && (
+ typeof input === 'string' ||
+ (input.nodeType && (
+ input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11
+ ))
+ )
+ )
+}
+
+return TurndownService;
+
+}());
+
+
+module.exports = TurndownService;
\ No newline at end of file
diff --git a/src/vender/webdav.js b/src/vender/webdav.js
new file mode 100644
index 000000000..65c800536
--- /dev/null
+++ b/src/vender/webdav.js
@@ -0,0 +1,164 @@
+/* A simple WebDav implementation in JavaScript
+ https://github.com/aslakhellesoy/webdavjs @license MIT
+*/
+var WebDAV = {
+ GET: function(url, callback) {
+ return this.request('GET', url, {}, null, 'text', callback);
+ },
+
+ PROPFIND: function(url, callback) {
+ return this.request('PROPFIND', url, {
+ Depth: "1"
+ }, null, 'xml', callback);
+ },
+
+ MKCOL: function(url, callback) {
+ return this.request('MKCOL', url, {}, null, 'text', callback);
+ },
+
+ DELETE: function(url, callback) {
+ return this.request('DELETE', url, {}, null, 'text', callback);
+ },
+
+ PUT: function(url, data, callback) {
+ return this.request('PUT', url, {}, data, 'text', callback);
+ },
+
+ Author: function(user, password) {
+ this.user = user;
+ this.password = password;
+ },
+
+ request: function(verb, url, headers, data, type, callback) {
+ var xhr = new XMLHttpRequest();
+ var body = function() {
+ var b = xhr.responseText;
+ if (type == 'xml') {
+ var xml = xhr.responseXML;
+ if (xml) {
+ b = xml.firstChild.nextSibling ? xml.firstChild.nextSibling : xml.firstChild;
+ }
+ }
+ return b;
+ };
+
+ if (callback) {
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === XMLHttpRequest.DONE && verb == "PROPFIND") {
+ var b = body();
+ if (b) {
+ callback(b);
+ }
+ } else if (xhr.readyState === XMLHttpRequest.DONE) {
+ callback(xhr);
+ }
+ };
+ }
+ xhr.open(verb, url, !! callback);
+ xhr.setRequestHeader("Content-Type", "text/xml; charset=UTF-8");
+ this.user && this.password &&
+ xhr.setRequestHeader("Authorization", "Basic " + btoa(this.user + ":" + this.password))
+ for (var header in headers) {
+ xhr.setRequestHeader(header, headers[header]);
+ }
+ xhr.send(data);
+
+ if (!callback) {
+ return body();
+ }
+ }
+};
+
+// An Object-oriented API around WebDAV.
+WebDAV.Fs = function(rootUrl, user, password) {
+ WebDAV.Author(user, password);
+ this.rootUrl = rootUrl;
+ var fs = this;
+
+ this.file = function(href) {
+ this.type = 'file';
+
+ this.url = fs.urlFor(href);
+
+ this.name = fs.nameFor(this.url);
+
+ this.read = function(callback) {
+ return WebDAV.GET(this.url, callback);
+ };
+
+ this.write = function(data, callback) {
+ return WebDAV.PUT(this.url, data, callback);
+ };
+
+ this.rm = function(callback) {
+ return WebDAV.DELETE(this.url, callback);
+ };
+
+ return this;
+ };
+
+ this.dir = function(href) {
+ this.type = 'dir';
+
+ this.url = fs.urlFor(href);
+
+ this.name = fs.nameFor(this.url);
+
+ this.children = function(callback) {
+ var childrenFunc = function(doc) {
+ if (doc.childNodes == null) {
+ throw ('No such directory: ' + url);
+ }
+ var result = [];
+ // Start at 1, because the 0th is the same as self.
+ for (var i = 1; i < doc.childNodes.length; i++) {
+ var response = doc.childNodes[i];
+ var href = decodeURI( response.getElementsByTagName('d:href')[0].firstChild.nodeValue.replace(/\/$/, ''));
+ var propstat = response.getElementsByTagName('d:propstat')[0];
+ var prop = propstat.getElementsByTagName('d:prop')[0];
+ var resourcetype = prop.getElementsByTagName('d:resourcetype')[0];
+ var collection = resourcetype.getElementsByTagName('d:collection')[0];
+
+ if (collection) {
+ result[i - 1] = new fs.dir(href);
+ } else {
+ result[i - 1] = new fs.file(href);
+ }
+ }
+ return result;
+ };
+
+ if (callback) {
+ WebDAV.PROPFIND(this.url, function(doc) {
+ callback(childrenFunc(doc));
+ });
+ } else {
+ return childrenFunc(WebDAV.PROPFIND(this.url));
+ }
+ };
+
+ this.rm = function(callback) {
+ return WebDAV.DELETE(this.url, callback);
+ };
+
+ this.mkdir = function(callback) {
+ return WebDAV.MKCOL(this.url, callback);
+ };
+
+ return this;
+ };
+
+ this.urlFor = function(href) {
+ return (/^http/.test(href) ? href : this.rootUrl + href);
+ };
+
+ this.nameFor = function(url) {
+ return url.replace(/.*\/(.*)/, '$1');
+ };
+
+ return this;
+};
+
+if (typeof module !== 'undefined') {
+ module.exports = WebDAV;
+}
\ No newline at end of file
diff --git a/src/vender/wiz.js b/src/vender/wiz.js
new file mode 100644
index 000000000..6e2942ebd
--- /dev/null
+++ b/src/vender/wiz.js
@@ -0,0 +1,126 @@
+/**
+ * Soure from https://github.com/xcffl/WizWebClipperWE
+ */
+
+var Base64 = {
+ // private property
+ _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
+ // public method for encoding
+ encode : function(input) {
+ var output = "";
+ var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
+ var i = 0;
+
+ input = Base64._utf8_encode(input);
+
+ while (i < input.length) {
+
+ chr1 = input.charCodeAt(i++);
+ chr2 = input.charCodeAt(i++);
+ chr3 = input.charCodeAt(i++);
+
+ enc1 = chr1 >> 2;
+ enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+ enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+ enc4 = chr3 & 63;
+
+ if (isNaN(chr2)) {
+ enc3 = enc4 = 64;
+ } else if (isNaN(chr3)) {
+ enc4 = 64;
+ }
+ output = output + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
+ }
+
+ return output;
+ },
+ // private method for UTF-8 encoding
+ _utf8_encode : function(string) {
+ string = string.replace(/\r\n/g, "\n");
+ var utftext = "";
+ for (var n = 0; n < string.length; n++) {
+ var c = string.charCodeAt(n);
+
+ if (c < 128) {
+ utftext += String.fromCharCode(c);
+ } else if ((c > 127) && (c < 2048)) {
+ utftext += String.fromCharCode((c >> 6) | 192);
+ utftext += String.fromCharCode((c & 63) | 128);
+ } else {
+ utftext += String.fromCharCode((c >> 12) | 224);
+ utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+
+ }
+
+ return utftext;
+ }
+};
+
+var wiz_base64Encode = function( str ) {
+ var scriptFilter = function (html) {
+ return html.replace(/