Merge branch 'release/1.1.4'

This commit is contained in:
Kenshin 2020-01-20 12:13:14 +08:00
commit 633f63b8de
81 changed files with 3847 additions and 447 deletions

View File

@ -3,12 +3,12 @@
<p align="center">让你瞬间进入沉浸式阅读的扩展,还原阅读的本质,提升你的阅读体验。</p>
<p align="center">为了达到完美的阅读模式这个小目标 ,我适配了 <a target="_blank" href="https://simpread.ksria.cn/sites/">数百种类型</a> 的网站,因此诞生了简悦。</p>
<p align="center">
<a href="https://github.com/kenshin/simpread/releases"><img src="https://img.shields.io/badge/lastest_version-1.1.3-blue.svg"></a>
<a href="https://github.com/kenshin/simpread/releases"><img src="https://img.shields.io/badge/lastest_version-1.1.4-blue.svg"></a>
<a target="_blank" href="http://ksria.com/simpread"><img src="https://img.shields.io/badge/website-_simpread.ksria.com-1DBA90.svg"></a>
</p>
<p align="center">
<a target="_blank" href="https://chrome.google.com/webstore/detail/%E7%AE%80%E6%82%A6-simpread/ijllcpnolfcooahcekpamkbidhejabll"><img src="https://img.shields.io/badge/download-_chrome_webstore-brightgreen.svg"></a>
<a href="http://ksria.com/simpread/crx/1.1.3/simpread.crx"><img src="https://img.shields.io/badge/download-_crx-brightgreen.svg"></a>
<a href="http://ksria.com/simpread/crx/1.1.4/simpread.crx"><img src="https://img.shields.io/badge/download-_crx-brightgreen.svg"></a>
<a target="_blank" href="https://addons.mozilla.org/zh-CN/firefox/addon/simpread"><img src="https://img.shields.io/badge/download-_firefox_addon-DD512A.svg"></a>
<a target="_blank" href="https://greasyfork.org/zh-CN/scripts/39998"><img src="https://i.imgur.com/JFhxHeR.png"></a>
<a target="_blank" href="https://xteko.com/redir?url=http://sr.ksria.cn/jsbox/simpread-1.0.2.box?201810231502&name=%E7%AE%80%E6%82%A6"><img src="https://i.imgur.com/zZeOllB.png"></a>
@ -51,7 +51,7 @@
***
## 马上使用
* [Chrome 应用商店](https://chrome.google.com/webstore/detail/%E7%AE%80%E6%82%A6-simpread/ijllcpnolfcooahcekpamkbidhejabll) 或者 [离线下载](http://ksria.com/simpread/crx/1.1.3/simpread.crx)
* [Chrome 应用商店](https://chrome.google.com/webstore/detail/%E7%AE%80%E6%82%A6-simpread/ijllcpnolfcooahcekpamkbidhejabll) 或者 [离线下载](http://ksria.com/simpread/crx/1.1.4/simpread.crx)
* [Firefox 扩展中心](https://addons.mozilla.org/zh-CN/firefox/addon/simpread)
@ -84,7 +84,7 @@
* 支持 [论坛类页面及分页](http://ksria.com/simpread/docs/#/论坛类页面及分页) 如:知乎 · 百度贴吧等
* ![new纯色.png](https://i.loli.net/2018/09/05/5b8f718046acb.png) 支持 [代码段的高亮](http://ksria.com/simpread/docs/#/代码段的高亮),包含了大部分常见的网站
* ![new纯色.png](https://i.loli.net/2018/09/05/5b8f718046acb.png) 支持 [代码段的高亮](https://github.com/Kenshin/simpread/issues/500),包含了大部分常见的网站
* 支持 [TXT 阅读器](http://ksria.com/simpread/docs/#/TXT-阅读器) · 支持 [LaTeX 解析](http://ksria.com/simpread/docs/#/LaTeX-阅读器) · [Markdown 阅读器](http://ksria.com/simpread/docs/#/Markdown-阅读器)
@ -130,7 +130,7 @@
- 导出到 `Pocket` `Linnk` `Instapaper` 的功能,包括:`当前页面的链接` `稍后读`
- 导出到生产力工具,包括:`坚果云` `语雀` `Dropbox` `Onenote` `Google Drive` `印象笔记 / Evernote`,详细请看 [导出到生产力](http://ksria.com/simpread/docs/#/导出到生产力工具)
- 导出到生产力工具,包括:`坚果云` `语雀` `有道云笔记` `为知笔记` `Dropbox` `Notion` `Onenote` `Google Drive` `印象笔记 / Evernote`,详细请看 [导出到生产力](http://ksria.com/simpread/docs/#/导出到生产力工具)
- 同步 · 上传/下载 配置 · 同步适配列表 · [快捷键支持](http://ksria.com/simpread/docs/#/快捷键) 等;
@ -141,7 +141,7 @@
## 全部功能
<details>
<img src="http://sr.ksria.cn/feature%201.1.3.png">
<img src="http://sr.ksria.cn/feature%201.1.4.png">
</details>
## 截图
@ -234,20 +234,7 @@ _如发现下图显示不全请直接访问 http://sr.ksria.cn/zhifu_m2.png_
![支付](http://sr.ksria.cn/zhifu_m2.png)
## 简悦的诞生离不开它们
- [Node.js](https://nodejs.org/) · [NPM](https://www.npmjs.com)
- [Webpack](https://webpack.github.io/)
- [React](https://facebook.github.io/react)
- [ES6](http://es6-features.org/) · [Babel](https://babeljs.io)
- [PostCSS](http://postcss.org/) · [cssnext](http://cssnext.io/)
- [jQuery](https://jquery.com/) · [Mousetrap](https://craig.is/killing/mice) · [pangu.js](https://github.com/vinta/pangu.js) · [ProgressBar.js](https://kimmobrunfeldt.github.io/progressbar.js/) · [timego.js](http://timeago.org/) · [Velocity.js](http://velocityjs.org/) · [minimatch](https://github.com/isaacs/minimatch) · [to-markdown](https://github.com/domchristie/to-markdown) · [FileSaver.js](https://github.com/eligrey/FileSaver.js) · [dom-to-image](https://github.com/tsayen/dom-to-image) · [WebDAV]( https://github.com/aslakhellesoy/webdavjs)
- [Visual Studio Code](https://code.visualstudio.com/)
- [Sketch](https://www.sketchapp.com/) · [Pixelmator](http://www.pixelmator.com/)
- Icon from <http://iconfont.cn>
- [Welcome PuRead II](http://sr.ksria.cn/welcome-puread-ii.png) via [www.freepik.com](https://www.freepik.com/free-vector/it-specialists-upgrading-operating-system-illustration_4332393.htm)
- Mockup Design usage <http://magicmockups.com/>
- Material Design usage <https://material.io/guidelines/>
- Mind Maps <https://coggle.it/>
- 咖啡 · 网易音乐 · Google Chrome · rMBP
<http://ksria.com/simpread/docs/#/开源列表>
## 许可
[![license-badge]][license-link]
@ -255,11 +242,11 @@ _如发现下图显示不全请直接访问 http://sr.ksria.cn/zhifu_m2.png_
<!-- Link -->
[www-badge]: https://img.shields.io/badge/website-_simpread.ksria.com-1DBA90.svg
[www-link]: http://ksria.com/simpread
[version-badge]: https://img.shields.io/badge/lastest_version-1.1.3-blue.svg
[version-badge]: https://img.shields.io/badge/lastest_version-1.1.4-blue.svg
[version-link]: https://github.com/kenshin/simpread/releases
[chrome-badge]: https://img.shields.io/badge/download-_chrome_webstore-brightgreen.svg
[chrome-link]: https://chrome.google.com/webstore/detail/%E7%AE%80%E6%82%A6-simpread/ijllcpnolfcooahcekpamkbidhejabll
[offline-badge]: https://img.shields.io/badge/download-_crx-brightgreen.svg
[offline-link]: http://ksria.com/simpread/crx/1.1.3/simpread.crx
[offline-link]: http://ksria.com/simpread/crx/1.1.4/simpread.crx
[license-badge]: https://img.shields.io/github/license/mashape/apistatus.svg
[license-link]: https://opensource.org/licenses/MIT

View File

@ -37,6 +37,68 @@ a {
text-decoration: none;
}
input, textarea {
font-family: Raleway, Menlo, "Dank Mono", Inconsolata, "Operator Mono", Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", "Courier New", Courier, monospace!important;
}
.loadingbar {
position: fixed;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
background-color: #fafafa;
z-index: 200;
}
.animated {
animation-duration: 1s;
animation-fill-mode: both;
animation-iteration-count: infinite;
}
.heartBeat {
animation-name: heartBeat;
animation-duration: 1.3s;
animation-timing-function: ease-in-out;
}
@keyframes heartBeat {
0% {
transform: scale(1);
}
14% {
transform: scale(1.3);
}
28% {
transform: scale(1);
}
42% {
transform: scale(1.3);
}
70% {
transform: scale(1);
}
}
.topnav {
position: fixed;
z-index: 200;
left: 12px;
top: 12px;
}
.header {
display: flex;
align-items: center;
@ -140,6 +202,9 @@ a {
color: var(--secondary-color);
font-size: 1.3rem;
opacity: 1;
transition: all .25s ease-out;
}
.welcome {
@ -160,6 +225,12 @@ a {
z-index: 3;
}
.dividers {
margin: 10px 0;
width: 100%;
border-bottom: 1px solid rgba(0,0,0,.12);
}
/**
* Labs style
*/
@ -396,7 +467,7 @@ card-empty a {
* Notice bubbles
*/
.bubbles {
position: fixed;
position: fixed!important;
bottom: 20px;
display: flex;
@ -414,10 +485,11 @@ card-empty a {
cursor: pointer;
transition: all 500ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;
overflow: initial;
}
.bubbles.notice {
right: 94px;
right: 164px;
background-color: #16666f;
}
@ -462,7 +534,7 @@ card-empty a {
* Help bubbles
*/
.bubbles.help {
right: 24px;
right: 94px;
background-color: #607D8B;
}
@ -661,3 +733,237 @@ guid-card-tips span {
font-size: 30px;
letter-spacing: .6em;
}
/**
* Feedback bubbles
*/
.bubbles.feedback {
right: 24px;
background-color: #fb7756;
}
.feedback:hover {
background-color: rgba(251, 119, 86, .8);
}
/**
* URL Scheme source form simpread.css
*/
.simpread-urlscheme,
.simpread-feedback {
position: fixed;
right: 20px;
bottom: 20px;
z-index: 2147483646;
}
simpread-urlscheme,
simpread-feedback {
display: flex;
justify-content: center;
align-items: flex-start;
flex-direction: column;
padding: 20px 20px 0;
width: 500px;
color: rgba(51, 51, 51, .87);
background-color: #fff;
border-radius: 3px;
box-shadow: rgba(0, 0, 0, 0.12) 0px 0px 2px, rgba(0, 0, 0, 0.26) 0px 2px 2px;
overflow: hidden;
transform-origin: bottom;
transition: all .6s ease;
}
simpread-urlscheme *,
simpread-feedback * {
font-size: 12px!important;
box-sizing: border-box;
}
simpread-urlscheme.active,
simpread-feedback.active {
animation-name: srFadeInUp;
animation-duration: 450ms;
animation-fill-mode: both;
}
simpread-urlscheme.hide,
simpread-feedback.hide {
animation-name: srFadeInDown;
animation-duration: 450ms;
animation-fill-mode: both;
}
simpread-urlscheme sr-urls-label,
simpread-feedback sr-fb-label {
width: 100%;
}
simpread-urlscheme sr-urls-head,
simpread-feedback sr-fb-head {
display: flex;
align-items: center;
flex-direction: row;
margin-bottom: 5px;
width: 100%;
}
simpread-urlscheme sr-urls-content,
simpread-feedback sr-fb-content {
margin-bottom: 5px;
width: 100%;
}
simpread-urlscheme sr-urls-footer,
simpread-feedback sr-urls-footer {
display: flex;
justify-content: flex-end;
width: 100%;
}
simpread-urlscheme sr-urls-a,
simpread-feedback sr-fb-a {
color: #2163f7;
cursor: pointer;
}
simpread-urlscheme text-field-state,
simpread-feedback text-field-state {
border-top: none rgba(34, 101, 247, 0.8)!important;
border-left: none rgba(34, 101, 247, 0.8)!important;
border-right: none rgba(34, 101, 247, 0.8)!important;
border-bottom: 2px solid rgba(34, 101, 247, 0.8)!important;
}
simpread-urlscheme switch,
simpread-feedback switch {
margin-top: 0!important;
}
@keyframes srFadeInUp {
from {
opacity: 0;
transform: translateY(100px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes srFadeInDown {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(100px);
}
}
/**
* Feeback
*/
simpread-feedback sr-fb-head {
font-weight: bold;
}
simpread-feedback sr-fb-content {
display: flex;
flex-direction: column;
}
simpread-feedback sr-fb-footer {
display: flex;
flex-direction: row;
justify-content: flex-end;
width: 100%;
}
/**
* Feeback: stars
*/
simpread-feedback sr-close {
position: absolute;
right: 20px;
cursor: pointer;
transition: all 1000ms cubic-bezier(0.23, 1, 0.32, 1) 100ms;
z-index: 200;
}
simpread-feedback sr-close:hover {
transform: rotate(-15deg) scale(1.3);
}
simpread-feedback sr-stars {
display: flex;
flex-direction: row;
justify-content: center;
margin-top: 10px;
}
simpread-feedback sr-stars {
display: flex;
flex-direction: row;
justify-content: center;
margin-top: 10px;
}
simpread-feedback sr-stars i {
margin-right: 10px;
cursor: pointer;
}
simpread-feedback sr-stars i svg {
transition: all 1000ms cubic-bezier(0.23, 1, 0.32, 1) 100ms;
}
simpread-feedback sr-stars i svg:hover {
transform: rotate(-15deg) scale(1.3);
}
simpread-feedback sr-stars i.active svg {
transform: rotate(0) scale(1);
}
simpread-feedback sr-emojis {
display: block;
height: 100px;
overflow: hidden;
}
simpread-feedback sr-emoji {
display: flex;
flex-direction: column;
align-items: center;
transition: .3s;
}
simpread-feedback sr-emoji > svg {
margin: 15px 0;
width: 70px;
height: 70px;
flex-shrink: 0;
}
simpread-feedback sr-stars-footer {
display: flex;
justify-content: center;
margin: 10px 0 20px 0;
}

View File

@ -24,6 +24,10 @@ sr-opt-gp {
font-size: 15px;
}
sr-opt-gp textarea, sr-opt-gp input {
font-family: Inconsolata, "Operator Mono", Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", "Courier New", Courier, monospace!important;
}
sr-opt-gp sr-opt-label {
display: block;
position: absolute;
@ -66,12 +70,12 @@ sr-opt-theme {
box-sizing: border-box;
opacity: 1;
transition: all 500ms opacity 1s cubic-bezier(0.23, 1, 0.32, 1) 0ms;
transition: all 500ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;
}
sr-opt-theme:hover {
opacity: .2;
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14),0 1px 5px 0 rgba(0,0,0,0.12),0 3px 1px -2px rgba(0,0,0,0.2);
transform: translateY(-1px);
box-shadow: 0 5px 10px rgba(0,0,0,.2);
}
sr-opt-theme:not(:first-child) {
@ -79,5 +83,6 @@ sr-opt-theme:not(:first-child) {
}
sr-opt-theme[sr-type="active"] {
box-shadow: 0 3px 3px 0 rgba(0,0,0,0.14),0 2px 20px 0 rgba(0,0,0,0.12),0 3px 1px -2px rgba(0,0,0,0.7);
box-shadow: 0 5px 10px rgba(0,0,0,.2);
border: none;
}

View File

@ -1,5 +1,5 @@
/**
* SimpRead
* SimpRead: Read mode
*/
.simpread-font {
@ -16,47 +16,10 @@
display: none;
}
/**
* Focus: Background( root ) style
*/
.simpread-focus-root {
display: block;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba( 235, 235, 235, 0.9 );
z-index: 2147483645;
opacity: 0;
transition : opacity 1s cubic-bezier(0.23, 1, 0.32, 1) 0ms;
}
.simpread-focus-highlight {
position: relative;
box-shadow: 0 0 0 20px #fff;
background-color: #fff;
overflow: visible;
z-index: 2147483646;
}
.sr-controlbar-bg sr-rd-crlbar {
z-index: 2147483647;
}
.sr-controlbar-bg sr-rd-crlbar fab {
z-index: 2147483647;
}
/**
* Read: background( root ) style
*/
.simpread-read-root {
.simpread-read-root {
display: -webkit-flex;
justify-content:center;
align-items:center;
@ -216,6 +179,67 @@ sr-rd-footer a:active {
border-bottom: 1px dotted!important;
}
/**
* Special blocks
*/
.simpread-blocks {
text-decoration: none!important;
}
.simpread-blocks * {
margin: 0;
}
.simpread-blocks a {
padding: 0;
text-decoration: none!important;
}
.simpread-blocks img {
margin: 0;
padding: 0;
border: 0;
background: transparent;
box-shadow: none;
}
/**
* Focus: Background( root ) style
*/
.simpread-focus-root {
display: block;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba( 235, 235, 235, 0.9 );
z-index: 2147483645;
opacity: 0;
transition : opacity 1s cubic-bezier(0.23, 1, 0.32, 1) 0ms;
}
.simpread-focus-highlight {
position: relative;
box-shadow: 0 0 0 20px #fff;
background-color: #fff;
overflow: visible;
z-index: 2147483646;
}
.sr-controlbar-bg sr-rd-crlbar {
z-index: 2147483647;
}
.sr-controlbar-bg sr-rd-crlbar fab {
z-index: 2147483647;
}
/**
* Controlbar: focus mode and read mode
*/
@ -278,8 +302,8 @@ sr-rd-crlbar.controlbar:hover {
transition: opacity .5s ease !important;
}
simpread-highlight {
simpread-highlight,
sr-snapshot-ctlbar {
position: fixed;
top: 0;
@ -297,6 +321,7 @@ simpread-highlight {
background-color: rgba(50, 50, 50, .9);
box-shadow: 0 2px 5px rgba(0, 0, 0, .26);
box-sizing: border-box;
z-index: 2147483640;
}
@ -497,7 +522,7 @@ kbd-mapping {
flex-flow: row;
width: 500px;
height: 590px;
height: 625px;
background-color: #fff;
@ -644,7 +669,7 @@ sharecard-content {
max-height: 500px;
font-size: 20px;
text-align: left;
text-align: justify;
background-color: rgb(33, 150, 243);
@ -705,4 +730,249 @@ sharecard-control {
height: 80px;
background-color: #fff;
}
/**
* Snapshot
*/
simpread-snapshot {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
cursor: move;
z-index: 2147483645;
}
sr-mask {
position: fixed;
left: 0;
top: 0;
background-color: rgba(0, 0, 0, .1);
}
/**
* URL Scheme
*/
.simpread-urlscheme,
.simpread-feedback {
position: fixed;
right: 20px;
bottom: 20px;
z-index: 2147483646;
}
simpread-urlscheme,
simpread-feedback {
display: flex;
justify-content: center;
align-items: flex-start;
flex-direction: column;
padding: 20px 20px 0;
width: 500px;
color: rgba(51, 51, 51, .87);
background-color: #fff;
border-radius: 3px;
box-shadow: rgba(0, 0, 0, 0.12) 0px 0px 2px, rgba(0, 0, 0, 0.26) 0px 2px 2px;
overflow: hidden;
transform-origin: bottom;
transition: all .6s ease;
}
simpread-urlscheme *,
simpread-feedback * {
font-size: 12px!important;
box-sizing: border-box;
}
simpread-urlscheme.active,
simpread-feedback.active {
animation-name: srFadeInUp;
animation-duration: 450ms;
animation-fill-mode: both;
}
simpread-urlscheme.hide,
simpread-feedback.hide {
animation-name: srFadeInDown;
animation-duration: 450ms;
animation-fill-mode: both;
}
simpread-urlscheme sr-urls-label,
simpread-feedback sr-fb-label {
width: 100%;
}
simpread-urlscheme sr-urls-head,
simpread-feedback sr-fb-head {
display: flex;
align-items: center;
flex-direction: row;
margin-bottom: 5px;
width: 100%;
}
simpread-urlscheme sr-urls-content,
simpread-feedback sr-fb-content {
margin-bottom: 5px;
width: 100%;
}
simpread-urlscheme sr-urls-footer,
simpread-feedback sr-urls-footer {
display: flex;
justify-content: flex-end;
width: 100%;
}
simpread-urlscheme sr-urls-a,
simpread-feedback sr-fb-a {
color: #2163f7;
cursor: pointer;
}
simpread-urlscheme text-field-state,
simpread-feedback text-field-state {
border-top: none rgba(34, 101, 247, 0.8)!important;
border-left: none rgba(34, 101, 247, 0.8)!important;
border-right: none rgba(34, 101, 247, 0.8)!important;
border-bottom: 2px solid rgba(34, 101, 247, 0.8)!important;
}
simpread-urlscheme switch,
simpread-feedback switch {
margin-top: 0!important;
}
@keyframes srFadeInUp {
from {
opacity: 0;
transform: translateY(100px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes srFadeInDown {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(100px);
}
}
/**
* Feeback
*/
simpread-feedback sr-fb-head {
font-weight: bold;
}
simpread-feedback sr-fb-content {
display: flex;
flex-direction: column;
}
simpread-feedback sr-fb-footer {
display: flex;
flex-direction: row;
justify-content: flex-end;
width: 100%;
}
/**
* Feeback: stars
*/
simpread-feedback sr-close {
position: absolute;
right: 20px;
cursor: pointer;
transition: all 1000ms cubic-bezier(0.23, 1, 0.32, 1) 100ms;
z-index: 200;
}
simpread-feedback sr-close:hover {
transform: rotate(-15deg) scale(1.3);
}
simpread-feedback sr-stars {
display: flex;
flex-direction: row;
justify-content: center;
margin-top: 10px;
}
simpread-feedback sr-stars {
display: flex;
flex-direction: row;
justify-content: center;
margin-top: 10px;
}
simpread-feedback sr-stars i {
margin-right: 10px;
cursor: pointer;
}
simpread-feedback sr-stars i svg {
transition: all 1000ms cubic-bezier(0.23, 1, 0.32, 1) 100ms;
}
simpread-feedback sr-stars i svg:hover {
transform: rotate(-15deg) scale(1.3);
}
simpread-feedback sr-stars i.active svg {
transform: rotate(0) scale(1);
}
simpread-feedback sr-emojis {
display: block;
height: 100px;
overflow: hidden;
}
simpread-feedback sr-emoji {
display: flex;
flex-direction: column;
align-items: center;
transition: .3s;
}
simpread-feedback sr-emoji > svg {
margin: 15px 0;
width: 70px;
height: 70px;
flex-shrink: 0;
}
simpread-feedback sr-stars-footer {
display: flex;
justify-content: center;
margin: 10px 0 20px 0;
}

View File

@ -28,7 +28,7 @@ sr-rd-content {
}
sr-rd-desc {
text-align: left;
text-align: justify;
line-height: 2.4;
margin: 0 0 1.2em 0;
}
@ -65,7 +65,7 @@ sr-rd-content a {
sr-rd-content a, sr-rd-content a:link {
color: inherit;
font-size: initial;
font-size: inherit;
font-weight: inherit;
border:none;
}
@ -77,11 +77,19 @@ sr-rd-content a:hover {
sr-rd-content img {
margin: 10px;
padding: 5px;
max-width: 100%;
background: #fff;
border: 1px solid #bbb;
box-shadow: 1px 1px 3px #d4d4d4;
}
sr-rd-content figcaption {
text-align: center;
font-size: 14px;
}
sr-rd-content sr-blockquote {
display: block;
position: relative;

View File

@ -0,0 +1,181 @@
/**
* Mobile media
*/
@media (pointer:coarse) {
sr-read {
margin: 20px 5%!important;
min-width: initial!important;
max-width: 90%!important;
}
sr-rd-title {
margin-top: 0;
font-size: 2.7rem;
}
sr-rd-desc,
sr-rd-content sr-blockquote {
margin: 10 0!important;
padding: 0 0 0 10px !important;
width: 90%;
font-size: 1.8rem;
font-style: normal;
line-height: 1.7;
text-align: justify;
}
sr-rd-content {
font-size: 1.75rem;
font-weight: 300;
}
sr-rd-content figure {
margin: 0;
padding: 0;
text-align: center;
}
sr-rd-content a, sr-rd-content a:link {
font-size: inherit;
}
sr-rd-content li code, sr-rd-content p code {
font-size: inherit;
}
sr-rd-footer {
margin-top: 20px;
}
sr-blockquote, sr-blockquote * {
margin: 5px !important;
padding: 5px !important;
}
sr-rd-title, sr-rd-content h1, sr-rd-content h2, sr-rd-content h3, sr-rd-content h4, sr-rd-content h5, sr-rd-content h6 {
font-family: PingFang SC, Verdana, Helvetica Neue, Microsoft Yahei, Hiragino Sans GB, Microsoft Sans Serif, WenQuanYi Micro Hei, sans-serif;
color: #000;
font-weight: 100;
line-height: 1.35;
}
sr-rd-content h1, sr-rd-content h2, sr-rd-content h3, sr-rd-content h4, sr-rd-content h5, sr-rd-content h6,
sr-rd-content-h1, sr-rd-content-h2, sr-rd-content-h3, sr-rd-content-h4, sr-rd-content-h5, sr-rd-content-h6 {
margin-top: 1.2em;
margin-bottom: 0.6em;
line-height: 1.35;
}
sr-rd-content h1, sr-rd-content-h1 {
font-size: 1.8em;
}
sr-rd-content h2, sr-rd-content-h2 {
font-size: 1.6em;
}
sr-rd-content h3, sr-rd-content-h3 {
font-size: 1.4em;
}
sr-rd-content h4, sr-rd-content-h4 {
font-size: 1.2em;
}
sr-rd-content h5, sr-rd-content h6, sr-rd-content-h5, sr-rd-content-h6 {
font-size: 1.2em;
}
sr-rd-content ul, sr-rd-content-ul {
margin-left: 1.3em!important;
list-style: disc;
}
sr-rd-content ol, sr-rd-content-ol {
list-style: decimal;
margin-left: 1.9em!important;
}
sr-rd-content li ul, sr-rd-content li ol, sr-rd-content-ul ul, sr-rd-content-ul ol, sr-rd-content-ol ul, sr-rd-content-ol ol {
margin-bottom: 0.8em;
margin-left: 2em!important;;
}
sr-rd-content img {
margin: 0;
padding: 0;
border: 0;
max-width: 100%!important;
height: auto;
box-shadow: 0 20px 20px -10px rgba(0,0,0,0.1);
}
sr-rd-mult {
min-width: initial;
background-color: #fff;
box-shadow: 0 1px 6px rgba(32, 33, 36, 0.28);
border-radius: 8px;
}
sr-rd-mult sr-rd-mult-avatar div {
margin: 0;
}
sr-rd-mult sr-rd-mult-avatar .sr-rd-content-center-small {
margin: 7px 0!important;
}
sr-rd-mult sr-rd-mult-avatar span {
display: block;
}
sr-rd-mult sr-rd-mult-content {
padding-left: 0;
}
/**
* iPad pro 12 and below
*/
@media only screen and (max-device-width: 1024px) {
html, .simpread-theme-root {
font-size: 80%!important;
}
sr-rd-mult sr-rd-mult-avatar img {
width: 50px;
height: 50px;
min-width: 50px;
min-height: 50px;
}
}
/**
* iPhone XS Max and below
*/
@media only screen and (max-device-width: 414px) {
html, .simpread-theme-root {
font-size: 70%!important;
}
sr-rd-mult sr-rd-mult-avatar img {
width: 30px;
height: 30px;
min-width: 30px;
min-height: 30px;
}
}
/**
* iPhone SE and below
*/
@media only screen and (max-device-width: 320px) {
html, .simpread-theme-root {
font-size: 90%!important;
}
sr-rd-content p {
margin-bottom: .5em;
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 374 B

After

Width:  |  Height:  |  Size: 343 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

View File

@ -8,7 +8,9 @@ import * as ver from 'version';
import * as menu from 'menu';
import * as watch from 'watch';
import * as WebDAV from 'webdav';
import * as permission
from 'permission';
import * as tips from 'tips';
import PureRead from 'puread';
// global update site tab id
@ -64,6 +66,7 @@ function getNewsitesHandler( result ) {
*/
menu.OnClicked( ( info, tab ) => {
console.log( "background contentmenu Listener", info, tab );
tracked({ eventCategory: "menu", eventAction: "menu", eventValue: info.menuItemId });
if ( info.menuItemId == "link" ) {
info.linkUrl && browser.tabs.create({ url: info.linkUrl + "?simpread_mode=read" });
} else if ( info.menuItemId == "list" ) {
@ -76,6 +79,8 @@ menu.OnClicked( ( info, tab ) => {
browser.tabs.sendMessage( tab.id, msg.Add( msg.MESSAGE_ACTION.menu_blacklist, {url: info.pageUrl } ));
} else if ( info.menuItemId == "unrdist" ) {
browser.tabs.sendMessage( tab.id, msg.Add( msg.MESSAGE_ACTION.menu_unrdist, {url: info.pageUrl } ));
} else if ( info.menuItemId == "lazyload" ) {
browser.tabs.sendMessage( tab.id, msg.Add( msg.MESSAGE_ACTION.menu_lazyload, {url: info.pageUrl } ));
} else {
if ( !tab.url.startsWith( "chrome://" ) ) browser.tabs.sendMessage( tab.id, msg.Add(info.menuItemId));
}
@ -144,7 +149,76 @@ browser.runtime.onMessage.addListener( function( request, sender, sendResponse )
});
/**
* Listen runtime message, include: `shortcuts` `browser_action`
* Listen runtime message, include: `download`, `base64` && `permission`
*/
browser.runtime.onMessage.addListener( function( request, sender, sendResponse ) {
if ( request.type == msg.MESSAGE_ACTION.download ) {
const { data, name } = request.value;
const blob = new Blob([data], {
type: "html/plain;charset=utf-8"
});
const url = URL.createObjectURL(blob);
browser.downloads.download({
url : url,
filename: name.replace( /[|]/ig, "" ),
}, downloadId => {
sendResponse({ done: downloadId });
});
} else if ( request.type == msg.MESSAGE_ACTION.base64 ) {
const { url } = request.value;
fetch( url )
.then( response => response.blob() )
.then( blob => new Promise(( resolve, reject ) => {
const reader = new FileReader()
reader.onloadend = event => {
sendResponse({ done: { url, uri: event.target.result }});
};
reader.onerror = error => {
sendResponse({ fail: { error, url } });
};
reader.readAsDataURL( blob );
}))
.catch( error => {
sendResponse({ fail: { error, url } });
});
} else if ( request.type == msg.MESSAGE_ACTION.permission ) {
permission.Get({ permissions: [ "downloads" ] }, result => {
sendResponse({ done: result });
});
}
return true;
});
/**
* Listen runtime message, include: `snapshot`
*/
browser.runtime.onMessage.addListener( function( request, sender, sendResponse ) {
if ( request.type == msg.MESSAGE_ACTION.snapshot ) {
const { left, top, width, height } = request.value;
chrome.tabs.captureVisibleTab( { format: "png" }, base64 => {
const image = new Image();
image.src = base64;
image.onload = () => {
const canvas = document.createElement( "canvas" ),
ctx = canvas.getContext( "2d" ),
dpi = window.devicePixelRatio,
sx = left * dpi,
sy = top * dpi,
sWidth = width * dpi,
sHeight = height * dpi;
canvas.width = sWidth;
canvas.height = sHeight;
ctx.drawImage( image, sx, sy, sWidth, height * dpi, 0, 0, sWidth, sHeight );
const uri = canvas.toDataURL( "image/png" );
sendResponse({ done: uri });
};
});
}
return true;
});
/**
* Listen runtime message
*/
browser.runtime.onMessage.addListener( function( request, sender, sendResponse ) {
console.log( "background runtime Listener", request );
@ -218,6 +292,12 @@ browser.runtime.onMessage.addListener( function( request, sender, sendResponse )
case msg.MESSAGE_ACTION.speak_stop:
browser.tts.stop();
break;
case msg.MESSAGE_ACTION.tips:
tips.Verify( request.value.code, sendResponse );
break;
case msg.MESSAGE_ACTION.tips_norepeat:
tips.Done( request.value.code );
break;
}
});
@ -333,27 +413,9 @@ function setMenuAndIcon( id, code ) {
*
* @param {object} google analytics track object
*/
function tracked({ eventCategory, eventAction, eventLabel }) {
console.log( "current track is", eventCategory, eventAction, eventLabel )
ga( 'send', {
hitType : 'event',
eventCategory,
eventAction,
eventLabel
});
}
/**
* Google analytics
*/
analytics();
function analytics() {
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-405976-12', 'auto');
ga('send', 'pageview');
function tracked({ eventCategory, eventAction, eventValue }) {
console.log( "current track is", eventCategory, eventAction, eventValue )
_gaq.push([ '_trackEvent', eventCategory, eventValue ]);
}
/**
@ -361,4 +423,5 @@ function analytics() {
*/
function uninstall() {
browser.runtime.setUninstallURL( storage.option.uninstall ? storage.service + "/uninstall" : "" );
tracked({ eventCategory: "install", eventAction: "install", eventValue: "uninstall" });
}

View File

@ -3,7 +3,6 @@ console.log( "=== simpread contentscripts load ===" )
import './assets/css/simpread.css';
import './assets/css/setting.css';
import 'notify_css';
import 'mintooltip';
import Velocity from 'velocity';
import Notify from 'notify';
@ -13,6 +12,7 @@ import * as read from 'read';
import * as setting from 'setting';
import * as kbd from 'keyboard';
import * as highlight from 'highlight';
import * as scheme from 'urlscheme';
import * as util from 'util';
import { storage, STORAGE_MODE as mode } from 'storage';
@ -46,7 +46,7 @@ storage.Read( () => {
});
} else {
bindShortcuts();
preload() && autoOpen();
!isLazyload() && autoOpen();
}
});
@ -56,49 +56,19 @@ storage.Read( () => {
* @return {boolean} true: is blacklist; false: is't blacklist
*/
function blacklist() {
for ( const item of storage.option.blacklist ) {
if ( item.trim() != "" && !item.startsWith( "http" ) ) {
if ( location.hostname.includes( item ) ) {
is_blacklist = true;
break;
}
} else {
if ( location.href == item ) {
is_blacklist = true;
break;
}
}
}
is_blacklist = util.Blacklist( puplugin.Plugin( "minimatch" ), storage.option );
console.log( "current site is blacklist", is_blacklist )
return is_blacklist;
}
/**
* Preload verify
* isLazyload verify
*
* @return {boolen}
* @return {boolen} true: lazyload; false: preload
*/
function preload() {
let is_proload = true;
if ( storage.option.preload == false ) {
is_proload = false;
} else if ( storage.option.preload ) {
for ( const item of storage.option.lazyload ) {
if ( item.trim() != "" && !item.startsWith( "http" ) ) {
if ( location.hostname.includes( item ) ) {
is_proload = false;
break;
}
} else {
if ( location.href == item ) {
is_proload = false;
break;
}
}
}
}
return is_proload;
function isLazyload() {
return util.Lazyload( puplugin.Plugin( "minimatch" ), storage.option );
}
/**
@ -116,7 +86,7 @@ browser.runtime.onMessage.addListener( function( request, sender, sendResponse )
bindShortcuts();
break;
case msg.MESSAGE_ACTION.tab_selected:
if ( preload() == false ) {
if ( isLazyload() ) {
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.browser_action, { code: 0 , url: window.location.href } ));
} else browserAction( request.value.is_update );
break;
@ -144,25 +114,37 @@ browser.runtime.onMessage.addListener( function( request, sender, sendResponse )
case msg.MESSAGE_ACTION.menu_whitelist:
case msg.MESSAGE_ACTION.menu_exclusion:
case msg.MESSAGE_ACTION.menu_blacklist:
case msg.MESSAGE_ACTION.menu_lazyload:
case msg.MESSAGE_ACTION.menu_unrdist:
if ( request.type == msg.MESSAGE_ACTION.menu_whitelist ) {
storage.read.whitelist.push( request.value.url );
new Notify().Render( "已加入到白名单。" );
} else if ( request.type == msg.MESSAGE_ACTION.menu_exclusion ) {
storage.read.exclusion.push( request.value.url );
new Notify().Render( "已加入到排除列表。" );
} else if ( request.type == msg.MESSAGE_ACTION.menu_blacklist ) {
storage.option.blacklist.push( request.value.url );
new Notify().Render( "已加入到黑名单。" );
} else if ( request.type == msg.MESSAGE_ACTION.menu_unrdist ) {
storage.UnRead( "add", { url: request.value.url, title: $("head").find("title").text() , desc: "" }, success => {
success && new Notify().Render( 0, "成功加入未读列表。" );
!success && new Notify().Render( 0, "已加入未读列表,请勿重新加入。" );
const menuSrv = ( type, url ) => {
if ( type == msg.MESSAGE_ACTION.menu_whitelist ) {
storage.read.whitelist.push( url );
new Notify().Render( "已加入到白名单。" );
} else if ( type == msg.MESSAGE_ACTION.menu_exclusion ) {
storage.read.exclusion.push( url );
new Notify().Render( "已加入到排除列表。" );
} else if ( type == msg.MESSAGE_ACTION.menu_blacklist ) {
storage.option.blacklist.push( url );
new Notify().Render( "已加入到黑名单。" );
} else if ( type == msg.MESSAGE_ACTION.menu_lazyload ) {
storage.option.lazyload.push( url );
new Notify().Render( "已加入到延迟加载。" );
} else if ( type == msg.MESSAGE_ACTION.menu_unrdist ) {
storage.UnRead( "add", util.GetPageInfo(), success => {
success && new Notify().Render( 0, "成功加入未读列表。" );
!success && new Notify().Render( 0, "已加入未读列表,请勿重新加入。" );
});
}
storage.Write( () => {
watch.SendMessage( "option", true );
});
}
storage.Write( () => {
watch.SendMessage( "option", true );
});
};
if ( storage.option.urlscheme && /whitelist|exclusion|blacklist|lazyload/ig.test( request.type )) {
scheme.Render( request.type.replace( "menu_", "" ), storage.option.urlscheme, ( type, off, value ) => {
storage.option.urlscheme = off;
menuSrv( "menu_" + type, value );
});
} else menuSrv( request.type, request.value.url );
break;
}
});
@ -250,13 +232,21 @@ function readMode() {
}
/**
* Auto open read mode
* Auto open read mode, include:
*
* - http://xxxx?simpread_mode=read
* - auto && location.href not include exclusion list
* - location.href include white list
*/
function autoOpen() {
getCurrent( mode.read );
if ( window.location.href.includes( "simpread_mode=read" ) ||
( storage.current.auto && util.Exclusion( puplugin.Plugin( "minimatch" ), storage.current )) ||
( !storage.current.auto && util.Whitelist( puplugin.Plugin( "minimatch" ), storage.current ))
const suffix = window.location.href.includes( "simpread_mode=read" ),
auto = storage.current.auto,
minimatch = puplugin.Plugin( "minimatch" ),
whitelist = util.Whitelist( minimatch, storage.current ),
exclusion = util.Exclusion( minimatch, storage.current );
if (
suffix || whitelist || ( auto && exclusion == false )
) {
switch ( storage.current.site.name ) {
case "my.oschina.net":
@ -275,6 +265,7 @@ function autoOpen() {
break;
default:
pr.state == "adapter" && readMode();
pr.state == "temp" && pr.current.site.html != "" && whitelist && readMode();
break;
}
}

View File

@ -33,6 +33,13 @@ class FControl extends React.Component {
});
}
onClose() {
setTimeout( ()=> {
$( "fab-bg" ).css({ width: '100px' })
$( "fab" ).find( "ul[type=hori]" ).css({ opacity: 0, visibility: "hidden" })
}, 200 );
}
onAction( event, type ) {
console.log( "fab type is =", type )
@ -46,9 +53,11 @@ class FControl extends React.Component {
break;
case "setting":
setting.Render( ()=>setTimeout( ()=>se.Render(), 500 ));
this.onClose();
break;
case "siteeditor":
se.Render();
this.onClose();
break;
case "remove":
new Notify().Render( "移动鼠标选择不想显示的内容,只针对本次有效。" );
@ -65,7 +74,7 @@ class FControl extends React.Component {
break;
default:
if ( type.indexOf( "_" ) > 0 && type.startsWith( "share" ) ||
[ "save", "markdown", "png", "epub", "pdf", "kindle", "temp", "html", "dropbox", "pocket", "instapaper", "linnk", "yinxiang","evernote", "onenote", "gdrive" ].includes( type )) {
[ "save", "markdown", "offlinemarkdown", "png", "epub", "pdf", "kindle", "temp", "bear", "ulysses", "html", "offlinehtml", "dropbox", "pocket", "instapaper", "linnk", "yinxiang","evernote", "onenote", "gdrive", "jianguo", "yuque", "notion", "youdao", "weizhi" ].includes( type )) {
const [ title, desc, content ] = [ $( "head title" ).text().trim(), "", $( ".simpread-focus-highlight" ).html().trim() ];
output.Action( type, title, desc, content );
}

View File

@ -6,6 +6,8 @@ var storage = require( "storage" ).storage,
fcontrol = require( "controlbar" ),
tooltip = require( "tooltip" ),
waves = require( "waves" ),
browser = require( "browser" ).browser,
msg = require( "message" ),
focus = ( function () {
var $parent,
@ -67,6 +69,7 @@ var storage = require( "storage" ).storage,
tooltip.Render( bgclsjq );
waves.Render({ root: bgclsjq });
storage.Statistics( "focus" );
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.track, { eventCategory: "mode", eventAction: "focusmode", eventValue: "focusmode" }) );
// click mask remove it
$( bgclsjq ).on( "click", function( event, data ) {

22
src/ga.js Normal file
View File

@ -0,0 +1,22 @@
/**
* Track using the asynchronous tracking API.
*
* See http://code.google.com/apis/analytics/docs/tracking/asyncTracking.html
* for information on how to use the asynchronous tracking API.
* _gaq.push(['_trackEvent', e.target.id, 'clicked']);
*/
var _AnalyticsCode = 'UA-405976-14';
var _gaq = _gaq || [];
_gaq.push(['_setAccount', _AnalyticsCode]);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = 'https://ssl.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

View File

@ -1,7 +1,7 @@
{
"name" : "__MSG_extension_name__",
"default_locale" : "en",
"version" : "1.1.3",
"version" : "1.1.4",
"short_name" : "SimpRead",
"description" : "__MSG_extension_desc__",
"homepage_url" : "http://ksria.com/simpread",
@ -15,10 +15,12 @@
"contextMenus",
"tabs",
"storage",
"tts"
"tts",
"<all_urls>"
],
"optional_permissions": [ "cookies", "https://*.youdao.com/", "downloads" ],
"background": {
"scripts" : [ "/bundle/common.js", "/bundle/background.js" ]
"scripts" : [ "/ga.js", "/bundle/common.js", "/bundle/background.js" ]
},
"content_scripts" : [
{
@ -40,10 +42,11 @@
"options_page" : "options/options.html",
"web_accessible_resources": [
"/assets/images/*",
"website_list.json"
"website_list.json",
"options/corb.html"
],
"offline_enabled" : true,
"update_url" : "https://clients2.google.com/service/update2/crx",
"content_security_policy" : "script-src 'self' 'unsafe-eval' https://www.google-analytics.com; object-src 'self'",
"content_security_policy" : "script-src 'self' 'unsafe-eval' https://ssl.google-analytics.com; object-src 'self'",
"manifest_version": 2
}

View File

@ -89,7 +89,7 @@ export default class About extends React.Component {
</div>
</div>
<div className="label">帮助</div>
<div className="label" data-head-level="h1">帮助</div>
<div style={{ 'padding-top': '10px', 'position': 'relative' }} className="lab">
<div className="more">
<div><a style={style.href} target="_blank" href="http://sr.ksria.cn/zhifu_m2.png">如果简悦可以解决你在阅读上痛点可以请我喝杯咖啡</a></div>
@ -117,12 +117,12 @@ export default class About extends React.Component {
</div>
<div style={{ 'margin-top': '10px', 'position': 'relative' }} className="lab">
<div className="more">
<a style={style.href}><b onClick={()=>this.props.onClick("welcome")}>重看引导页面</b> 或者 <a style={style.href} target="_blank" href="http://ksria.com/simpread/welcome/version_1.1.3.html"><b>重看当前版本</b></a> 的功能介绍</a>
<a style={style.href}><b onClick={()=>this.props.onClick("welcome")}>重看引导页面</b> 或者 <a style={style.href} target="_blank" href="http://ksria.com/simpread/welcome/version_1.1.4.html"><b>重看当前版本</b></a> 的功能介绍</a>
<span style={{ bottom: "11px" }} className="arrow"></span>
</div>
</div>
<div className="label">其它平台的简悦</div>
<div className="label" data-head-level="h1">其它平台的简悦</div>
<div style={{ 'padding-top': '10px', 'position': 'relative' }} className="lab">
<div className="more">
<div><a style={style.href} target="_blank" href="http://ksria.com/simpread/#downloads">简悦已经上线了 Firefox UserScript JSBox 总有一款适合你</a></div>
@ -131,7 +131,7 @@ export default class About extends React.Component {
</div>
</div>
<div className="label">反馈</div>
<div className="label" data-head-level="h1">反馈</div>
<div style={{ 'padding-top': '10px', 'position': 'relative' }} className="lab">
<div className="more">
<a style={style.href} target="_blank" href="https://github.com/kenshin/simpread/issues">如果有任何问题请提交 issues</a>
@ -151,7 +151,7 @@ export default class About extends React.Component {
</div>
</div>
<div className="label">其它作品</div>
<div className="label" data-head-level="h1">其它作品</div>
<div style={{ 'margin-top': '10px', 'position': 'relative' }} className="lab">
<div className="more">
<a style={style.href} target="_blank" href="http://ksria.com/gnvm">GNVM - 使用 Go 语言编写的 Node.js 多版本管理器</a>

View File

@ -4,11 +4,14 @@ import {storage} from 'storage';
import * as exp from 'export';
import * as msg from 'message';
import {browser} from 'browser';
import * as permission
from 'permission';
import Notify from 'notify';
import Switch from 'switch';
import TextField from 'textfield';
import Button from 'button';
import Dropdown from 'dropdown';
export default class Auth extends React.Component {
@ -24,6 +27,10 @@ export default class Auth extends React.Component {
jianguo: {
username: "",
password: "",
},
weizhi: {
username: "",
password: "",
}
}
@ -32,11 +39,14 @@ export default class Auth extends React.Component {
linnk : undefined,
instapaper : undefined,
jianguo: undefined,
weizhi : undefined,
notion : undefined,
youdao : undefined,
}
onChange( state, value, flag ) {
let notify;
const { dropbox, pocket, instapaper, linnk, evernote, onenote, gdrive, jianguo, yuque } = exp,
const { dropbox, pocket, instapaper, linnk, evernote, onenote, gdrive, jianguo, yuque, notion, youdao, weizhi } = exp,
clear = ( id, name ) => {
Object.keys( storage.secret[id] ).forEach( item => storage.secret[id][item] = "" );
storage.Safe( ()=> {
@ -53,6 +63,9 @@ export default class Auth extends React.Component {
id == "linnk" && this.setState({ secret: storage.secret, linnk: false });
id == "instapaper" && this.setState({ secret: storage.secret, instapaper: false });
id == "jianguo" && this.setState({ secret: storage.secret, jianguo: false });
id == "weizhi" && this.setState({ secret: storage.secret, weizhi: false });
id == "notion" && this.setState({ secret: storage.secret, notion: notion.blocks });
id == "youdao" && this.setState({ secret: storage.secret, youdao: youdao.folders });
if ( location.hash.startsWith( "#labs?auth=" ) ) {
new Notify().Render( "3 秒钟将会关闭此页面..." );
setTimeout( () => {
@ -64,6 +77,7 @@ export default class Auth extends React.Component {
failed = ( error, id, name ) => {
notify && notify.complete();
console.error( `${name} auth faild, error: ${error}` )
id == "youdao" || id == "notion" ? new Notify().Render( 2, `获取 ${name} 授权失败,${error}` ) :
new Notify().Render( 2, `获取 ${name} 授权失败,请重新获取。` );
storage.secret[state].access_token = "";
this.setState({ secret: storage.secret });
@ -84,6 +98,11 @@ export default class Auth extends React.Component {
return;
}
if ( state == "weizhi" && !flag && !storage.secret.weizhi.username ) {
this.setState({ weizhi: !this.state.weizhi });
return;
}
if ( !value ) {
state == "pocket" && $( this.refs.pocket_tags ).velocity( value ? "slideDown" : "slideUp" );
if ( state == "linnk" ) {
@ -98,6 +117,14 @@ export default class Auth extends React.Component {
this.props.jianguo.username = "";
this.props.jianguo.password = "";
}
if ( state == "weizhi" ) {
this.props.weizhi.username = "";
this.props.weizhi.password = "";
this.props.weizhi.access_token = "";
}
if ( state == "youdao" ) {
permission.Remove( youdao.permissions, result => new Notify().Render( `已取消 cookies 权限。` ));
}
clear( state, exp.Name( state ));
return;
}
@ -212,6 +239,27 @@ export default class Auth extends React.Component {
});
}).fail( error => failed( error, yuque.id, yuque.name ));
break;
case "notion":
notion.Auth( ( result, error ) => {
if ( error ) failed( error, notion.id, notion.name );
else success( notion.id, notion.name, { access_token: notion.access_token, folder_id: notion.folder_id });
});
break;
case "youdao":
permission.Get( youdao.permissions, result => {
if ( !result ) {
new Notify().Render( 2, `此功能需要申请 cookies 权限后才能使用,授权成功后会自动取消。` );
this.setState({ secret: storage.secret });
return;
}
setTimeout( () => {
youdao.Auth( ( result, error ) => {
if ( error ) failed( error, youdao.id, youdao.name );
else success( youdao.id, youdao.name, { access_token: youdao.access_token, folder_id: youdao.folder_id });
});
}, 500 );
});
break;
case "jianguo":
jianguo.Auth( this.props.jianguo.username, this.props.jianguo.password, result => {
if ( result && result.status == 401 ) {
@ -219,12 +267,28 @@ export default class Auth extends React.Component {
} else success( "jianguo", "坚果云", { username: this.props.jianguo.username, password: this.props.jianguo.password } );
});
break;
case "weizhi":
if ( location.hash.startsWith( "#labs?auth=" ) ) {
this.props.weizhi.username = storage.secret.weizhi.username;
this.props.weizhi.password = storage.secret.weizhi.password;
}
weizhi.Auth( this.props.weizhi.username, this.props.weizhi.password, result => {
if ( result && result.status == 401 ) {
failed( "授权错误,请重新授权。", weizhi.id, weizhi.name );
} else {
if ( result && result.returnCode == 200 ) success( "weizhi", "为知笔记", { username: this.props.weizhi.username, password: this.props.weizhi.password, access_token: weizhi.access_token } );
else failed( "授权错误,请重新授权。", weizhi.id, weizhi.name );
}
});
break;
}
}
save( state, value ) {
state == "pocket" && ( storage.secret.pocket.tags = value.trim() );
state == "linnk" && ( storage.secret.linnk.group_name = value.trim() );
state == "notion" && ( storage.secret.notion.folder_id = value.trim() );
state == "youdao" && ( storage.secret.youdao.folder_id = value.trim() );
storage.Safe( () => this.setState({ secret: storage.secret }), storage.secret );
}
@ -240,16 +304,42 @@ export default class Auth extends React.Component {
this.props.jianguo[state] = value;
}
weizhiOnChange( state, value ) {
this.props.weizhi[state] = value;
}
webdavOnChange() {
this.state.secret.webdav = event.target.value.split("\n");
storage.Safe( () => this.setState({ secret: storage.secret }), storage.secret );
}
notionChange() {
exp.notion.Auth( ( result, error ) => {
this.setState({ secret: storage.secret, notion: exp.notion.blocks });
});
}
youdaoChange() {
permission.Get( exp.youdao.permissions, result => {
if ( !result ) {
new Notify().Render( 2, `此功能需要申请 cookies 权限后才能使用,授权成功后会自动取消。` );
this.setState({ secret: storage.secret });
return;
}
setTimeout( () => {
exp.youdao.Auth( ( result, error ) => {
if ( result ) this.setState({ secret: storage.secret, youdao: exp.youdao.folders });
else new Notify().Render( 2, `重新获取失败,${error}` );
});
}, 500 );
});
}
webdavAuth() {
this.state.secret.webdav.forEach( ( item, idx ) => {
try {
item = JSON.parse( item );
if ( Object.keys( item ).join( "" ).replace( /url|name|password|user/ig, "" ) != "" ) {
if ( Object.keys( item ).join( "" ).replace( /url|name|password|user|format/ig, "" ) != "" ) {
throw "error";
}
exp.webdav.Auth( item.url, item.user, item.password, result => {
@ -270,10 +360,12 @@ export default class Auth extends React.Component {
}
componentDidMount() {
storage.Safe( () => this.setState({ secret: storage.secret }) );
if ( location.hash.startsWith( "#labs?auth=" ) ) {
this.onChange( location.hash.replace( "#labs?auth=", "" ), true );
}
storage.Safe( () => {
this.setState({ secret: storage.secret })
if ( location.hash.startsWith( "#labs?auth=" ) ) {
this.onChange( location.hash.replace( "#labs?auth=", "" ), true );
}
});
}
render() {
@ -418,7 +510,68 @@ export default class Auth extends React.Component {
onChange={ (s)=>this.onChange( "yuque", s ) } />
</div>
<div className="version-tips" data-version="1.1.3" data-hits="webdav">
<div className="version-tips" data-version="1.1.4" data-hits="notion">
<Switch width="100%" checked={ this.state.secret.notion.access_token != "" ? true : false }
thumbedColor="#3F51B5" trackedColor="#7986CB" waves="md-waves-effect"
label={ this.state.secret.notion.access_token ? "已授权 Notion是否取消授权" : "是否连接并授权 Notion " }
onChange={ (s)=>this.onChange( "notion", s ) } />
{ this.state.secret.notion.access_token &&
<div style={{ display: "flex","flex-direction": "row", "justify-content": "center" }}>
{ this.state.notion ? <Dropdown name={ "请选择保存的位置,默认为第一个" } items={ this.state.notion } width="100%" onChange={ (v,n)=>this.save( "notion", v ) } />
: <Button type="flat" width="100%" style={{ "margin": "0" }}
text="重新获取 Notion Page"
color="#fff" backgroundColor="#3F51B5"
waves="md-waves-effect md-waves-button"
onClick={ (s)=>this.notionChange() } /> }
</div> }
</div>
<div className="version-tips" data-version="1.1.4" data-hits="youdao">
<Switch width="100%" checked={ this.state.secret.youdao.access_token != "" ? true : false }
thumbedColor="#3F51B5" trackedColor="#7986CB" waves="md-waves-effect"
label={ this.state.secret.youdao.access_token ? "已授权 有道云笔记" : "是否连接并授权 有道云笔记 " }
onChange={ (s)=>this.onChange( "youdao", s ) } />
{ this.state.secret.youdao.access_token &&
<div style={{ display: "flex","flex-direction": "row", "justify-content": "center" }}>
{ this.state.youdao ? <Dropdown name={ "请选择保存的位置,默认为第一个" } items={ this.state.youdao } width="100%" onChange={ (v,n)=>this.save( "youdao", v ) } />
: <Button type="flat" width="100%" style={{ "margin": "0" }}
text="重新获取 有道云笔记 的文件夹"
color="#fff" backgroundColor="#3F51B5"
waves="md-waves-effect md-waves-button"
onClick={ (s)=>this.youdaoChange() } /> }
</div> }
</div>
<div className="version-tips" data-version="1.1.4" data-hits="weizhi">
<Switch width="100%" checked={ this.state.secret.weizhi && this.state.secret.weizhi.username != "" && this.state.secret.weizhi.access_token ? true : false }
thumbedColor="#3F51B5" trackedColor="#7986CB" waves="md-waves-effect"
label={ this.state.secret.weizhi && this.state.secret.weizhi.username != "" ? "已授权 为知笔记,是否取消授权?" : "是否连接并授权 为知笔记 " }
onChange={ (s)=>this.onChange( "weizhi", s ) } />
</div>
{ this.state.weizhi &&
<div ref="weizhi">
<div style={{ "display": "flex", "flex-direction": "row" }}>
<TextField
placeholder="请填入 为知笔记 的登录邮箱,简悦不会记录你的邮箱。"
onChange={ (evt)=>this.weizhiOnChange( "username", evt.target.value ) }
/>
<TextField
password={true}
placeholder="请填入 为知笔记 的密码,简悦不会记录你的密码。"
onChange={ (evt)=>this.weizhiOnChange( "password", evt.target.value ) }
/>
</div>
<Button type="raised" width="100%" style={{ "margin": "0" }}
text="绑定 为知笔记 的信息"
color="#fff" backgroundColor="#3F51B5"
waves="md-waves-effect md-waves-button"
onClick={ (s)=>this.onChange( "weizhi", s, "login" ) } />
</div> }
<div className="version-tips" data-version="1.1.4" data-hits="webdav">
<div className="label" style={{'margin-bottom':' -15px'}}>WebDAV</div>
<div className="sublabel">简悦支持任意 WebDAV 的服务包括Box · TeraCLOUD </div>
<TextField

View File

@ -9,7 +9,7 @@ import * as ver from 'version';
import * as menu from 'menu';
import * as watch from 'watch';
import * as exp from 'export';
import {br} from 'browser';
import {browser,br}from 'browser';
import * as msg from 'message';
export default class CommonOpt extends React.Component {
@ -101,6 +101,7 @@ export default class CommonOpt extends React.Component {
};
storage.Safe( ()=> {
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.track, { eventCategory: "sync", eventAction: "sync", eventValue: storage.option.save_at }) );
if ( storage.option.save_at == "dropbox" ) {
const sec_dbx = storage.secret.dropbox;
!sec_dbx.access_token ?
@ -154,7 +155,8 @@ export default class CommonOpt extends React.Component {
new Notify().Render({ type: 2, content: `上传版本太低,已自动转换为最新版本。`, state: "holdon" });
}
menu.Refresh( json.option.menu );
ver.Incompatible( json.version, json );
ver.Incompatible( json.version, json ) && new Notify().Render({ type: 2, content: `检测到你曾经修改过第三方适配源,<b>务必刷新后重新导入</b><a target="_blank" href="http://ksria.com/simpread/docs/#/站点适配源?id=第三方适配源">详细说明</a>`, state: "holdon" });
ver.VerifyPlugins( json.option ) && new Notify().Render({ type: 2, content: `已清理失效的插件,详细请看 <a href="http://ksria.com/simpread/welcome/version_${json.version}.html#badplugins" target="_blank">失效插件</a>`, state: "holdon" });
json.option.origins && json.option.origins.length > 0 &&
new Notify().Render({ content: `导入的配置文件包含了第三方源,刷新后请重新 <b>手动导入</b>。`, state: "holdon" });
json.option.plugins && json.option.plugins.length > 0 &&

View File

@ -25,7 +25,7 @@ export default class ThemeSel extends React.Component {
render() {
return (
<sr-opt-themes onClick={ evt=> this.changeBgColor(evt) }>
{ this.props.themes.map( (theme,idx) => <sr-opt-theme style={{backgroundColor: `rgba( ${theme} )`}} name={ this.props.names[idx] } data-tooltip={ this.props.labels[idx] } data-tooltip-position="bottom" data-tooltip-delay="50"></sr-opt-theme> )}
{ this.props.themes.map( (theme,idx) => <sr-opt-theme style={{backgroundColor: `rgba( ${theme} )`}} name={ this.props.names[idx] } data-tooltip={ this.props.labels[idx] } data-tooltip-position="up" data-tooltip-delay="50"></sr-opt-theme> )}
</sr-opt-themes>
)
}

View File

@ -26,10 +26,12 @@ export default class URL extends React.Component {
if ( url == "" ) {
code = -2;
this.setState({ error : "当前输入不能为空。" });
} else if ( !/^http[s|*]?:\/\//.test( url ) ) {
} else if ( url.startsWith( "[[/" ) && url.endsWith( "/]]" ) && !new RegExp( url.replace( /^\[\[\/|\/\]\]/g, "" ) ).test( location.href )) {
location.protocol != "chrome-extension:" && this.setState({ error : "请输入与当前网址匹配的域名,正则表达式出现错误。" });
} else if ( !url.startsWith( "[[/" ) && !/^http[s|*]?:\/\//.test( url ) ) {
code = -1;
this.setState({ error : "请输入有效的 url " });
} else if ( location.protocol.startsWith( "http" ) && !minimatch( window.location.href, url ) && url != this.props.url ) {
} else if ( !url.startsWith( "[[/" ) && location.protocol.startsWith( "http" ) && !minimatch( window.location.href, url ) && url != this.props.url ) {
code = -1;
this.setState({ error : "请输入与当前网址匹配的域名,支持 minimatch " });
} else {

240
src/module/feedback.jsx Normal file
View File

@ -0,0 +1,240 @@
console.log( "===== simpread feedback load =====" )
import Switch from 'switch';
import TextField from 'textfield';
import Button from 'button';
import {browser} from 'browser';
import * as msg from 'message';
export class Feedback extends React.Component {
static defaultProps = {
user : {},
url : "",
version : "",
anonymous: false,
rate : false,
product : "https://support.qq.com/product/" + 117464,
star : `<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="35" height="35"><path d="M512 837.12L255.6928 950.0672c-14.336 6.3488-31.1296-0.2048-37.4784-14.5408-1.9456-4.5056-2.7648-9.4208-2.2528-14.336l28.16-278.6304-186.5728-208.896c-10.4448-11.6736-9.4208-29.696 2.2528-40.1408 3.6864-3.2768 8.0896-5.5296 12.9024-6.5536L346.5216 327.68 487.424 85.7088c7.8848-13.6192 25.2928-18.1248 38.912-10.24 4.3008 2.4576 7.7824 6.0416 10.24 10.24L677.4784 327.68l273.7152 59.2896c15.36 3.2768 25.088 18.432 21.8112 33.792-1.024 4.8128-3.2768 9.216-6.5536 12.9024l-186.6752 208.896L807.936 921.1904c1.536 15.6672-9.8304 29.5936-25.3952 31.1296-4.9152 0.512-9.8304-0.3072-14.336-2.2528L512 837.12z" fill="#E3E3E3"></path></svg>`,
stared : `<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="35" height="35"><path d="M512 837.12L255.6928 950.0672c-14.336 6.3488-31.1296-0.2048-37.4784-14.5408-1.9456-4.5056-2.7648-9.4208-2.2528-14.336l28.16-278.6304-186.5728-208.896c-10.4448-11.6736-9.4208-29.696 2.2528-40.1408 3.6864-3.2768 8.0896-5.5296 12.9024-6.5536L346.5216 327.68 487.424 85.7088c7.8848-13.6192 25.2928-18.1248 38.912-10.24 4.3008 2.4576 7.7824 6.0416 10.24 10.24L677.4784 327.68l273.7152 59.2896c15.36 3.2768 25.088 18.432 21.8112 33.792-1.024 4.8128-3.2768 9.216-6.5536 12.9024l-186.6752 208.896L807.936 921.1904c1.536 15.6672-9.8304 29.5936-25.3952 31.1296-4.9152 0.512-9.8304-0.3072-14.336-2.2528L512 837.12z" fill="#FFB82F"</path></svg>`,
}
static propType = {
user : React.PropTypes.object,
url : React.PropTypes.string,
version : React.PropTypes.string,
anonymous: React.PropTypes.bool,
rate : React.PropTypes.bool,
product : React.PropTypes.string,
}
state = {
mode: "github",
rate: this.props.rate,
stars: 0,
};
onStarClick( idx ) {
$( this.refs.stars ).find( "i" ).removeClass( "active" );
for( let i = 0; i < 5; i++ ) {
const $target = $( $( this.refs.stars ).find( "i" )[i] );
if ( i < idx ) $target.addClass( "active" ).html( this.props.stared );
else $target.html( this.props.star );
}
$( this.refs.emoji ).css({ 'transform': `translateY(-${idx}00px)` });
this.setState({ stars: idx });
}
onStarHover( idx ) {
$( this.refs.emoji ).css({ 'transform': `translateY(-${idx}00px)` });
}
onRateClick() {
if ( this.state.stars < 4 ) {
this.setState({ rate: false });
} else {
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.new_tab, { url: "https://chrome.google.com/webstore/detail/simpread-reader-view/ijllcpnolfcooahcekpamkbidhejabll/reviews" }));
setTimeout( () => this.onClose(), 200 );
}
}
onURLChange( event ) {
this.props.url = event.target.value.trim();
}
onAnonymousChange( value ) {
this.props.anonymous = value;
}
onChangeMode( mode ) {
this.setState({ mode });
}
onClose() {
$( this.refs.target )
.addClass( "hide" )[0]
.addEventListener( 'animationend', () => {
ReactDOM.unmountComponentAtNode( $( ".simpread-feedback" )[0] );
$( ".simpread-feedback" ).remove();
}, false );
}
onSubmitClick() {
this.state.mode == "github" ? this.onGithubClick() : this.onTucaoClick();
}
onGithubClick() {
const content = `**小提示**
> 简悦已经服务 70K+ 的用户所以你的很多问题或许已经被前人解决了所以试着看看以下几个列表中的内容
- [用好 Github issues 能解决你大部分的疑问](https://github.com/Kenshin/simpread/issues/533)
- [常见问题汇总](https://github.com/Kenshin/simpread/issues/618)
- [代码段的专项整治](https://github.com/Kenshin/simpread/issues/500)
***
> 如上述内容无法解决你的问题那么请将上述内容删除并按照下方的提示书写~ 😀
**请说明发生问题的环境**
> 简悦包含了很多平台的版本所以为了方便定位建议告诉我一些必要信息
- 操作系统 **${window.navigator.platform}**
- 浏览器版本 **e.g. Chrome 78.0.3904.108**
- 简悦版本 **${ this.props.version }**
- 发生问题的地址 <${ this.props.url }>
**请描述你的问题**
> 请使用可以 **准确定位到错误** 的语句来告诉我😀
**截图**
> 一图胜千言所以方便的话可以试着贴图
`, url = encodeURI( `https://github.com/Kenshin/simpread/issues/new?title=<>&labels=to do&body=${content}` )
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.new_tab, { url }));
}
onTucaoClick() {
const data = {
"nickname" : this.props.anonymous ? "简悦用户" : this.props.user.name || "简悦用户",
"avatar" : `https://api.adorable.io/avatars/285/${ this.props.user.name || this.props.user.uid.substr( 0,13 ) }.png`,
"openid" : this.props.user.uid.substr( 0,13 ),
"clientVersion": this.props.version,
"clientInfo" : window.navigator.userAgent,
"customInfo" : "https://github.com/erguotou520/tucao-dingtalk-webhook"
};
$.ajax({
url: this.props.product,
method: "POST",
data
}).done( ( result, textStatus, jqXHR ) => {
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.new_tab, { url: this.props.product }));
}).fail( error => {
console.log( "count failed ", error )
});
}
render() {
return (
<simpread-feedback ref="target" class="active">
{ this.state.rate == false ?
<sr-block style={{ 'width': '100%' }}>
<sr-fb-head>
<sr-fb-label>有了你们的帮助简悦才会变得更好 🙏</sr-fb-label>
</sr-fb-head>
<sr-fb-content>
<sr-fb-label>提交的站点默认为当前页面的地址可为空</sr-fb-label>
<TextField multi={ false } value={ this.props.url } onChange={ (e)=>this.onURLChange(e) } />
</sr-fb-content>
<sr-fb-content>
<sr-fb-label>支持两种提交方式</sr-fb-label>
<span style={{ 'display': 'flex' }}>
<Button
text="有 Github Issues 帐号" type="raised" waves="md-waves-effect"
color="#fff" backgroundColor="#2196F3" width="50%" style={{ 'margin-left': '0', 'font-weight': 'bold' }}
tooltip={{ text: "如果有 Github 帐号,请首选此方式" }} onClick={ ()=>this.onChangeMode( "github" ) } />
<Button
text="无 Github Issues 帐号" type="raised" mode="secondary" waves="md-waves-effect"
color="#fff" backgroundColor="#757575" width="50%" style={{ 'margin-right': '0', 'font-weight': 'bold' }}
tooltip={{ text: "腾讯旗下的一款用户反馈收集系统,无需注册" }} onClick={ ()=>this.onChangeMode( "tucao" ) } />
</span>
</sr-fb-content>
{ this.state.mode == "tucao" &&
<sr-fb-content>
<sr-fb-content>
<Switch width="100%" checked={ this.props.anonymous }
thumbedColor="#2163f7" trackedColor="#6699FF" waves="md-waves-effect"
label="支持匿名提交,但建议不要勾选此项"
onChange={ (v)=>this.onAnonymousChange( v ) } />
</sr-fb-content>
<sr-fb-content>
<sr-fb-label><b>吐个槽</b> 是腾讯旗下的一款用户反馈收集系统具有如下特点</sr-fb-label>
<sr-fb-label>· 无需注册点击后会自动使用简悦的注册系统</sr-fb-label>
<sr-fb-label>· 如需实时收到反馈请根据提示关注腾讯官方微信号</sr-fb-label>
<sr-fb-label>· 你的提交内容他人无法看到</sr-fb-label>
</sr-fb-content>
</sr-fb-content>
}
<sr-fb-content>
<sr-fb-label><b>方便的话请帮助简悦使其变得更好 👉 <sr-fb-a onClick={ ()=>window.open( 'https://wj.qq.com/s2/3611463/7260/', '_blank') }>调查问卷</sr-fb-a></b></sr-fb-label>
</sr-fb-content>
<sr-fb-footer>
<Button text="评个分" color="#FF5252" waves="md-waves-effect" style={{ 'font-weight': 'bold' }} onClick={ ()=>this.setState({ rate: true }) } />
<Button text="取 消" mode="secondary" color="#333" waves="md-waves-effect" onClick={ ()=>this.onClose() } />
<Button text="提 交" waves="md-waves-effect" color="#2163f7" style={{ 'font-weight': 'bold' }} onClick={ ()=>this.onSubmitClick() } />
</sr-fb-footer>
</sr-block>
:
<sr-block style={{ 'width': '100%' }}>
<sr-close onClick={ ()=>this.onClose() }><svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M649.179 512l212.839-212.84c37.881-37.881 37.881-99.298 0-137.179s-99.298-37.881-137.179 0L512 374.821l-212.839-212.84c-37.881-37.881-99.298-37.881-137.179 0s-37.881 99.298 0 137.179L374.821 512 161.982 724.84c-37.881 37.881-37.881 99.297 0 137.179 18.94 18.94 43.765 28.41 68.589 28.41 24.825 0 49.649-9.47 68.589-28.41L512 649.179l212.839 212.84c18.94 18.94 43.765 28.41 68.589 28.41s49.649-9.47 68.59-28.41c37.881-37.882 37.881-99.298 0-137.179L649.179 512z" fill="#E3E3E3"></path></svg></sr-close>
<sr-emojis>
<sr-emoji ref="emoji">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><circle cx="256" cy="256" r="256" fill="#ffd93b"></circle><path d="M512 256c0 141.44-114.64 256-256 256-80.48 0-152.32-37.12-199.28-95.28 43.92 35.52 99.84 56.72 160.72 56.72 141.36 0 256-114.56 256-256 0-60.88-21.2-116.8-56.72-160.72C474.8 103.68 512 175.52 512 256z" fill="#f4c534"></path><ellipse transform="scale(-1) rotate(31.21 715.433 -595.455)" cx="166.318" cy="199.829" rx="56.146" ry="56.13" fill="#fff"></ellipse><ellipse transform="rotate(-148.804 180.87 175.82)" cx="180.871" cy="175.822" rx="28.048" ry="28.08" fill="#3e4347"></ellipse><ellipse transform="rotate(-113.778 194.434 165.995)" cx="194.433" cy="165.993" rx="8.016" ry="5.296" fill="#5a5f63"></ellipse><ellipse transform="scale(-1) rotate(31.21 715.397 -1237.664)" cx="345.695" cy="199.819" rx="56.146" ry="56.13" fill="#fff"></ellipse><ellipse transform="rotate(-148.804 360.25 175.837)" cx="360.252" cy="175.84" rx="28.048" ry="28.08" fill="#3e4347"></ellipse><ellipse transform="scale(-1) rotate(66.227 254.508 -573.138)" cx="373.794" cy="165.987" rx="8.016" ry="5.296" fill="#5a5f63"></ellipse><path d="M370.56 344.4c0 7.696-6.224 13.92-13.92 13.92H155.36c-7.616 0-13.92-6.224-13.92-13.92s6.304-13.92 13.92-13.92h201.296c7.696.016 13.904 6.224 13.904 13.92z" fill="#3e4347"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><circle cx="256" cy="256" r="256" fill="#ffd93b"></circle><path d="M512 256A256 256 0 0 1 56.7 416.7a256 256 0 0 0 360-360c58.1 47 95.3 118.8 95.3 199.3z" fill="#f4c534"></path><path d="M328.4 428a92.8 92.8 0 0 0-145-.1 6.8 6.8 0 0 1-12-5.8 86.6 86.6 0 0 1 84.5-69 86.6 86.6 0 0 1 84.7 69.8c1.3 6.9-7.7 10.6-12.2 5.1z" fill="#3e4347"></path><path d="M269.2 222.3c5.3 62.8 52 113.9 104.8 113.9 52.3 0 90.8-51.1 85.6-113.9-2-25-10.8-47.9-23.7-66.7-4.1-6.1-12.2-8-18.5-4.2a111.8 111.8 0 0 1-60.1 16.2c-22.8 0-42.1-5.6-57.8-14.8-6.8-4-15.4-1.5-18.9 5.4-9 18.2-13.2 40.3-11.4 64.1z" fill="#f4c534"></path><path d="M357 189.5c25.8 0 47-7.1 63.7-18.7 10 14.6 17 32.1 18.7 51.6 4 49.6-26.1 89.7-67.5 89.7-41.6 0-78.4-40.1-82.5-89.7A95 95 0 0 1 298 174c16 9.7 35.6 15.5 59 15.5z" fill="#fff"></path><path d="M396.2 246.1a38.5 38.5 0 0 1-38.7 38.6 38.5 38.5 0 0 1-38.6-38.6 38.6 38.6 0 1 1 77.3 0z" fill="#3e4347"></path><path d="M380.4 241.1c-3.2 3.2-9.9 1.7-14.9-3.2-4.8-4.8-6.2-11.5-3-14.7 3.3-3.4 10-2 14.9 2.9 4.9 5 6.4 11.7 3 15z" fill="#fff"></path><path d="M242.8 222.3c-5.3 62.8-52 113.9-104.8 113.9-52.3 0-90.8-51.1-85.6-113.9 2-25 10.8-47.9 23.7-66.7 4.1-6.1 12.2-8 18.5-4.2 16.2 10.1 36.2 16.2 60.1 16.2 22.8 0 42.1-5.6 57.8-14.8 6.8-4 15.4-1.5 18.9 5.4 9 18.2 13.2 40.3 11.4 64.1z" fill="#f4c534"></path><path d="M155 189.5c-25.8 0-47-7.1-63.7-18.7-10 14.6-17 32.1-18.7 51.6-4 49.6 26.1 89.7 67.5 89.7 41.6 0 78.4-40.1 82.5-89.7A95 95 0 0 0 214 174c-16 9.7-35.6 15.5-59 15.5z" fill="#fff"></path><path d="M115.8 246.1a38.5 38.5 0 0 0 38.7 38.6 38.5 38.5 0 0 0 38.6-38.6 38.6 38.6 0 1 0-77.3 0z" fill="#3e4347"></path><path d="M131.6 241.1c3.2 3.2 9.9 1.7 14.9-3.2 4.8-4.8 6.2-11.5 3-14.7-3.3-3.4-10-2-14.9 2.9-4.9 5-6.4 11.7-3 15z" fill="#fff"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><circle cx="256" cy="256" r="256" fill="#ffd93b"></circle><path d="M512 256A256 256 0 0 1 56.7 416.7a256 256 0 0 0 360-360c58.1 47 95.3 118.8 95.3 199.3z" fill="#f4c534"></path><path d="M336.6 403.2c-6.5 8-16 10-25.5 5.2a117.6 117.6 0 0 0-110.2 0c-9.4 4.9-19 3.3-25.6-4.6-6.5-7.7-4.7-21.1 8.4-28 45.1-24 99.5-24 144.6 0 13 7 14.8 19.7 8.3 27.4z" fill="#3e4347"></path><path d="M276.6 244.3a79.3 79.3 0 1 1 158.8 0 79.5 79.5 0 1 1-158.8 0z" fill="#fff"></path><circle cx="340" cy="260.4" r="36.2" fill="#3e4347"></circle><g fill="#fff"><ellipse transform="rotate(-135 326.4 246.6)" cx="326.4" cy="246.6" rx="6.5" ry="10"></ellipse><path d="M231.9 244.3a79.3 79.3 0 1 0-158.8 0 79.5 79.5 0 1 0 158.8 0z"></path></g><circle cx="168.5" cy="260.4" r="36.2" fill="#3e4347"></circle><ellipse transform="rotate(-135 182.1 246.7)" cx="182.1" cy="246.7" rx="10" ry="6.5" fill="#fff"></ellipse></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><circle cx="256" cy="256" r="256" fill="#ffd93b"></circle><path d="M407.7 352.8a163.9 163.9 0 0 1-303.5 0c-2.3-5.5 1.5-12 7.5-13.2a780.8 780.8 0 0 1 288.4 0c6 1.2 9.9 7.7 7.6 13.2z" fill="#3e4347"></path><path d="M512 256A256 256 0 0 1 56.7 416.7a256 256 0 0 0 360-360c58.1 47 95.3 118.8 95.3 199.3z" fill="#f4c534"></path><g fill="#fff"><path d="M115.3 339c18.2 29.6 75.1 32.8 143.1 32.8 67.1 0 124.2-3.2 143.2-31.6l-1.5-.6a780.6 780.6 0 0 0-284.8-.6z"></path><ellipse cx="356.4" cy="205.3" rx="81.1" ry="81"></ellipse></g><ellipse cx="356.4" cy="205.3" rx="44.2" ry="44.2" fill="#3e4347"></ellipse><g fill="#fff"><ellipse transform="scale(-1) rotate(45 454 -906)" cx="375.3" cy="188.1" rx="12" ry="8.1"></ellipse><ellipse cx="155.6" cy="205.3" rx="81.1" ry="81"></ellipse></g><ellipse cx="155.6" cy="205.3" rx="44.2" ry="44.2" fill="#3e4347"></ellipse><ellipse transform="scale(-1) rotate(45 454 -421.3)" cx="174.5" cy="188" rx="12" ry="8.1" fill="#fff"></ellipse></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><circle cx="256" cy="256" r="256" fill="#ffd93b"></circle><path d="M512 256A256 256 0 0 1 56.7 416.7a256 256 0 0 0 360-360c58.1 47 95.3 118.8 95.3 199.3z" fill="#f4c534"></path><path d="M232.3 201.3c0 49.2-74.3 94.2-74.3 94.2s-74.4-45-74.4-94.2a38 38 0 0 1 74.4-11.1 38 38 0 0 1 74.3 11.1z" fill="#e24b4b"></path><path d="M96.1 173.3a37.7 37.7 0 0 0-12.4 28c0 49.2 74.3 94.2 74.3 94.2C80.2 229.8 95.6 175.2 96 173.3z" fill="#d03f3f"></path><path d="M215.2 200c-3.6 3-9.8 1-13.8-4.1-4.2-5.2-4.6-11.5-1.2-14.1 3.6-2.8 9.7-.7 13.9 4.4 4 5.2 4.6 11.4 1.1 13.8z" fill="#fff"></path><path d="M428.4 201.3c0 49.2-74.4 94.2-74.4 94.2s-74.3-45-74.3-94.2a38 38 0 0 1 74.4-11.1 38 38 0 0 1 74.3 11.1z" fill="#e24b4b"></path><path d="M292.2 173.3a37.7 37.7 0 0 0-12.4 28c0 49.2 74.3 94.2 74.3 94.2-77.8-65.7-62.4-120.3-61.9-122.2z" fill="#d03f3f"></path><path d="M411.3 200c-3.6 3-9.8 1-13.8-4.1-4.2-5.2-4.6-11.5-1.2-14.1 3.6-2.8 9.7-.7 13.9 4.4 4 5.2 4.6 11.4 1.1 13.8z" fill="#fff"></path><path d="M381.7 374.1c-30.2 35.9-75.3 64.4-125.7 64.4s-95.4-28.5-125.8-64.2a17.6 17.6 0 0 1 16.5-28.7 627.7 627.7 0 0 0 218.7-.1c16.2-2.7 27 16.1 16.3 28.6z" fill="#3e4347"></path><path d="M256 438.5c25.7 0 50-7.5 71.7-19.5-9-33.7-40.7-43.3-62.6-31.7-29.7 15.8-62.8-4.7-75.6 34.3 20.3 10.4 42.8 17 66.5 17z" fill="#e24b4b"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><g fill="#ffd93b"><circle cx="256" cy="256" r="256"></circle><path d="M512 256A256 256 0 0 1 56.8 416.7a256 256 0 0 0 360-360c58 47 95.2 118.8 95.2 199.3z"></path></g><path d="M512 99.4v165.1c0 11-8.9 19.9-19.7 19.9h-187c-13 0-23.5-10.5-23.5-23.5v-21.3c0-12.9-8.9-24.8-21.6-26.7-16.2-2.5-30 10-30 25.5V261c0 13-10.5 23.5-23.5 23.5h-187A19.7 19.7 0 0 1 0 264.7V99.4c0-10.9 8.8-19.7 19.7-19.7h472.6c10.8 0 19.7 8.7 19.7 19.7z" fill="#e9eff4"></path><path d="M204.6 138v88.2a23 23 0 0 1-23 23H58.2a23 23 0 0 1-23-23v-88.3a23 23 0 0 1 23-23h123.4a23 23 0 0 1 23 23z" fill="#45cbea"></path><path d="M476.9 138v88.2a23 23 0 0 1-23 23H330.3a23 23 0 0 1-23-23v-88.3a23 23 0 0 1 23-23h123.4a23 23 0 0 1 23 23z" fill="#e84d88"></path><g fill="#38c0dc"><path d="M95.2 114.9l-60 60v15.2l75.2-75.2zM123.3 114.9L35.1 203v23.2c0 1.8.3 3.7.7 5.4l116.8-116.7h-29.3z"></path></g><g fill="#d23f77"><path d="M373.3 114.9l-66 66V196l81.3-81.2zM401.5 114.9l-94.1 94v17.3c0 3.5.8 6.8 2.2 9.8l121.1-121.1h-29.2z"></path></g><path d="M329.5 395.2c0 44.7-33 81-73.4 81-40.7 0-73.5-36.3-73.5-81s32.8-81 73.5-81c40.5 0 73.4 36.3 73.4 81z" fill="#3e4347"></path><path d="M256 476.2a70 70 0 0 0 53.3-25.5 34.6 34.6 0 0 0-58-25 34.4 34.4 0 0 0-47.8 26 69.9 69.9 0 0 0 52.6 24.5z" fill="#e24b4b"></path><path d="M290.3 434.8c-1 3.4-5.8 5.2-11 3.9s-8.4-5.1-7.4-8.7c.8-3.3 5.7-5 10.7-3.8 5.1 1.4 8.5 5.3 7.7 8.6z" fill="#fff" opacity=".2"></path></svg>
</sr-emoji>
</sr-emojis>
<sr-stars ref="stars">
<i data-balloon-pos="up" aria-label="吐个槽 😡" onMouseEnter={ () => this.onStarHover( 1 ) } onClick={ () => this.onStarClick( 1 ) } dangerouslySetInnerHTML={{__html: this.props.star }}></i>
<i data-balloon-pos="up" aria-label="一般般 💔" onMouseEnter={ () => this.onStarHover( 2 ) } onClick={ () => this.onStarClick( 2 ) } dangerouslySetInnerHTML={{__html: this.props.star }}></i>
<i data-balloon-pos="up" aria-label="还不错 😁" onMouseEnter={ () => this.onStarHover( 3 ) } onClick={ () => this.onStarClick( 3 ) } dangerouslySetInnerHTML={{__html: this.props.star }}></i>
<i data-balloon-pos="up" aria-label="我喜欢 😘" onMouseEnter={ () => this.onStarHover( 4 ) } onClick={ () => this.onStarClick( 4 ) } dangerouslySetInnerHTML={{__html: this.props.star }}></i>
<i data-balloon-pos="up" aria-label="棒棒哒 👍" onMouseEnter={ () => this.onStarHover( 5 ) } onClick={ () => this.onStarClick( 5 ) } dangerouslySetInnerHTML={{__html: this.props.star }}></i>
</sr-stars>
<sr-stars-footer>
{ this.state.stars == 0 && <Button text="投个票,有你的参与简悦才能变得更美好" waves="md-waves-effect" color="#2163f7" style={{ 'font-weight': 'bold' }} /> }
{ this.state.stars > 0 && this.state.stars < 4 && <Button text="吐个槽?" waves="md-waves-effect" color="#FF5252" style={{ 'font-weight': 'bold' }} onClick={ () => this.onRateClick() }/> }
{ this.state.stars > 3 && <Button color="#fff" backgroundColor="#2196F3" text="谢谢,方便请前往 Chrome 应用商店投票 👉" waves="md-waves-effect" style={{ 'font-weight': 'bold' }} onClick={ () => this.onRateClick() }/> }
</sr-stars-footer>
</sr-block> }
</simpread-feedback>
)
}
}
/**
*
* @param {string} storage.version
* @param {object} storage.user
* @param {boolen} rate, true: show rating; false: show feedback
*/
function Render( version, user, rate = false ) {
if ( $( "simpread-feedback" ).length > 0 ) return;
$( "html" ).append( `<div class="simpread-feedback"></div>` );
ReactDOM.render( <Feedback version={ version } user={ user } url={ location.href } rate={ rate }/>, $( ".simpread-feedback" )[0] );
}
export {
Render
}

View File

@ -91,7 +91,7 @@ export default class LabsOpt extends React.Component {
render() {
return (
<div id="labs" style={{ width: '100%' }}>
<div className="label">全局</div>
<div className="label" data-head-level="h1">全局</div>
<div className="lab">
<div className="version-tips" data-hits="esc">
<Switch width="100%" checked={ this.props.option.esc }
@ -141,7 +141,7 @@ export default class LabsOpt extends React.Component {
</div>
<div className="version-tips" data-hits="menu">
<div className="label">右键菜单</div>
<div className="label" data-head-level="h1">右键菜单</div>
<div style={{ 'padding-top': '10px' }} className="lab">
<Switch width="100%" checked={ this.props.option.menu.focus }
thumbedColor="#3F51B5" trackedColor="#7986CB" waves="md-waves-effect"
@ -155,10 +155,16 @@ export default class LabsOpt extends React.Component {
thumbedColor="#3F51B5" trackedColor="#7986CB" waves="md-waves-effect"
label="是否显示「使用阅读模式打开此链接」?"
onChange={ (s)=>this.onChange(s, "option", "menu", "link" ) } />
<div className="dividers"></div>
<Switch width="100%" checked={ this.props.option.menu.list }
thumbedColor="#3F51B5" trackedColor="#7986CB" waves="md-waves-effect"
label="是否显示「打开稍后读」?"
onChange={ (s)=>this.onChange(s, "option", "menu", "list" ) } />
<Switch width="100%" checked={ this.props.option.menu.unrdist }
thumbedColor="#3F51B5" trackedColor="#7986CB" waves="md-waves-effect"
label="是否显示「加入到稍后读」?"
onChange={ (s)=>this.onChange(s, "option", "menu", "unrdist" ) } />
<div className="dividers"></div>
<Switch width="100%" checked={ this.props.option.menu.whitelist }
thumbedColor="#3F51B5" trackedColor="#7986CB" waves="md-waves-effect"
label="是否显示「加入白名单」?"
@ -171,15 +177,24 @@ export default class LabsOpt extends React.Component {
thumbedColor="#3F51B5" trackedColor="#7986CB" waves="md-waves-effect"
label="是否显示「加入到黑名单」?"
onChange={ (s)=>this.onChange(s, "option", "menu", "blacklist" ) } />
<Switch width="100%" checked={ this.props.option.menu.unrdist }
<div className="version-tips" data-version="1.1.4" data-hits="lazyload">
<Switch width="100%" checked={ this.props.option.menu.lazyload }
thumbedColor="#3F51B5" trackedColor="#7986CB" waves="md-waves-effect"
label="是否显示「加入到稍后读」?"
onChange={ (s)=>this.onChange(s, "option", "menu", "unrdist" ) } />
label="是否显示「加入到延迟加载」?"
onChange={ (s)=>this.onChange(s, "option", "menu", "lazyload" ) } />
</div>
<div className="version-tips" data-version="1.1.4" data-hits="urlscheme">
<Switch width="100%" checked={ this.props.option.urlscheme }
thumbedColor="#3F51B5" trackedColor="#7986CB" waves="md-waves-effect"
label="默认弹出编辑框,取消后意味着直接保存"
desc="包括:黑名单 · 白名单 · 排除列表 · 延迟加载均可使用"
onChange={ (s)=>this.onChange(s, "option", "urlscheme" ) } />
</div>
</div>
</div>
<div className="version-tips" data-hits="focusconfig">
<div className="label">聚焦模式</div>
<div className="label" data-head-level="h1">聚焦模式</div>
<div style={{ 'padding-top': '10px' }} className="lab">
<Switch width="100%" checked={ this.props.focus.mask }
thumbedColor="#3F51B5" trackedColor="#7986CB" waves="md-waves-effect"
@ -199,7 +214,7 @@ export default class LabsOpt extends React.Component {
</div>
<div className="version-tips" data-hits="readconfig">
<div className="label">阅读模式</div>
<div className="label" data-head-level="h1">阅读模式</div>
<div style={{ 'padding-top': '10px' }} className="lab">
<div className="version-tips" data-hits="progress">
<Switch width="100%" checked={ this.props.read.progress }
@ -277,7 +292,7 @@ export default class LabsOpt extends React.Component {
</div>
<div className="version-tips" data-hits="pured">
<div className="label">词法分析引擎 <a target="_blank" href="http://ksria.com/simpread/docs/#/词法分析引擎" style={{ color:' #FF5252', borderBottom: '2px dotted', fontSize: '10px', fontWeight: 'bold', cursor: 'pointer' }}>测试版</a></div>
<div className="label" data-head-level="h1" data-head-title="词法分析引擎">词法分析引擎 <a target="_blank" href="http://ksria.com/simpread/docs/#/词法分析引擎" style={{ color:' #FF5252', borderBottom: '2px dotted', fontSize: '10px', fontWeight: 'bold', cursor: 'pointer' }}>测试版</a></div>
<div style={{ 'padding-top': '10px', 'position': 'relative' }} className="lab">
<Switch width="100%" checked={ this.props.read.cleanup == undefined ? true : this.props.read.cleanup }
thumbedColor="#3F51B5" trackedColor="#7986CB"
@ -320,14 +335,14 @@ export default class LabsOpt extends React.Component {
</div>
<div className="version-tips" data-hits="auth">
<div className="label">授权管理</div>
<div className="label" data-head-level="h1">授权管理</div>
<div style={{ 'padding-top': '10px' }} className="lab">
<Auth/>
</div>
</div>
<div className="version-tips" data-hits="custom">
<div className="label">自定义样式</div>
<div className="label" data-head-level="h1">自定义样式</div>
<div style={{ 'padding-top': '10px', 'position': 'relative' }} className="lab" onClick={ ()=>this.onClick('custom') }>
<div className="more" style={{ 'cursor': 'pointer' }}>
<div>增强中文阅读体验设置</div>
@ -338,7 +353,7 @@ export default class LabsOpt extends React.Component {
</div>
<div className="version-tips" data-version="1.1.3" data-hits="notice">
<div className="label">消息中心</div>
<div className="label" data-head-level="h1">消息中心</div>
<div style={{ 'padding-top': '10px', 'position': 'relative' }} className="lab">
<Switch width="100%" checked={ this.props.option.notice }
thumbedColor="#3F51B5" trackedColor="#7986CB"

View File

@ -242,8 +242,9 @@ export default class PluginsOpt extends React.Component {
}
componentWillMount() {
$( "head" ).append( '<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/solid.css" integrity="sha384-TbilV5Lbhlwdyc4RuIV/JhD8NR+BfMrvz4BL5QFa2we1hQu6wvREr3v6XSRfCTRp" crossorigin="anonymous">' );
$( "head" ).append( '<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/fontawesome.css" integrity="sha384-ozJwkrqb90Oa3ZNb+yKFW2lToAWYdTiF1vt8JiH5ptTGHTGcN7qdoR1F95e0kYyG" crossorigin="anonymous">' );
$( "head" ).append( '<link rel="stylesheet" class="simpread-fs-style" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/solid.min.css" />' );
$( "head" ).append( '<link rel="stylesheet" class="simpread-fs-style" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/brands.min.css" />' );
$( "head" ).append( '<link rel="stylesheet" class="simpread-fs-style" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/fontawesome.min.css" />' );
storage.Plugins( () => {
decodeURIComponent( location.href ).includes( "#plugins?install=" ) && this.install();
this.setState({ plugins: Object.values( storage.plugins ) });
@ -252,7 +253,7 @@ export default class PluginsOpt extends React.Component {
render() {
return (
<div id="labs" style={{ width: '100%' }}>
<div id="labs" style={{ width: '100%', overflow: 'hidden' }}>
<div className="label">管理</div>
<div className="lab">
<div style={{ display: 'inline-flex', width: '100%' }}>

View File

@ -326,7 +326,7 @@ export default class SitesOpts extends React.Component {
return (
<div id="labs" style={{ width: '100%' }}>
<div className="version-tips" data-hits="newsites">
<div className="label">官方主适配源 <a target="_blank" href="https://simpread.ksria.cn/sites/" style={{ color:' #FF5252', borderBottom: '2px dotted', fontSize: '10px', fontWeight: 'bold', cursor: 'pointer' }}>共计 { storage.simpread.sites.length } </a></div>
<div className="label" data-head-level="h1" data-head-title="官方主适配源">官方主适配源 <a target="_blank" href="https://simpread.ksria.cn/sites/" style={{ color:' #FF5252', borderBottom: '2px dotted', fontSize: '10px', fontWeight: 'bold', cursor: 'pointer' }}>共计 { storage.simpread.sites.length } </a></div>
<div className="lab">
<Button type="raised" text="手动同步适配列表" width="100%"
icon={ ss.IconPath( "update_icon" ) }
@ -336,7 +336,7 @@ export default class SitesOpts extends React.Component {
</div>
</div>
<div className="label">第三方适配源</div>
<div className="label" data-head-level="h1">第三方适配源</div>
<div ref="origins" style={{ 'padding-top': '10px', 'margin-bottom': '8px;' }} className="lab">
<div className="version-tips" data-hits="customsites">
<TextField
@ -366,7 +366,7 @@ export default class SitesOpts extends React.Component {
</div>
<div className="version-tips" data-hits="personsites">
<div className="label">站点集市 <a target="_blank" href="https://simpread.ksria.cn/sites/" style={{ color:' #FF5252', borderBottom: '2px dotted', fontSize: '10px', fontWeight: 'bold', cursor: 'pointer' }}>共计 { storage.pr.sites.person.length } </a></div>
<div className="label" data-head-level="h1" data-head-title="站点集市">站点集市 <a target="_blank" href="https://simpread.ksria.cn/sites/" style={{ color:' #FF5252', borderBottom: '2px dotted', fontSize: '10px', fontWeight: 'bold', cursor: 'pointer' }}>共计 { storage.pr.sites.person.length } </a></div>
<div className="lab">
<div style={{ display: 'inline-flex', width: '100%' }}>
<Button type="raised" text="打开「站点集市」" width="100%"
@ -388,7 +388,7 @@ export default class SitesOpts extends React.Component {
</div>
<div className="version-tips" data-hits="sitemgr">
<div className="label">站点管理器</div>
<div className="label" data-head-level="h1">站点管理器</div>
<div style={{ 'padding-top': '10px', 'position': 'relative' }} className="lab" onClick={ ()=>this.onClick('sitemgr') }>
<div className="more" style={{ 'cursor': 'pointer' }}>
<div>可以管理全部的适配站点</div>

View File

@ -40,6 +40,7 @@ export default class Unrdist extends React.Component {
static propsType = {
list: React.PropTypes.array,
step: React.PropTypes.number,
onLoadMoreClick: React.PropTypes.func,
};
state = {
@ -91,6 +92,7 @@ export default class Unrdist extends React.Component {
onClick() {
this.setState({ page: this.state.page + 1 });
this.props.onLoadMoreClick && this.props.onLoadMoreClick();
}
render() {

115
src/module/urlscheme.jsx Normal file
View File

@ -0,0 +1,115 @@
console.log( "===== simpread url scheme load =====" )
import Switch from 'switch';
import TextField from 'textfield';
import Button from 'button';
import Dropdown from 'dropdown';
import * as puplugin from 'puplugin';
const category = [
{ name: "黑名单", value: "blacklist" },
{ name: "白名单", value: "whitelist" },
{ name: "排除列表", value: "exclusion" },
{ name: "延迟加载", value: "lazyload" },
];
export class URLScheme extends React.Component {
static defaultProps = {
type: "",
url: "",
off: false,
}
static propType = {
type : React.PropTypes.string,
url : React.PropTypes.string,
off : React.PropTypes.bool,
onChange : React.PropTypes.func,
}
state = {
error : "",
disable: false,
};
onDropdownChange( value ) {
this.props.type = value;
}
onURLChange( event ) {
const minimatch = puplugin.Plugin( "minimatch" ),
value = event.target.value.trim();
if ( value == "" ) {
this.setState({ error : "不能为空", disable: true });
} else if ( value.startsWith( "[[/" ) && value.endsWith( "/]]" ) && !new RegExp( value.replace( /\[\[\/|\/\]\]/ig, "" ) ).test( location.href ) ) {
this.setState({ error : "正则表达式错误", disable: true });
} else if ( !value.startsWith( "[[/" ) && !value.startsWith( "http" ) && value != location.hostname.replace( "www.", "" ) ) {
this.setState({ error : "主域名不匹配", disable: true });
} else if ( !value.startsWith( "[[/" ) && value.startsWith( "http" ) && !minimatch( location.href, value ) ) {
this.setState({ error : "minimatch 适配错误", disable: true });
} else {
this.setState({ error : "", disable: false });
this.props.url = value;
}
}
onOpenedChange( value ) {
this.props.off = value;
}
onClose() {
$( this.refs.target )
.addClass( "hide" )[0]
.addEventListener( 'animationend', () => {
ReactDOM.unmountComponentAtNode( $( ".simpread-urlscheme" )[0] );
$( ".simpread-urlscheme" ).remove();
}, false );
}
onSave() {
this.props.onChange && this.props.onChange( this.props.type, this.props.off, this.props.url );
this.onClose();
}
render() {
return (
<simpread-urlscheme ref="target" class="active">
<sr-urls-head>
<sr-urls-label>请选择添加模式</sr-urls-label>
<Dropdown name={ category.filter( item => item.value == this.props.type )[0].name } items={ category } width="100%" onChange={ (v)=>this.onDropdownChange(v) } />
</sr-urls-head>
<sr-urls-content>
<sr-urls-label>支持 域名 · 主域名 · 正则表达式 · minimatch 等规则详细 <sr-urls-a onClick={ ()=>window.open( 'http://ksria.com/simpread/docs/#/右键菜单?id=URL编辑器', '_blank') }>请看这里</sr-urls-a> </sr-urls-label>
<TextField
multi={ false }
value={ this.props.url }
errortext={ this.state.error }
onChange={ (e)=>this.onURLChange(e) }
/>
</sr-urls-content>
<sr-urls-content>
<Switch width="100%" checked={ this.props.off }
thumbedColor="#2163f7" trackedColor="#6699FF" waves="md-waves-effect"
label="默认弹出编辑框,取消后意味着直接保存"
onChange={ (v)=>this.onOpenedChange( v ) } />
</sr-urls-content>
<sr-urls-footer>
<Button text="取 消" mode="secondary" color="#333" waves="md-waves-effect" onClick={ ()=>this.onClose() } />
<Button text="确 认" waves="md-waves-effect" color="#2163f7" disable={ this.state.disable } style={{ 'font-weight': 'bold' }} onClick={ ()=>this.onSave() } />
</sr-urls-footer>
</simpread-urlscheme>
)
}
}
function Render( type, opened, callback ) {
if ( $( "simpread-urlscheme" ).length > 0 ) return;
$( "html" ).append( `<div class="simpread-urlscheme"></div>` );
ReactDOM.render( <URLScheme type={ type } off={ opened } url={ location.href } onChange={ (t,f,v)=>callback(t,f,v) } />, $( ".simpread-urlscheme" )[0] );
}
export {
Render
}

View File

@ -208,7 +208,7 @@ class Welcome extends React.Component {
<h2 style={ style.h2 }>连接你的生产力工具</h2>
<div style={ style.desc }>
支持下载 HTML · PDF · Markdown · PNG · <a target="_blank" href="http://ksria.com/simpread/docs/#/发送到-Epub">Epub</a> 到本地 以及 发送到 <a target="_blank" href="http://ksria.com/simpread/docs/#/发送到-Kindle">Kindle</a><br/>
支持输出到 坚果云 · 语雀 · Dropbox · 印象笔记 · Evernote · Onenote · Google 云端硬盘<br/>
支持输出到 坚果云 · 有道云笔记 · 为知笔记 · 语雀 · 印象笔记 · Dropbox · Onenote · Notion <br/>
发送页面链接到 <a target="_blank" href="http://ksria.com/simpread/docs/#/稍后读">稍后读</a> · Pocket · Instapaper · Linnk详细 <a target="_blank" href="http://ksria.com/simpread/docs/#/导出到生产力工具">请看这里</a>
</div>
</section>
@ -291,6 +291,19 @@ class Welcome extends React.Component {
</section>
</div> }
{ !first && version == "1.1.4" &&
<div className="carousel-item" id="1.1.4">
<section style={ style.section }>
<img src="http://sr.ksria.cn/welcome-newservice-ii.png?202001181335" style={ style.img }/>
<h2 style={ style.h2 }>更强大更易用的导出服务</h2>
<div style={ style.desc }>
期待已久的 <a target="_blank" href="http://ksria.com/simpread/docs/#/Notion">Notion</a> · <a target="_blank" href="http://ksria.com/simpread/docs/#/有道云笔记">有道云笔记</a> · <a target="_blank" href="http://ksria.com/simpread/docs/#/为知笔记">为知笔记</a> · <a target="_blank" href="http://ksria.com/simpread/docs/#/URLSCHEME">Bear</a> · <a target="_blank" href="http://ksria.com/simpread/docs/#/URLSCHEME">Ulysses</a> 来啦~<br/>
原生的 <a target="_blank" href="http://ksria.com/simpread/docs/#/离线HTML">离线 HTML / Markdown</a> 下载功能还有截取任意位置的 <a target="_blank" href="http://ksria.com/simpread/docs/#/截图">截图</a> 功能<br/>
<a target="_blank" href="http://ksria.com/simpread/docs/#/WebDAV?id=定制">WebDAV</a> 现已定制导出格式包括 <span>Markdown</span> · <span>HTML</span>
</div>
</section>
</div> }
{ (( !first && version == "1.1.3" ) || version == "all" ) &&
<div className="carousel-item" id="1.1.3">
<section style={ style.section }>

5
src/options/corb.html Normal file
View File

@ -0,0 +1,5 @@
<html>
<script src="../bundle/common.js"></script>
<script src="../bundle/vendors.js"></script>
<script src="../bundle/corb.js"></script>
</html>

27
src/options/corb.js Normal file
View File

@ -0,0 +1,27 @@
import axios from 'axios';
import {browser} from 'browser';
import * as msg from 'message';
/**
* Listen runtime message, include: `axios`
*/
browser.runtime.onMessage.addListener( function( request, sender, sendResponse ) {
if ( request.type == msg.MESSAGE_ACTION.AXIOS ) {
if ( request.value.type == "post" ) {
if ( request.value.form ) {
request.value.data = new FormData();
Object.keys( request.value.form ).forEach( key => request.value.data.append( key, request.value.form[key] ) );
}
axios.post( request.value.url, request.value.data )
.then( response => sendResponse({ done: response }))
.catch( error => sendResponse({ fail: error }));
} else if ( request.value.type == 'put' ) {
axios.put( request.value.url, request.value.content, request.value.data )
.then( response => sendResponse({ done: response }))
.catch( error => sendResponse({ fail: error }));
}
}
return true;
});

View File

@ -82,8 +82,9 @@
</div>
</div>
<div class="bottom">
<span>简悦 SimpRead - 为你提供「如杂志般沉浸式阅读体验」的扩展</span> <span>&nbsp;©&nbsp;2017&nbsp;-&nbsp;2019&nbsp;<a href="http://ksria.com/simpread">ksria.com</a> by <a href="http://kenshin.wang" target="_blank">Kenshin Wang</a></span>
<span>简悦 SimpRead - 为你提供「如杂志般沉浸式阅读体验」的扩展</span> <span>&nbsp;©&nbsp;2017&nbsp;-&nbsp;2020&nbsp;<a href="http://ksria.com/simpread">ksria.com</a> by <a href="http://kenshin.wang" target="_blank">Kenshin Wang</a></span>
</div>
<script src="../ga.js"></script>
<script src="../bundle/common.js"></script>
<script src="../bundle/vendors.js"></script>
<script src="../bundle/custom.js"></script>

View File

@ -9,8 +9,9 @@
<div class="header"><div class="nav"></div><div class="title">消息中心</div></div>
<div class="notice"></div>
<div class="bottom">
<span>简悦 SimpRead - 为你提供「如杂志般沉浸式阅读体验」的扩展</span> <span>&nbsp;©&nbsp;2017&nbsp;-&nbsp;2019&nbsp;<a href="http://ksria.com/simpread">ksria.com</a> by <a href="http://kenshin.wang" target="_blank">Kenshin Wang</a></span>
<span>简悦 SimpRead - 为你提供「如杂志般沉浸式阅读体验」的扩展</span> <span>&nbsp;©&nbsp;2017&nbsp;-&nbsp;2020&nbsp;<a href="http://ksria.com/simpread">ksria.com</a> by <a href="http://kenshin.wang" target="_blank">Kenshin Wang</a></span>
</div>
<script src="../ga.js"></script>
<script src="../bundle/common.js"></script>
<script src="../bundle/vendors.js"></script>
<script src="../bundle/notice.js"></script>

View File

@ -4,17 +4,23 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>选项页 - 简悦 SimpRead</title>
<style>
.loadingbar{position:fixed;top:0;left:0;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center;height:100%;width:100%;background-color:#fafafa;z-index:200}
</style>
</head>
<body>
<div class="loadingbar"><img class="heartBeat animated" src="/assets/images/icon128.png" width="80px"></div>
<div class="sidebar"></div>
<div class="topnav nav"></div>
<div class="header"><div class="nav"></div><div class="title"></div></div>
<div class="top"></div>
<div class="main">
<div class="tabscontainer"></div>
</div>
<div class="bottom">
<span>简悦 SimpRead - 为你提供「如杂志般沉浸式阅读体验」的扩展</span> <span>&nbsp;©&nbsp;2017&nbsp;-&nbsp;2019&nbsp;<a href="http://ksria.com/simpread">ksria.com</a> by <a href="http://kenshin.wang" target="_blank">Kenshin Wang</a></span>
<div class="bottom" style="opacity:0;">
<span>简悦 SimpRead - 为你提供「如杂志般沉浸式阅读体验」的扩展</span> <span>&nbsp;©&nbsp;2017&nbsp;-&nbsp;2020&nbsp;<a href="http://ksria.com/simpread">ksria.com</a> by <a href="http://kenshin.wang" target="_blank">Kenshin Wang</a></span>
</div>
<script src="../ga.js"></script>
<script src="../bundle/common.js"></script>
<script src="../bundle/vendors.js"></script>
<script src="../bundle/options.js"></script>

View File

@ -2,6 +2,7 @@ console.log( "==== simpread options page load ====" )
import '../assets/css/options_page.css';
import '../assets/css/setting.css';
import 'mduikit_css';
import 'notify_css';
import 'intro_css';
@ -34,6 +35,7 @@ import About from 'about';
import Unrdist from 'unrdist';
import * as welc from 'welcome';
import * as guide from 'guide';
import * as fb from 'feedback';
import PureRead from 'puread';
@ -99,6 +101,7 @@ browser.runtime.onMessage.addListener( function( request, sender, sendResponse )
* @param {number} tab index
*/
function tabChange( idx ) {
if ( idx == -1 ) return;
conf.tabsItem.forEach( ( item, index ) => item.active = idx == index ? true : false );
mainRender( idx );
}
@ -108,19 +111,36 @@ function tabChange( idx ) {
*/
storage.Read( first => {
console.log( "simpread storage get success!", storage.focus, storage.read, first );
loadingRender();
pRead();
hashnotify();
firstLoad( first );
sidebarRender();
navRender();
vernotify( first );
//welcomeRender( false, "1.1.4" );
mainRender( tabsItemID );
setTimeout(() => noticeRender(), 500 );
helpRender();
feedbackRender();
tt.Render( "body" );
waves.Render({ root: "body" });
});
/**
* Loading Render
*/
function loadingRender() {
setTimeout( () => {
$( '.loadingbar' ).animate({
opacity: 0,
}, () => {
$( '.loadingbar' ).remove();
$( ".bottom" ).removeAttr( "style" );
});
}, 1000 );
}
/**
* Pure Read
*/
@ -136,8 +156,10 @@ function pRead() {
function updateData() {
ver.Incompatible( storage.version, storage.simpread ) && storage.Write( () => {
console.log( "current simpread is update ", storage.simpread )
new Notify().Render({ type: 2, content: `检测到你曾经修改过第三方适配源,<b>务必刷新后重新导入</b><a target="_blank" href="http://ksria.com/simpread/docs/#/站点适配源?id=第三方适配源">详细说明</a>`, state: "holdon" });
watch.SendMessage( "option", true );
}, storage.simpread );
ver.VerifyPlugins( storage.option ) && new Notify().Render({ type: 2, content: `有需要清理的已失效插件,详细请看 <a href="http://ksria.com/simpread/welcome/version_${storage.version}.html#badplugins" target="_blank">失效插件</a>`, state: "holdon" });
}
/**
@ -174,9 +196,9 @@ function vernotify( first ) {
if ( hash.startsWith( "#firstload?ver=" ) || hash.startsWith( "#update?ver=" ) ) {
const prefix = hash.match( /\w+/ )[0],
version = hash.match( /[0-9\.]+/ )[0],
msg = ver.Notify( first, prefix, version );
message = ver.Notify( first, prefix, version );
new Notify().Render( "简悦 版本提示", msg );
new Notify().Render( "简悦 版本提示", message );
loadState = { first: true };
if ( hash.startsWith( "#update?ver=" )) {
@ -186,7 +208,7 @@ function vernotify( first ) {
updateData();
}
// website_sync = true; when version is 1.1.3 website_list is newer
browser.runtime.sendMessage({ type: "track", value: { eventAction: hash.startsWith( "#firstload?ver=" ) ? "install" : "update" , eventCategory: "install", eventLabel: "install && update" } });
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.track, { eventCategory: "install", eventAction: hash.startsWith( "#firstload?ver=" ) ? "install" : "update", eventValue: hash.startsWith( "#firstload?ver=" ) ? "install" : "update" }) );
history.pushState( "", "", "/options/options.html" );
} else if ( hash.startsWith( "#update?patch=" ) ) {
const patch = hash.match( /[0-9\.]+/ )[0];
@ -277,17 +299,17 @@ function tabsRender( color ) {
<section style={{ 'padding': '0;' }}>
<LabsOpt option={ storage.option } read={ storage.read } focus={ storage.focus } onChange={ (s)=>save(s) } />
</section>
<section style={{ 'padding': '0;' }}>
<section style={{ 'padding': '0;', 'overflow-x': 'hidden' }}>
<SitesOpts option={ storage.option } onChange={ (s)=>save(s) } />
</section>
<section style={{ 'padding': '0;' }}>
<PluginsOpt />
</section>
<section><Unrdist list={ storage.unrdist.map( item => { return { ...item }} ) } /></section>
<section><Unrdist list={ storage.unrdist.map( item => { return { ...item }} ) } onLoadMoreClick={ ()=> setTimeout( ()=> tt.Render( "list" ), 200 ) } /></section>
<section style={{ 'padding': '0;' }}>
<AccountOps user={ storage.user } load={ loadState } />
</section>
<section style={{ 'padding': '0;' }}><About option={ storage.option } site={ storage.simpread.sites.length } statistics={ storage.simpread.statistics } onClick={t=>welcomeRender(true,"all")}/></section>
<section style={{ 'padding': '0;' }}><About option={ storage.option } site={ storage.simpread.sites.length } statistics={ storage.statistics } onClick={t=>welcomeRender(true,"all")}/></section>
</Tabs>,
tabsOnChange = ( $prev, $target, event ) => {
const idx = $target.attr( "id" );
@ -314,6 +336,7 @@ function navRender() {
};
const button = <Button waves="md-waves-effect md-waves-circle" hoverColor="transparent" icon={ ss.IconPath( "sidebar_icon" ) } onClick={ ()=>navClick() } />;
ReactDOM.render( button, $( ".header .nav" )[0] );
ReactDOM.render( button, $( ".topnav" )[0] );
}
/**
@ -323,10 +346,24 @@ function sidebarRender() {
const sidebarClick = ( $target, items ) => {
const idx = conf.tabsItem.findIndex( item => item.value == items.value );
tabChange( idx );
};
}, newItems = [
{
name: "帮助中心",
value: "help",
fontIcon: "<i class=\"fas fa-question-circle\"></i>",
route: "http://ksria.com/simpread/docs/",
},
{
name: "开源列表",
value: "license",
fontIcon: "<i class=\"fas fa-keyboard\"></i>",
route: "http://ksria.com/simpread/docs/#/开源列表",
},
];
conf.menuItem = conf.menuItem.concat( newItems );
const sidebar = <side.Sidebar items={ conf.menuItem }
waves="md-waves-effect"
header="设定" footer=" 简悦 © 2017" onClick={ ($t,o)=>sidebarClick($t,o) } />;
waves="md-waves-effect" autoClose={false} showClose={ true }
header="设定" footer=" 简悦 © 2017 ~ 2020" onClick={ ($t,o)=>sidebarClick($t,o) } />;
ReactDOM.render( sidebar, $( ".sidebar" )[0] );
}
@ -336,11 +373,10 @@ function sidebarRender() {
function noticeRender() {
sessionStorage.setItem( "is_update", false );
const tmpl = `
<div class="md-waves-effect bubbles notice effect">
<div class="md-waves-effect bubbles notice effect" aria-label="消息中心" data-balloon-pos="up">
<i><svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2555" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24"><defs><style type="text/css"></style></defs><path d="M787.908422 563.765991 787.908422 349.052814c0-152.726403-96.294137-222.682685-223.373417-236.678444 0.031722-0.931209 0.278339-1.811252 0.278339-2.76702 0-27.231201-22.429849-49.288566-50.031487-49.288566-27.662013 0-50.058093 22.057365-50.058093 49.288566 0 0.937348 0.23843 1.804089 0.295735 2.677992-127.636982 13.70207-224.524636 83.607186-224.524636 236.767472l0 214.713176c0 172.349323-442.565605 257.698177 265.890766 257.698177C1214.842001 821.464167 787.908422 736.115314 787.908422 563.765991L787.908422 563.765991zM514.782881 960.670649c52.405557 0 94.916766-41.893132 94.916766-93.54042L419.849742 867.13023C419.849742 918.777517 462.347648 960.670649 514.782881 960.670649L514.782881 960.670649zM514.782881 960.670649" p-id="2556" fill="#ffffff"></path></svg></i>
<em class="init">...</em>
</div>
`;
</div>`;
storage.Notice( result => {
if ( $.isEmptyObject( result ) ) {
storage.notice.latest = 0;
@ -366,19 +402,19 @@ function noticeRender() {
$( "body" ).on( "click", ".notice", event => {
location.href = location.origin + "/options/notice.html?is_update=" + sessionStorage.getItem( "is_update" );
});
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.track, { eventCategory: "help", eventAction: "help", eventValue: "notice" }) );
}
/*
* Help bubbles
*/
function helpRender() {
const help_icon = '<svg t="1560061923091" viewBox="0 0 1024 1024" version="1.1" width="24" height="24"><defs><style type="text/css"></style></defs><path d="M512 704c-187.733333 0-341.333333-153.6-341.333333-341.333333s153.6-341.333333 341.333333-341.333334 341.333333 153.6 341.333333 341.333334-153.6 341.333333-341.333333 341.333333z m0-597.333333c-140.8 0-256 115.2-256 256s115.2 256 256 256 256-115.2 256-256-115.2-256-256-256z" p-id="4789" fill="#ffffff"></path><path d="M512 576c119.466667 0 213.333333-93.866667 213.333333-213.333333s-93.866667-213.333333-213.333333-213.333334-213.333333 93.866667-213.333333 213.333334 93.866667 213.333333 213.333333 213.333333z" p-id="4790" fill="#ffffff"></path><path d="M384 776.533333c0-25.6 21.333333-42.666667 42.666667-42.666666h170.666666c21.333333 0 42.666667 17.066667 42.666667 42.666666s-21.333333 42.666667-42.666667 42.666667h-170.666666c-25.6 0-42.666667-17.066667-42.666667-42.666667z m42.666667 110.933334c0-25.6 17.066667-42.666667 42.666666-42.666667h85.333334c25.6 0 42.666667 17.066667 42.666666 42.666667s-17.066667 42.666667-42.666666 42.666666h-85.333334c-21.333333 0-42.666667-21.333333-42.666666-42.666666z m42.666666 85.333333c0-12.8 8.533333-21.333333 21.333334-21.333333h42.666666c12.8 0 21.333333 8.533333 21.333334 21.333333s-8.533333 21.333333-21.333334 21.333333h-42.666666c-12.8-4.266667-21.333333-12.8-21.333334-21.333333z" p-id="4791" fill="#ffffff"></path></svg>',
close_icon = '<svg t="1560141389230" viewBox="0 0 1024 1024" version="1.1" width="24" height="24"><defs><style type="text/css"></style></defs><path d="M649.179 512l212.839-212.84c37.881-37.881 37.881-99.298 0-137.179s-99.298-37.881-137.179 0L512 374.821l-212.839-212.84c-37.881-37.881-99.298-37.881-137.179 0s-37.881 99.298 0 137.179L374.821 512 161.982 724.84c-37.881 37.881-37.881 99.297 0 137.179 18.94 18.94 43.765 28.41 68.589 28.41 24.825 0 49.649-9.47 68.589-28.41L512 649.179l212.839 212.84c18.94 18.94 43.765 28.41 68.589 28.41s49.649-9.47 68.59-28.41c37.881-37.882 37.881-99.298 0-137.179L649.179 512z" p-id="1990" fill="#ffffff"></path></svg>',
const help_icon = '<svg viewBox="0 0 1024 1024" version="1.1" width="24" height="24"><defs><style type="text/css"></style></defs><path d="M512 704c-187.733333 0-341.333333-153.6-341.333333-341.333333s153.6-341.333333 341.333333-341.333334 341.333333 153.6 341.333333 341.333334-153.6 341.333333-341.333333 341.333333z m0-597.333333c-140.8 0-256 115.2-256 256s115.2 256 256 256 256-115.2 256-256-115.2-256-256-256z" p-id="4789" fill="#ffffff"></path><path d="M512 576c119.466667 0 213.333333-93.866667 213.333333-213.333333s-93.866667-213.333333-213.333333-213.333334-213.333333 93.866667-213.333333 213.333334 93.866667 213.333333 213.333333 213.333333z" fill="#ffffff"></path><path d="M384 776.533333c0-25.6 21.333333-42.666667 42.666667-42.666666h170.666666c21.333333 0 42.666667 17.066667 42.666667 42.666666s-21.333333 42.666667-42.666667 42.666667h-170.666666c-25.6 0-42.666667-17.066667-42.666667-42.666667z m42.666667 110.933334c0-25.6 17.066667-42.666667 42.666666-42.666667h85.333334c25.6 0 42.666667 17.066667 42.666666 42.666667s-17.066667 42.666667-42.666666 42.666666h-85.333334c-21.333333 0-42.666667-21.333333-42.666666-42.666666z m42.666666 85.333333c0-12.8 8.533333-21.333333 21.333334-21.333333h42.666666c12.8 0 21.333333 8.533333 21.333334 21.333333s-8.533333 21.333333-21.333334 21.333333h-42.666666c-12.8-4.266667-21.333333-12.8-21.333334-21.333333z" p-id="4791" fill="#ffffff"></path></svg>',
close_icon = '<svg viewBox="0 0 1024 1024" version="1.1" width="24" height="24"><defs><style type="text/css"></style></defs><path d="M649.179 512l212.839-212.84c37.881-37.881 37.881-99.298 0-137.179s-99.298-37.881-137.179 0L512 374.821l-212.839-212.84c-37.881-37.881-99.298-37.881-137.179 0s-37.881 99.298 0 137.179L374.821 512 161.982 724.84c-37.881 37.881-37.881 99.297 0 137.179 18.94 18.94 43.765 28.41 68.589 28.41 24.825 0 49.649-9.47 68.589-28.41L512 649.179l212.839 212.84c18.94 18.94 43.765 28.41 68.589 28.41s49.649-9.47 68.59-28.41c37.881-37.882 37.881-99.298 0-137.179L649.179 512z" fill="#ffffff"></path></svg>',
tmpl = `
<div class="md-waves-effect bubbles help effect">
<div class="md-waves-effect bubbles help effect" aria-label="帮助中心" data-balloon-pos="up">
<i>${help_icon}</i>
</div>
`,
</div>`,
exit = () => {
ReactDOM.unmountComponentAtNode( $( ".guide-bg" )[0] );
$( ".help i" ).html( help_icon ).css({ "animation": ".1s reverse fadein,235ms cubic-bezier(.4,0,.2,1) popdown" });
@ -394,4 +430,21 @@ function helpRender() {
exit();
}
});
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.track, { eventCategory: "help", eventAction: "help", eventValue: "help" }) );
}
/*
* Feedback bubbles
*/
function feedbackRender() {
const tmpl = `
<div class="md-waves-effect bubbles feedback effect" aria-label="给我反馈" data-balloon-pos="up">
<i><svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M896 981.333333l-213.333333-128H213.333333c-46.933333 0-85.333333-38.4-85.333333-85.333333V128c0-46.933333 38.4-85.333333 85.333333-85.333333h597.333334c46.933333 0 85.333333 38.4 85.333333 85.333333v853.333333zM298.666667 512c-8.533333 0-12.8 0-21.333334 4.266667s-17.066667 17.066667-21.333333 25.6c0 12.8 0 25.6 4.266667 34.133333 55.466667 93.866667 153.6 149.333333 260.266666 149.333333 106.666667 0 204.8-55.466667 260.266667-149.333333 4.266667-8.533333 8.533333-21.333333 4.266667-34.133333-4.266667-12.8-8.533333-21.333333-21.333334-25.6-8.533333-4.266667-12.8-4.266667-21.333333-4.266667-17.066667 0-29.866667 8.533333-38.4 21.333333C665.6 597.333333 597.333333 640 520.533333 640c-76.8 0-145.066667-42.666667-183.466666-106.666667-8.533333-12.8-21.333333-21.333333-38.4-21.333333z" fill="#ffffff"></path></svg></i>
</div>`;
$( "body" ).append( tmpl );
$( "body" ).on( "click", ".feedback", event => {
fb.Render( storage.version, storage.user );
setTimeout( () => tt.Render( ".simpread-feedback" ), 200 );
});
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.track, { eventCategory: "help", eventAction: "help", eventValue: "feedback" }) );
}

View File

@ -21,8 +21,9 @@
</div>
</div>
<div class="bottom">
<span>简悦 SimpRead - 为你提供「如杂志般沉浸式阅读体验」的扩展</span> <span>&nbsp;©&nbsp;2017&nbsp;-&nbsp;2019&nbsp;<a href="http://ksria.com/simpread">ksria.com</a> by <a href="http://kenshin.wang" target="_blank">Kenshin Wang</a></span>
<span>简悦 SimpRead - 为你提供「如杂志般沉浸式阅读体验」的扩展</span> <span>&nbsp;©&nbsp;2017&nbsp;-&nbsp;2020&nbsp;<a href="http://ksria.com/simpread">ksria.com</a> by <a href="http://kenshin.wang" target="_blank">Kenshin Wang</a></span>
</div>
<script src="../ga.js"></script>
<script src="../bundle/common.js"></script>
<script src="../bundle/vendors.js"></script>
<script src="../bundle/sitemgr.js"></script>

View File

@ -109,7 +109,7 @@ export default class ReadCtlbar extends React.Component {
break;
default:
if ( type.indexOf( "_" ) > 0 && type.startsWith( "share" ) ||
[ "fullscreen", "save", "markdown", "png", "epub", "pdf", "kindle", "temp", "html", "dropbox", "pocket", "instapaper", "linnk", "yinxiang","evernote", "onenote", "gdrive", "jianguo", "yuque" ].includes( type )) {
[ "fullscreen", "save", "markdown", "offlinemarkdown", "png", "epub", "pdf", "kindle", "temp", "bear", "ulysses", "html", "offlinehtml", "snapshot", "dropbox", "pocket", "instapaper", "linnk", "yinxiang", "evernote", "onenote", "gdrive", "jianguo", "yuque", "notion", "youdao", "weizhi" ].includes( type )) {
const [ title, desc, content ] = [ $( "sr-rd-title" ).text().trim(), $( "sr-rd-desc" ).text().trim(), $( "sr-rd-content" ).html().trim() ];
output.Action( type, title, desc, content );
}
@ -159,6 +159,10 @@ export default class ReadCtlbar extends React.Component {
if ( this.props.type.startsWith( "metaread::" ) || this.props.type.startsWith( "txtread::" ) ) {
delete readItems.option;
}
if ( !/macintosh|mac os x/i.test(navigator.userAgent) ) {
delete readItems.send.items.bear;
delete readItems.send.items.ulysses;
}
storage.Safe( () => {
storage.secret.webdav.forEach( item => {
item = JSON.parse( item );

View File

@ -7,6 +7,7 @@ import * as toc from 'toc';
import * as setting from 'setting';
import * as se from 'siteeditor';
import * as kbd from 'keyboard';
import * as fb from 'feedback';
import { storage, Clone } from 'storage';
import th from 'theme';
@ -15,6 +16,7 @@ import {browser} from 'browser';
import * as msg from 'message';
import * as highlight from 'highlight';
import * as run from 'runtime';
import * as tips from 'tips';
import * as tooltip from 'tooltip';
import * as waves from 'waves';
@ -31,12 +33,10 @@ let load_count = 0;
const Footer = () => {
const good_icon = '<svg t="1556354786433" viewBox="0 0 1024 1024" version="1.1" width="33" height="33"><defs><style type="text/css"></style></defs><path d="M859.8 191.2c-80.8-84.2-212-84.2-292.8 0L512 248.2l-55-57.2c-81-84.2-212-84.2-292.8 0-91 94.6-91 248.2 0 342.8L512 896l347.8-362C950.8 439.4 950.8 285.8 859.8 191.2z" p-id="6225" fill="#8C8C8C"></path></svg>',
bad_icon = '<svg t="1556354650943" viewBox="0 0 1024 1024" version="1.1" p-id="5899" width="33" height="33"><defs><style type="text/css"></style></defs><path d="M458 576c2-36 0-76 16-110 4-10 2-20 2-30-8-42-28-80-30-120 0-2.78 2.008-9.542 2.01-12.314-6.432 4.468-15.214 8.048-22.01 10.314-40 12-35.02 5.146-69.02 27.146l-23.866 14.456c32.686-35.878 77.056-49.562 113.05-77.428 0.388-30.876 1.716-61.354 6.274-91.68C371.22 106.992 243.57 108.536 164.246 191.14c-90.994 94.688-90.994 248.202 0 342.89l305.698 318.192c-0.17-21.312-0.886-42.352-3.944-62.222C454 718 458 648 458 576z" p-id="5900" fill="#8C8C8C"></path><path d="M644 602c-22-52-66-88-126-100-1.7 0-3.758-1.086-5.872-2.638-0.046 0.214-0.082 0.426-0.128 0.638-22 96-46 188-42 284 0 24.454 7.966 50.234 7.666 76.262L512 896l208-216.5C690.306 658.542 660.856 637.242 644 602z" p-id="5901" fill="#8C8C8C"></path><path d="M859.748 191.14c-80.852-84.188-211.978-84.188-292.816 0L528 230.806c0.15 26.35 0.426 52.404-6 77.194-4 20-38 38-32 62 6.006 26.426 16.332 51.41 21.464 77.118C542.028 464.168 569.542 485.792 594 512c45.602 53.532 75.494 114.918 130.566 162.742l135.182-140.71C950.75 439.342 950.75 285.828 859.748 191.14z" p-id="5902" fill="#8C8C8C"></path></svg>',
onClick = () => {
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.CORB, { settings: { url: storage.service + "/sites/service/pending", type: "POST", data:{url: location.href, site: storage.pr.current.site, uid: storage.user.uid, type: "failed"} }}), result => {
console.log( 'Add stat sites', result )
});
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.new_tab, { url: "https://wj.qq.com/s2/3611463/7260/" }));
};
onClick = ( rate = false ) => {
fb.Render( storage.version, storage.user, rate );
setTimeout( () => tooltip.Render( ".simpread-feedback" ), 200 );
};
return (
<sr-rd-footer>
<sr-rd-footer-group>
@ -48,8 +48,8 @@ const Footer = () => {
<div>本文由 <a href="http://ksria.com/simpread" target="_blank">简悦 SimpRead</a> 优化用以提升阅读体验</div>
<div className="second">使用了 <abbr>全新的简悦词法分析引擎<sup>beta</sup></abbr><a target="_blank" href="http://ksria.com/simpread/docs/#/词法分析引擎">点击查看</a>详细说明</div>
<div className="third">
<a className="sr-icon good sr-top" data-sr-mini-tooltip="觉得不错?请帮忙投票 😄" data-position="up" target="_blank" href="https://chrome.google.com/webstore/detail/%E7%AE%80%E6%82%A6-simpread/ijllcpnolfcooahcekpamkbidhejabll/reviews" dangerouslySetInnerHTML={{__html: good_icon }} ></a>
<a className="sr-icon bad sr-top" data-sr-mini-tooltip="有待改进,请帮忙吐槽 😄" data-position="up" target="_blank" onClick={ ()=>onClick() } dangerouslySetInnerHTML={{__html: bad_icon }} ></a>
<a className="sr-icon good sr-top" aria-label="觉得不错?请帮忙投票 😄" data-balloon-pos="up" target="_blank" onClick={ ()=>onClick( true ) } dangerouslySetInnerHTML={{__html: good_icon }} ></a>
<a className="sr-icon bad sr-top" aria-label="有待改进,请帮忙吐槽 😄" data-balloon-pos="up" target="_blank" onClick={ ()=>onClick() } dangerouslySetInnerHTML={{__html: bad_icon }} ></a>
</div>
</sr-rd-footer-copywrite>
</sr-rd-footer>
@ -104,9 +104,9 @@ class Read extends React.Component {
$( "body" ).addClass( "simpread-hidden" );
th.Change( this.props.read.theme );
if ( storage.current.fap ) {
$( "head" ).append( '<link rel="stylesheet" class="simpread-fs-style" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.1/css/solid.min.css" />' );
$( "head" ).append( '<link rel="stylesheet" class="simpread-fs-style" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.1/css/brands.min.css" />' );
$( "head" ).append( '<link rel="stylesheet" class="simpread-fs-style" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.1/css/fontawesome.min.css" />' );
$( "head" ).append( '<link rel="stylesheet" class="simpread-fs-style" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/solid.min.css" />' );
$( "head" ).append( '<link rel="stylesheet" class="simpread-fs-style" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/brands.min.css" />' );
$( "head" ).append( '<link rel="stylesheet" class="simpread-fs-style" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/fontawesome.min.css" />' );
}
}
@ -141,6 +141,7 @@ class Read extends React.Component {
tooltip.Render( rdclsjq );
waves.Render({ root: rdclsjq });
storage.Statistics( "read" );
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.track, { eventCategory: "mode", eventAction: "readmode", eventValue: "readmode" }) );
!this.props.wrapper.avatar && this.props.read.toc
&& toc.Render( "sr-read", $( "sr-rd-content" ), this.props.read.theme, this.props.read.toc_hide );
@ -151,6 +152,8 @@ class Read extends React.Component {
setTimeout( ()=>{
this.verifyContent();
tips.Render( storage.option.plugins );
tips.Help( storage.statistics );
}, 50 );
}

View File

@ -9,6 +9,11 @@ const keyboard = {
"type" : "markdown",
"desc" : "导出为 Markdown",
},
om: {
"kbd" : "om",
"type" : "offlinemarkdown",
"desc" : "导出为 离线 Markdown",
},
pg: {
"kbd" : "pg",
"type" : "png",
@ -28,7 +33,22 @@ const keyboard = {
"kbd" : "hm",
"type" : "html",
"desc" : "导出为 HTML",
}
},
oh: {
"kbd" : "oh",
"type" : "offlinehtml",
"desc" : "导出为 离线 HTML",
},
tm: {
"kbd" : "tm",
"type" : "temp",
"desc" : "导出为 临时页面",
},
cp: {
"kbd" : "cp",
"type" : "snapshot",
"desc" : "截图",
},
},
"控制栏 - 其它" : {
ff: {
@ -93,6 +113,11 @@ const keyboard = {
"type" : "yuque",
"desc" : "保存到 语雀",
},
wz: {
"kbd" : "wz",
"type" : "weizhi",
"desc" : "保存到 为知笔记",
},
kd: {
"kbd" : "kd",
"type" : "kindle",
@ -118,10 +143,15 @@ const keyboard = {
"type" : "save",
"desc" : "保存到 稍后读",
},
tm: {
"kbd" : "tm",
"type" : "temp",
"desc" : "生成临时页面",
br: {
"kbd" : "br",
"type" : "bear",
"desc" : "保存到 Bear",
},
ul: {
"kbd" : "ul",
"type" : "ulysses",
"desc" : "保存到 Ulysses",
},
},
"控制栏 - 无障碍" : {
@ -286,11 +316,26 @@ const readItems = {
"icon" : ss.IconPath("markdown_icon"),
"color": "#D4237A",
},
"offlinemarkdown" : {
"name" : "导出为 离线 MD",
"icon" : ss.IconPath("offline_markdown_icon"),
"color": "#D4237A",
},
"html" : {
"name" : "导出为 HTML",
"icon" : ss.IconPath("html_icon"),
"color": "#D4237A",
},
"offlinehtml" : {
"name" : "导出为 离线 HTML",
"icon" : ss.IconPath("offline_html_icon"),
"color": "#D4237A",
},
"snapshot" : {
"name" : "截图",
"icon" : ss.IconPath("snapshot_icon"),
"color": "#D4237A",
},
},
},
"send" : {
@ -333,6 +378,21 @@ const readItems = {
"icon" : ss.IconPath("yuque_icon"),
"color": "#00BCD4",
},
"notion" : {
"name" : "保存到 Notion",
"icon" : ss.IconPath("notion_icon"),
"color": "#00BCD4",
},
"youdao" : {
"name" : "保存到 有道云笔记",
"icon" : ss.IconPath("youdao_icon"),
"color": "#00BCD4",
},
"weizhi" : {
"name" : "保存到 为知笔记",
"icon" : ss.IconPath("wiz_icon"),
"color": "#00BCD4",
},
"kindle" : {
"name" : "保存到 Kindle",
"icon" : ss.IconPath("kindle_icon"),
@ -343,6 +403,16 @@ const readItems = {
"icon" : ss.IconPath("temp_icon"),
"color": "#00BCD4",
},
"bear" : {
"name" : "保存到 Bear",
"icon" : ss.IconPath("bear_icon"),
"color": "#00BCD4",
},
"ulysses" : {
"name" : "保存到 Ulysses",
"icon" : ss.IconPath("ulysses_icon"),
"color": "#00BCD4",
},
},
},
"dyslexia" : {
@ -586,6 +656,9 @@ const focusItems = ( items => {
dels.forEach( del => delete news[ del ] );
delete news.option.items.fullscreen;
delete news.option.items.tempread;
delete news.download.items.snapshot;
delete news.download.items.offlinehtml;
delete news.download.items.offlinemarkdown;
news.top = {
"name" : "返回顶部",
"icon" : ss.IconPath("top_icon"),
@ -653,28 +726,28 @@ const tabsItem = [{
switch ( idx ) {
case 0:
delete menu.active;
menu.icon = ss.IconPath( "common_icon" );
menu.fontIcon = '<i class="fas fa-sync-alt"></i>';
break;
case 1:
menu.icon = ss.IconPath( "focus_mode_icon" );
menu.fontIcon = '<i class="fas fa-wrench"></i>';
break;
case 2:
menu.icon = ss.IconPath( "read_mode_icon" );
menu.fontIcon = '<i class="fas fa-tools"></i>';
break;
case 3:
menu.icon = ss.IconPath( "labs_icon" );
menu.fontIcon = '<i class="fas fa-sitemap"></i>';
break;
case 4:
menu.icon = ss.IconPath( "plugins_icon" );
menu.fontIcon = '<i class="fas fa-plug"></i>';
break;
case 5:
menu.icon = ss.IconPath( "read_later_icon" );
menu.fontIcon = '<i class="fas fa-inbox"></i>';
break;
case 6:
menu.icon = ss.IconPath( "about_icon" );
menu.fontIcon = '<i class="fas fa-user"></i>';
break;
case 7:
menu.icon = ss.IconPath( "help_icon" );
menu.fontIcon = '<i class="fas fa-info-circle"></i>';
break;
}
return menu;

View File

@ -10,6 +10,7 @@ import Instapaper from 'instapaper';
import * as msg from 'message';
import {browser} from 'browser';
import * as puplugin from 'puplugin';
import * as wiz from 'wiz';
/**
* Create PNG
@ -130,6 +131,9 @@ function unlink( id ) {
"onenote" : "https://account.live.com/consent/Manage",
"gdrive" : "https://drive.google.com/drive/my-drive",
"yuque" : "https://www.yuque.com/yuque/developer/delete-oauth-apps",
"notion" : "http://ksria.com/simpread/docs/#/授权服务?id=取消授权",
"youdao" : "http://ksria.com/simpread/docs/#/授权服务?id=取消授权",
"weizhi" : "http://ksria.com/simpread/docs/#/授权服务?id=取消授权",
"jianguo" : "http://help.jianguoyun.com/?p=2064",
"linnk" : "https://linnk.net/",
}
@ -399,12 +403,10 @@ class Ins {
this.ins.token_secret = this.token_secret;
this.ins.consumer_key = this.consumer_key;
this.ins.consumer_secret = this.consumer_secret;
this.ins.add( url, title, description ).done( result => {
if ( result && result.length > 0 ) callback( "success", undefined );
else callback( undefined, "error" );
}).fail( ( jqXHR, textStatus, error ) => {
console.error( jqXHR, textStatus, error )
callback( undefined, textStatus );
const settings = this.ins.add( url, title, description );
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.CORB, { settings } ), result => {
if ( result.done ) { callback( "success", undefined ); }
else callback( undefined, result.fail );
});
}
}
@ -463,33 +465,36 @@ class Linnk {
targetURL: url,
title,
tagsStr : this.tags,
};
$.ajax({
},
settings = {
url : "https://linnk.net/a/api/bookmark/new",
type : "POST",
headers : { Authorization: this.access_token },
data,
}).done( ( result, textStatus, jqXHR ) => {
const data = JSON.parse(result);
if ( data && data.code == 200 ) callback( "success", undefined );
else callback( undefined, "error" );
}).fail( ( jqXHR, textStatus, error ) => {
console.error( jqXHR, textStatus, error )
callback( undefined, textStatus );
};
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.CORB, { settings } ), result => {
if ( result.done ) {
const data = JSON.parse( result.done );
if ( data && data.code == 200 ) callback( "success", undefined );
else callback( undefined, "error" );
} else callback( undefined, result.fail );
});
}
Groups( callback ) {
$.ajax({
const settings = {
url : "https://linnk.net/a/api/group/my",
type : "GET",
headers : { Authorization: this.access_token },
}).done( ( result, textStatus, jqXHR ) => {
callback( JSON.parse(result), undefined );
}).fail( ( jqXHR, textStatus, error ) => {
console.error( jqXHR, textStatus, error )
callback( undefined, textStatus );
};
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.CORB, { settings } ), result => {
if ( result.done ) {
const data = JSON.parse( result.done );
if ( data.code != 200 ) {
callback( undefined, this.error_code[ data.code ] );
} else callback( data, undefined );
} else callback( undefined, "error" );
});
}
@ -500,27 +505,27 @@ class Linnk {
}
NewGroup( name, callback ) {
$.ajax({
const settings = {
url : "https://linnk.net/a/api/group/new",
type : "POST",
headers : { Authorization: this.access_token },
data : { groupName: name },
}).done( ( result, textStatus, jqXHR ) => {
callback( JSON.parse(result), undefined );
}).fail( ( jqXHR, textStatus, error ) => {
console.error( jqXHR, textStatus, error )
callback( undefined, textStatus );
};
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.CORB, { settings } ), result => {
if ( result.done ) {
callback( JSON.parse( result.done ), undefined );
} else callback( undefined, result.fail );
});
}
GetSafeGroup( name, callback ) {
this.Groups( result => {
this.Groups( ( result, error ) => {
if ( result && result.code == 200 ) {
const group = this.GetGroup( name, result.data );
!group && this.NewGroup( name, callback );
group && callback({ data: group, code: 200 }, undefined );
} else {
callback( undefined, "error" );
callback( undefined, error == "error" ? "error" : error );
}
})
}
@ -1229,6 +1234,366 @@ class Yuque {
}
}
/**
* Notion
*
* @class
*/
class Notion {
get id() { return "notion"; }
get name() { return name( this.id ); }
get url() {
return "https://www.notion.so/";
}
UUID() {
var __extends=void 0&&(void 0).__extends||function(){var _extendStatics=function extendStatics(d,b){_extendStatics=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(d,b){d.__proto__=b}||function(d,b){for(var p in b)if(b.hasOwnProperty(p))d[p]=b[p]};return _extendStatics(d,b)};return function(d,b){_extendStatics(d,b);function __(){this.constructor=d}d.prototype=b===null?Object.create(b):(__.prototype=b.prototype,new __())}}();var ValueUUID=function(){function ValueUUID(_value){this._value=_value;this._value=_value}ValueUUID.prototype.asHex=function(){return this._value};return ValueUUID}();var V4UUID=function(_super){__extends(V4UUID,_super);function V4UUID(){return _super.call(this,[V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),'-',V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),'-','4',V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),'-',V4UUID._oneOf(V4UUID._timeHighBits),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),'-',V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex()].join(''))||this}V4UUID._oneOf=function(array){return array[Math.floor(array.length*Math.random())]};V4UUID._randomHex=function(){return V4UUID._oneOf(V4UUID._chars)};V4UUID._chars=['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];V4UUID._timeHighBits=['8','9','a','b'];return V4UUID}(ValueUUID);function generateUuid(){return new V4UUID().asHex()}
return generateUuid();
}
Auth( callback ) {
$.ajax({
url : this.url + "api/v3/loadUserContent",
type : "POST",
}).done( ( result, status, xhr ) => {
if ( result && status == "success" ) {
this.access_token = Object.values( result.recordMap.notion_user )[0].value.id;
this.folder_id = Object.values( result.recordMap.block )[0].value.id;
this.blocks = Object.values( result.recordMap.block ).map( item => {
return { name: item.value.properties ? item.value.properties.title[0][0] : "Undefined", value: item.value.id }
});
callback( result, undefined );
}
}).fail( ( xhr, status, error ) => {
console.error( error, status, xhr )
callback( undefined, xhr.status == 401 ? `请先 <a target="_blank" href="https://www.notion.so/">登录 Notion</a> ` : "请稍后再试" );
});
}
Add( title, content, callback ) {
this.TempFile( this.folder_id, title, ( documentId, error ) => {
console.log( 'TempFile: ', documentId )
if ( error ) {
callback( undefined, error );
} else this.GetFileUrl( `${title}.md`, urls => {
console.log( 'GetFileUrl: ', urls )
this.WriteFile( urls.signedPutUrl, content, result => {
console.log( 'WriteFile: ', result )
this.ImportFile( urls.url, `${title}.md`, documentId, result => {
console.log( 'ImportFile: ', result )
result.done && callback( result, undefined );
result.fail && callback( undefined, "error" );
});
});
});
});
}
TempFile( parentId, title, callback ) {
const documentId = this.UUID(),
userId = this.access_token,
time = new Date().getDate(),
operations = {
operations: [
{
id: documentId,
table: 'block',
path: [],
command: 'set',
args: {
type: 'page',
id: documentId,
version: 1,
},
},
{
id: documentId,
table: 'block',
path: [],
command: 'update',
args: {
parent_id: parentId,
parent_table: 'block',
alive: true,
},
},
{
table: 'block',
id: parentId,
path: ['content'],
command: 'listAfter',
args: { id: documentId },
},
{
id: documentId,
table: 'block',
path: [],
command: 'update',
args: {
created_by: userId,
created_time: time,
last_edited_time: time,
last_edited_by: userId,
},
},
{
id: parentId,
table: 'block',
path: [],
command: 'update',
args: { last_edited_time: time },
},
{
id: documentId,
table: 'block',
path: ['properties', 'title'],
command: 'set',
args: [[title]],
},
{
id: documentId,
table: 'block',
path: [],
command: 'update',
args: { last_edited_time: time },
},
],
};
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.AXIOS, {
type: "post",
url: this.url + "api/v3/submitTransaction",
data: operations
}), result => {
result.done && callback( documentId, undefined );
result.fail && callback( undefined, result.fail.message.includes( '401' ) ? `授权已过期,请重新授权。` : "请稍后再试" );
});
}
GetFileUrl( name, callback ) {
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.AXIOS, {
type: "post",
url: this.url + "api/v3/getUploadFileUrl",
data:{
bucket: 'temporary',
name: name,
contentType: 'text/markdown',
}
}), result => {
if ( result && result.done ) {
callback( result.done.data );
}
});
}
WriteFile( url, content, callback ) {
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.AXIOS, {
type: "put",
url,
content,
data: {
headers: {
'Content-Type': 'text/markdown'
}
}
}), result => {
if ( result && result.done ) {
callback( result.done );
}
});
}
ImportFile( url, name, documentId, callback ) {
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.AXIOS, {
type: "post",
url: this.url + "api/v3/enqueueTask",
data: {
task: {
eventName: 'importFile',
request: {
fileURL: url,
fileName: name,
importType: 'ReplaceBlock',
pageId: documentId,
},
}
}
}), result => callback( result ));
}
}
/**
* Youdao
*
* @class
*/
class Youdao {
get id() { return "youdao"; }
get name() { return name( this.id ); }
get url() {
return "https://note.youdao.com";
}
get permissions() {
return {
permissions: [ 'cookies' ],
origins: [ 'https://*.youdao.com/' ]
};
}
UUID() {
var __extends=void 0&&(void 0).__extends||function(){var _extendStatics=function extendStatics(d,b){_extendStatics=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(d,b){d.__proto__=b}||function(d,b){for(var p in b)if(b.hasOwnProperty(p))d[p]=b[p]};return _extendStatics(d,b)};return function(d,b){_extendStatics(d,b);function __(){this.constructor=d}d.prototype=b===null?Object.create(b):(__.prototype=b.prototype,new __())}}();var ValueUUID=function(){function ValueUUID(_value){this._value=_value;this._value=_value}ValueUUID.prototype.asHex=function(){return this._value};return ValueUUID}();var V4UUID=function(_super){__extends(V4UUID,_super);function V4UUID(){return _super.call(this,[V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),'-',V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),'-','4',V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),'-',V4UUID._oneOf(V4UUID._timeHighBits),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),'-',V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex(),V4UUID._randomHex()].join(''))||this}V4UUID._oneOf=function(array){return array[Math.floor(array.length*Math.random())]};V4UUID._randomHex=function(){return V4UUID._oneOf(V4UUID._chars)};V4UUID._chars=['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];V4UUID._timeHighBits=['8','9','a','b'];return V4UUID}(ValueUUID);function generateUuid(){return new V4UUID().asHex()}
return generateUuid();
}
Cookies( callback ) {
browser.cookies.get({
url: this.url,
name: 'YNOTE_CSTK',
}, cookie => {
callback( cookie );
})
}
Auth( callback ) {
this.Cookies( token => {
if ( !token ) {
callback( undefined, `请先 <a target="_blank" href="https://note.youdao.com/web">登录有道云笔记</a> ` );
return;
}
this.access_token = token.value;
const formData = new FormData();
formData.append( 'path', '/' );
formData.append( 'dirOnly', 'true' );
formData.append( 'f', 'true');
formData.append( 'cstk', this.access_token );
$.ajax({
url : this.url + `/yws/api/personal/file?method=listEntireByParentPath&keyfrom=web&cstk=${this.access_token}`,
type : "POST",
contentType: false,
processData: false,
data : formData
}).done( ( result, status, xhr ) => {
if ( result && result.length > 0 ) {
this.folder_id = result[0].fileEntry.id;
this.folders = result.map( item => {
return { name: item.fileEntry.name, value: item.fileEntry.id };
});
callback( result, undefined );
}
}).fail( ( xhr, status, error ) => {
console.error( error, status, xhr )
callback( undefined, xhr.status == 500 ? `请先 <a target="_blank" href="https://note.youdao.com/web">登录有道云笔记</a> ` : "请稍后再试" );
});
});
}
Add( title, content, callback ) {
const timestamp = String( Math.floor( Date.now() / 1000 )),
uuid = this.UUID().replace( /-/g, '' ),
fileId = `WEB${uuid}`;
let formData = {};
formData[ 'fileId' ] = fileId;
formData[ 'parentId' ] = this.folder_id;
formData[ 'name' ] = `${title}.md`;
formData[ 'domain' ] = `1`;
formData[ 'rootVersion' ] = `-1`;
formData[ 'dir' ] = `false`;
formData[ 'sessionId' ] = '';
formData[ 'createTime' ] = timestamp;
formData[ 'modifyTime' ] = timestamp;
formData[ 'transactionId' ] = fileId;
formData[ 'bodyString' ] = content;
formData[ 'transactionTime' ] = timestamp;
formData[ 'cstk' ] = this.access_token;
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.AXIOS, {
type: "post",
url : this.url + `/yws/api/personal/sync?method=push&keyfrom=web&cstk=${this.access_token}`,
form: formData,
}), result => {
if ( result.fail ) callback( undefined, result.fail.message.includes( '500' ) ? `授权已过期,请重新授权。` : "请稍后再试" );
else callback( result, undefined );
});
}
}
/**
* Wiz
*
* @class
*/
class Wiz {
get id() { return "weizhi"; }
get name() { return name( this.id ); }
get tag() {
return "SimpRead";
}
get category() {
return "/My Notes/";
}
Auth( user, password, callback ) {
const data = {
userId : user,
password : password,
autoLogin: true,
};
$.ajax({
url : "https://note.wiz.cn/as/user/login?clientType=webclip_chrome&clientVersion=4.0.10&apiVersion=10&lang=zh-CN",
type : "POST",
dataType: "JSON",
contentType: "application/json; charset=utf-8",
data : JSON.stringify(data),
}).done( ( result, textStatus, jqXHR ) => {
result && result.returnCode == 200 && ( this.access_token = result.result.userGuid );
callback( result, undefined );
}).fail( ( jqXHR, textStatus, error ) => {
console.error( jqXHR, textStatus, error )
callback( undefined, textStatus );
});
}
Add( url, title, content, callback ) {
const info = {
title,
url,
category: this.category,
cmd : "save_content",
comment : "",
tag : this.tag,
userid : this.username,
params : wiz.getParams( url, title, content ),
};
let data = wiz.getInfos( info, this.access_token );
data = JSON.stringify( data );
const options = {
url : "https://kshttps0.wiz.cn/ks/gather?clientType=webclip_chrome&clientVersion=4.0.10&apiVersion=10&lang=zh-CN",
type : "POST",
dataType: "JSON",
contentType: "application/json; charset=utf-8",
async: true,
cache: false,
data,
};
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.CORB, { settings: options }), result => {
if ( result && result.done && result.done.return_code == 200 ) callback( result, undefined );
else if ( result && result.done ) callback( undefined, result.done.return_code == 301 ? `授权已过期,请重新授权。` : "请稍后再试" );
else callback( undefined, result.fail );
});
}
}
/**
* Kindle
*
@ -1246,7 +1611,7 @@ class Kindle {
}
get server() {
return "http://fivefilters.org/kindle-it/send.php";
return "https://pushtokindle.fivefilters.org/send.php";
}
Read( url, title, desc, content, style, callback ) {
@ -1292,7 +1657,7 @@ class Kindle {
*/
function name( type ) {
type = type.toLowerCase();
if ( [ "dropbox", "pocket", "instapaper", "linnk" , "evernote", "onenote" ].includes( type ) ) {
if ( [ "dropbox", "pocket", "instapaper", "linnk" , "evernote", "onenote", "notion" ].includes( type ) ) {
return type.replace( /\S/i, $0=>$0.toUpperCase() );
} else if ( type == "yinxiang" ) {
return "印象笔记";
@ -1302,6 +1667,10 @@ function name( type ) {
return "坚果云";
} else if ( type == "yuque" ) {
return "语雀";
} else if ( type == "youdao" ) {
return "有道云笔记";
} else if ( type == "weizhi" ) {
return "为知笔记";
}
return type;
}
@ -1376,7 +1745,7 @@ function verifyService( storage, service, type, name, notify, auto = true ) {
dtd.resolve( type );
} else {
auto ? notify.Render( `请先获取 ${name} 的授权,才能使用此功能!`, "授权", ()=>{
notify.Clone().Render( type == "linnk" ? "Linnk 无法自动授权 3 秒后请自行授权。" : "3 秒钟后将会自动重新授权,请勿关闭此页面..." );
notify.Clone().Render( [ "linnk", "jianguo", "youdao", "weizhi" ].includes( type ) ? `${name} 无法自动授权 3 秒后请自行授权。` : "3 秒钟后将会自动重新授权,请勿关闭此页面..." );
setTimeout( ()=>browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.auth, { name: type } )), 3000 );
}) : notify.Render( `请先获取 ${name} 的授权,才能使用此功能!` );
dtd.reject( type );
@ -1394,7 +1763,10 @@ const dropbox = new Dropbox(),
gdrive = new GDrive(),
yuque = new Yuque(),
jianguo = new Jianguo(),
notion = new Notion(),
youdao = new Youdao(),
webdav = new WebDAV(),
weizhi = new Wiz(),
kindle = new Kindle();
export {
@ -1407,9 +1779,9 @@ export {
md2HTML as MD2HTML,
unlink as Unlink,
name as Name,
dropbox, pocket, instapaper, linnk, evernote, onenote, gdrive,yuque, jianguo, webdav,
dropbox, pocket, instapaper, linnk, evernote, onenote, gdrive,yuque, jianguo, webdav, notion, youdao, weizhi,
kindle,
mdWrapper as MDWrapper,
serviceCallback as svcCbWrapper,
verifyService as VerifySvcWrapper,
}
}

View File

@ -16,6 +16,7 @@ const context = {
exclusion : { id: "", menu: {} },
blacklist : { id: "", menu: {} },
unrdist : { id: "", menu: {} },
lazyload : { id: "", menu: {} },
},
menu = {
"type" : "normal",
@ -23,14 +24,17 @@ const context = {
"documentUrlPatterns" : [ "http://*/*" , "https://*/*" ]
};
Object.assign( context.focus.menu, menu, { id: "focus", "title" : "聚焦模式" });
Object.assign( context.read.menu, menu, { id: "read", "title" : "阅读模式" });
Object.assign( context.list.menu, menu, { id: "list", "title" : "打开稍后读" });
Object.assign( context.link.menu, menu, { id: "link", "title" : "使用阅读模式打开此链接", contexts: [ "link" ] });
Object.assign( context.focus.menu, menu, { id: "focus", "title" : "聚焦模式" });
Object.assign( context.read.menu, menu, { id: "read", "title" : "阅读模式" });
Object.assign( context.link.menu, menu, { id: "link", "title" : "使用阅读模式打开此链接", contexts: [ "link" ] });
Object.assign( context.list.menu, menu, { id: "list", "title" : "打开稍后读" });
Object.assign( context.unrdist.menu, menu, { id: "unrdist", "title" : "将当前页面加入稍后读" });
Object.assign( context.whitelist.menu, menu, { id: "whitelist", "title" : "将当前页面加入到白名单" });
Object.assign( context.exclusion.menu, menu, { id: "exclusion", "title" : "将当前页面加入到排除列表" });
Object.assign( context.blacklist.menu, menu, { id: "blacklist", "title" : "将当前页面加入到黑名单" });
Object.assign( context.unrdist.menu, menu, { id: "unrdist", "title" : "将当前页面加入稍后读" });
Object.assign( context.lazyload.menu, menu, { id: "lazyload", "title" : "将当前页面加入到延迟加载" });
/**
* Listen contextMenus message
@ -43,6 +47,8 @@ function onClicked( callback ) {
* Create all context menu
*/
function createAll() {
browser.contextMenus.create({ "type": "separator" });
storage.option.menu.focus &&
( context.focus.id = browser.contextMenus.create( context.focus.menu ));
@ -52,9 +58,18 @@ function createAll() {
storage.option.menu.link &&
( context.link.id = browser.contextMenus.create( context.link.menu ));
browser.contextMenus.create({ "type": "separator" });
browser.contextMenus.create({ "type": "separator" });
storage.option.menu.list &&
( context.list.id = browser.contextMenus.create( context.list.menu ));
storage.option.menu.unrdist &&
( context.unrdist.id = browser.contextMenus.create( context.unrdist.menu ));
browser.contextMenus.create({ "type": "separator" });
browser.contextMenus.create({ "type": "separator" });
storage.option.menu.whitelist &&
( context.whitelist.id = browser.contextMenus.create( context.whitelist.menu ));
@ -64,8 +79,10 @@ function createAll() {
storage.option.menu.blacklist &&
( context.blacklist.id = browser.contextMenus.create( context.blacklist.menu ));
storage.option.menu.unrdist &&
( context.unrdist.id = browser.contextMenus.create( context.unrdist.menu ));
storage.option.menu.lazyload &&
( context.lazyload.id = browser.contextMenus.create( context.lazyload.menu ));
browser.contextMenus.create({ "type": "separator" });
}
/**

View File

@ -9,10 +9,12 @@ const action = {
tab_selected : "tab_selected",
new_tab : "new_tab",
close_tab : "close_tab",
// menu
menu : "menu",
menu_whitelist : "menu_whitelist",
menu_exclusion : "menu_exclusion",
menu_blacklist : "menu_blacklist",
menu_lazyload : "menu_lazyload",
menu_unrdist : "menu_unrdist",
updated : "updated",
save_verify : "save_verify",
@ -34,13 +36,23 @@ const action = {
temp_site : "temp_site",
// corb
CORB : "corb",
AXIOS : "axios",
// webdav
jianguo : "jianguo",
WebDAV : "webdav",
// event
turn_tab : "turn_tab",
welcome_close : "welcome_close",
"controlbar" : "simpread-plugin_controlbar",
controlbar : "simpread-plugin_controlbar",
// offline
download : "download",
base64 : "base64",
permission : "permission",
// snapshot
snapshot : "snapshot",
// tips
tips : "tips",
tips_norepeat : "tips_norepeat",
};
/**

204
src/service/offline.js Normal file
View File

@ -0,0 +1,204 @@
console.log( "=== simpread offline load ===" )
import {browser} from 'browser';
import * as msg from 'message';
let currIdx = 0, maxCount = 0, urls = [], images, cb, type = "html", markdown;
/**
* Offline HTML
*
* @param {string} title
* @param {string} desc
* @param {string} content
* @param {object} styles, include: simpread(global), common, theme, css
*
* @return {string} html
*/
function HTML( title, desc, content, styles ) {
const hightlight = () => {
if ( content.search( 'pre class="hljs' ) > -1 || content.search( 'code class="hljs' ) > -1 ) {
return `<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.6/styles/default.min.css">`
} else return '';
},
html = `
<html lang="en" class="simpread-font simpread-theme-root" style='${ $( "html" ).attr( "style" ) }'>
<head>
<meta charset="utf-8">
<meta http-equiv="content-type" content="text/html; charset=UTF-8;charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=1">
<meta name="author" content="Kenshin"/>
<meta name="description" content="简悦 SimpRead - 如杂志般沉浸式阅读体验的扩展" />
<meta name="keywords" content="Chrome extension, Chrome 扩展, 阅读模式, 沉浸式阅读, 简悦, 简阅, read mode, reading mode, reader view, firefox, firefox addon, userscript, safari, opera, tampermonkey"/>
<meta name="thumbnail" content="https://simpread-1254315611.cos.ap-shanghai.myqcloud.com/static/introduce-2.png"/>
<meta property="og:title" content="简悦 SimpRead - 如杂志般沉浸式阅读体验的扩展"/>
<meta property="og:type" content="website">
<meta property="og:local" content="zh_CN"/>
<meta property="og:url" content="http://ksria.com/simpread"/>
<meta property="og:image" content="https://simpread-1254315611.cos.ap-shanghai.myqcloud.com/static/introduce-2.png"/>
<meta property="og:image:type" content="image/png"/>
<meta property="og:image:width" content="960"/>
<meta property="og:image:height" content="355"/>
<meta property="og:site_name" content="http://ksria.com/simpread"/>
<meta property="og:description" content="简悦 SimpRead - 如杂志般沉浸式阅读体验的扩展"/>
<style type="text/css">${ styles.common }</style>
<style type="text/css">${ styles.theme }</style>
<style type="text/css">${ styles.global }</style>
<style type="text/css">${ styles.mobile }</style>
<style type="text/css">${ styles.css }</style>
<style type="text/css">${ styles.special}</style>
${hightlight()}
<title>简悦 | ${title}</title>
</head>
<body>
<sr-read style='${ $( "sr-read" ).attr( "style" ) }'>
<sr-rd-title>${title}</sr-rd-title>
<sr-rd-desc ${desc == "" ? 'style="display: none;"' : "" }>${desc}</sr-rd-desc>
<sr-rd-content>${content}</sr-rd-content>
<sr-rd-footer>
<sr-rd-footer-group>
<sr-rd-footer-line></sr-rd-footer-line>
<sr-rd-footer-text>全文完</sr-rd-footer-text>
<sr-rd-footer-line></sr-rd-footer-line>
</sr-rd-footer-group>
<sr-rd-footer-copywrite>
<div>本文由 <a href="http://ksria.com/simpread" target="_blank">简悦 SimpRead</a> <a href="${ location.href }" target="_blank"> </a></div>
</sr-rd-footer-copywrite>
</sr-rd-footer>
</sr-read>
</body>
</html>`;
return html;
}
/**
* Markdown offline e.g. ![img](http://xxx.png) → ![img][id] ... [id]:base54
*
* @param {string} markdown str
* @param {func} callback
*/
function Markdown( content, callback ) {
type = "markdown";
cb = callback;
markdown = content;
images = new Map();
const arr = markdown.match( /!\[\]\(http\S+\)/ig );
if ( arr && arr.length > 0 ) {
arr.forEach( ( item, idx ) => {
markdown = markdown.replace( item, `![][img-${idx}]` );
item = item.replace( /[!\[\]\(]|[\)]/ig, "" );
markdown = markdown + `\r\n\r\n` + `[img-${idx}]:${item}`;
images.set( item, `[img-${idx}]:${item}` );
});
urls = [...images.keys()];
maxCount = urls.length;
currIdx = 0;
serialConvert( urls[0] );
} else cb( markdown );
}
/**
* Get current page( readmode ) all images and convert to base64
*
* @param {func} callback
*/
function getImages( callback ) {
type = "html";
cb = callback;
images = new Map();
$( "sr-rd-content" ).find( "img" ).map( ( idx, img ) => {
if ( !images.has( img.src ) ) {
images.set( img.src, img );
} else {
//TO-DO
}
});
urls = [...images.keys()];
maxCount = urls.length;
currIdx = 0;
serialConvert( urls[0] );
}
/**
* Convert url to base64
*
* @param {string} url
*/
function serialConvert( url ) {
// call contentscriptsa
//toBase64( url, result => {
// call background
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.base64, { url }), result => {
currIdx++;
if ( result && result.done ) {
setBase64( result.done.url, result.done.uri );
} else {
// TO-DO
}
if ( currIdx < maxCount ) {
serialConvert( urls[currIdx] );
} else {
console.log( "All images convert done" )
cb && cb( markdown );
}
});
}
/**
* Change img.src to base64
*
* @param {string} url
* @param {string} uri
*/
function setBase64( url, uri ) {
const img = images.get( url );
if ( type == "html" ) {
$(img).attr( "src", uri ).attr( "sr-org-src", url );
} else {
const str = img.replace( url, uri )
markdown = markdown.replace( img, str );
}
}
/**
* toBase64 usage FileReader
*
* @param {string} url
* @param {func} callback
*/
function toBase64( url, callback ) {
fetch( url )
.then( response => response.blob() )
.then( blob => new Promise(( resolve, reject ) => {
const reader = new FileReader()
reader.onloadend = event => {
callback({ done: { url, uri: event.target.result }});
};
reader.onerror = error => {
callback({ fail: { error, url } });
};
reader.readAsDataURL( blob );
}))
.catch( error => {
callback({ fail: { error, url } });
});
}
/**
* Restore base64 to url
*/
function restoreImg() {
$( "sr-rd-content" ).find( "img" ).map( ( idx, img ) => {
const src = $(img).attr( "sr-org-src" );
$(img).attr( "src", src ).removeAttr( "sr-org-src" );
});
}
export {
HTML,
Markdown,
getImages,
toBase64,
restoreImg,
}

View File

@ -7,6 +7,10 @@ import {browser} from 'browser';
import * as msg from 'message';
import * as highlight from 'highlight';
import * as share from 'sharecard';
import * as offline from 'offline';
import th from 'theme';
import * as ss from 'stylesheet';
import * as snap from 'snapshot';
/**
* Controlbar common action, include:
@ -24,6 +28,21 @@ function action( type, title, desc, content ) {
console.log( "output: Action is ", type )
const styles = callback => {
ss.SpecialCSS( storage.pr.mathjax, special => {
th.GetAll();
const theme = th.Get( storage.read.theme ),
global = th.Get( "global" ),
common = th.Get( "common" ),
mobile = th.Get( "mobile" ),
css = ss.GetCustomCSS();
callback({ theme, global, common, css, mobile, special });
});
},
toMarkdown = callback => {
exp.MDWrapper( util.ClearMD( content ), undefined, new Notify() ).done( result => callback( result ));
};
if ( type.indexOf( "_" ) > 0 && type.startsWith( "share" ) ) {
let url = "";
switch ( type.split("_")[1] ) {
@ -51,12 +70,13 @@ function action( type, title, desc, content ) {
break;
}
type.split("_")[1] != "card" && browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.new_tab, { url }));
} else if ( [ "save", "markdown", "png", "kindle", "pdf", "epub", "temp", "html" ].includes( type ) ) {
} else if ( [ "save", "markdown", "offlinemarkdown", "png", "kindle", "pdf", "epub", "temp", "html", "offlinehtml", "snapshot", "bear", "ulysses" ].includes( type ) ) {
storage.Statistics( "service", type );
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.track, { eventCategory: "service", eventAction: "service", eventValue: type }) );
switch ( type ) {
case "save":
const url = window.location.href.replace( /(\?|&)simpread_mode=read/, "" );
storage.UnRead( "add", { url, title, desc }, success => {
storage.UnRead( "add", util.GetPageInfo(), success => {
success && new Notify().Render( 0, "成功加入未读列表。" );
!success && new Notify().Render( 0, "已加入未读列表,请勿重新加入。" );
});
@ -66,6 +86,26 @@ function action( type, title, desc, content ) {
storage.pr.current.site.avatar[0].name != "" && ( content = util.MULTI2ENML( content ) );
exp.MDWrapper( util.ClearMD( content ), md, new Notify() );
break;
case "offlinemarkdown":
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.permission ), result => {
if ( !result.done ) {
new Notify().Render( 2, `离线下载的文件体积较大,所以需要使用 Chrome 下载方案,请授权。` );
return;
} else {
const notify2 = new Notify().Render({ content: "图片转换中吗,请稍等...", state: "loading" });
const md = "simpread-" + title + ".md";
storage.pr.current.site.avatar[0].name != "" && ( content = util.MULTI2ENML( content ) );
toMarkdown( result => {
offline.Markdown( result, str => {
notify2.complete();
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.download, { data: str, name: md }), result => {
console.log( "Current download result: ", result )
});
});
});
}
});
break;
case "png":
try {
new Notify().Render( "下载已开始,请稍等..." );
@ -88,7 +128,59 @@ function action( type, title, desc, content ) {
!success && new Notify().Render( 2, `转换失败,这是一个实验性功能,不一定能导出成功,详细请看 <a href="http://ksria.com/simpread/docs/#/发送到-Epub" target="_blank">epub.press</a>` );
});
break;
case "offlinehtml":
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.permission ), result => {
if ( !result.done ) {
new Notify().Render( 2, `离线下载的文件体积较大,所以需要使用 Chrome 下载方案,请授权。` );
return;
} else {
const notify2 = new Notify().Render({ content: "图片转换中吗,请稍等...", state: "loading" });
offline.getImages( () => {
notify2.complete();
new Notify().Render( 0, "全部图片已经转换完毕,马上开始下载,请稍等。" );
styles( csses => {
const html = offline.HTML( title, desc, $( "sr-rd-content" ).html(), csses );
offline.restoreImg();
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.download, { data: html, name: `simpread-${title}.html` }), result => {
console.log( "Current download result: ", result )
});
});
});
}
});
break;
case "html":
styles( csses => {
const html = offline.HTML( title, desc, content, csses );
exp.Download( "data:text/plain;charset=utf-8," + encodeURIComponent(html), `simpread-${title}.html` );
});
break;
case "snapshot":
new Notify().Render( "请移动鼠标,按住鼠标左键框选,框选后可再次框选。" );
$("panel-bg").click();
setTimeout( () => {
snap.Start().done( result => {
snap.End();
setTimeout(() => {
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.snapshot, result ), result => {
exp.Download( result.done, `simpread-${title}.png` );
});
}, 100 );
});
}, 500 );
break;
case "bear":
storage.pr.current.site.avatar[0].name != "" && ( content = util.MULTI2ENML( content ) );
toMarkdown( result => {
location.href = `bear://x-callback-url/create?title=${title}&text=${encodeURIComponent(result)}&tags=simpread`;
});
break;
case "ulysses":
storage.pr.current.site.avatar[0].name != "" && ( content = util.MULTI2ENML( content ) );
toMarkdown( result => {
location.href = `ulysses://x-callback-url/new-sheet?text=${encodeURIComponent(result)}`;
});
break;
case "temp":
case "kindle":
const notify = new Notify().Render({ state: "loading", content: "开始转码阅读模式并上传到服务器,请稍后。" });
@ -113,15 +205,6 @@ function action( type, title, desc, content ) {
new Notify().Render( "保存成功3 秒钟后将跳转到临时页面。" );
setTimeout( ()=>{ exp.kindle.Temp(); }, 3000 );
break;
case "html":
new Notify().Render( "保存成功,开始下载..." );
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.CORB, { settings: { url: `${exp.kindle.host}/${exp.kindle.id}.html`, type: "GET" }}), result => {
if ( result && result.done != "" ) {
result = result.done.replace( /<link rel=\"stylesheet\" href=\"\.\/css\//ig, '<link rel="stylesheet" href="http://sr.ksria.cn/puread/' )
exp.Download( "data:text/plain;charset=utf-8," + encodeURIComponent(result), `simpread-${title}.html` );
} else new Notify().Render( 2, "导出出现问题,请稍后再试。" );
});
break;
}
}
});
@ -138,15 +221,16 @@ function action( type, title, desc, content ) {
}
break;
}
} else if ( [ "dropbox", "pocket", "instapaper", "linnk", "yinxiang","evernote", "onenote", "gdrive", "jianguo", "yuque" ].includes( type ) ) {
const { dropbox, pocket, instapaper, linnk, evernote, onenote, gdrive, jianguo, yuque } = exp,
} else if ( [ "dropbox", "pocket", "instapaper", "linnk", "yinxiang","evernote", "onenote", "gdrive", "jianguo", "yuque", "notion", "youdao", "weizhi" ].includes( type ) ) {
const { dropbox, pocket, instapaper, linnk, evernote, onenote, gdrive, jianguo, yuque, notion, youdao, weizhi } = exp,
id = type == "yinxiang" ? "evernote" : type;
storage.Statistics( "service", type );
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.track, { eventCategory: "service", eventAction: "service", eventValue: type }) );
const service = type => {
switch( type ) {
case "dropbox":
storage.pr.current.site.avatar[0].name != "" && ( content = util.MULTI2ENML( content ) );
exp.MDWrapper( util.ClearMD( content ), undefined, new Notify() ).done( result => {
toMarkdown( result => {
dropbox.Write( `${ title }.md`, result, ( _, result, error ) => exp.svcCbWrapper( result, error, dropbox.name, type, new Notify() ), "md/" );
});
break;
@ -158,12 +242,13 @@ function action( type, title, desc, content ) {
break;
case "linnk":
const notify = new Notify().Render({ content: `开始保存到 Linnk请稍等...`, state: "loading" });
linnk.access_token = storage.secret.linnk.access_token;
linnk.GetSafeGroup( linnk.group_name, ( result, error ) => {
notify.complete();
if ( !error ) {
linnk.group_id = result.data.groupId;
linnk.Add( window.location.href, title, ( result, error ) => exp.svcCbWrapper( result, error, linnk.name, type, new Notify() ));
} else new Notify().Render( 2, `${ linnk.name } 保存失败,请稍后重新再试。` );
} else new Notify().Render( 2, error == "error" ? `${ linnk.name } 保存失败,请稍后重新再试。` : error );
});
break;
case "evernote":
@ -205,12 +290,12 @@ function action( type, title, desc, content ) {
break;
case "gdrive":
storage.pr.current.site.avatar[0].name != "" && ( content = util.MULTI2ENML( content ) );
exp.MDWrapper( util.ClearMD( content ), undefined, new Notify() ).done( result => {
toMarkdown( result => {
gdrive.Add( "file",( result, error ) => exp.svcCbWrapper( result, error, gdrive.name, type, new Notify() ), gdrive.CreateFile( `${title}.md`, result ));
});
break;
case "jianguo":
exp.MDWrapper( util.ClearMD( content ) , undefined, new Notify() ).done( markdown => {
toMarkdown( markdown => {
title = title.replace( /[|@!#$%^&*()<>/,.+=\\]/ig, "-" );
jianguo.Add( storage.secret.jianguo.username, storage.secret.jianguo.password, `${jianguo.root}/${jianguo.folder}/${title}.md`, markdown, result => {
let error = undefined;
@ -222,10 +307,42 @@ function action( type, title, desc, content ) {
});
break;
case "yuque":
exp.MDWrapper( util.ClearMD( content ), undefined, new Notify() ).done( result => {
toMarkdown( result => {
yuque.Add( title, result,( result, error ) => exp.svcCbWrapper( result, error, yuque.name, type, new Notify() ));
});
break;
case "notion":
toMarkdown( result => {
corbLoader( "load", () => {
notion.access_token = storage.secret.notion.access_token;
notion.folder_id = storage.secret.notion.folder_id;
notion.Add( title, result.replace( /.jpeg!720/ig, '.jpeg' ), ( result, error ) => {
exp.svcCbWrapper( result, error, notion.name, type, new Notify() )
});
}, 500 );
});
break;
case "youdao":
toMarkdown( result => {
corbLoader( "load", () => {
youdao.access_token = storage.secret.youdao.access_token;
youdao.folder_id = storage.secret.youdao.folder_id;
youdao.Add( title, result, ( result, error ) => {
exp.svcCbWrapper( result, error, youdao.name, type, new Notify() )
});
});
});
break;
case "weizhi":
styles( csses => {
const html = offline.HTML( title, desc, content, csses );
weizhi.username = storage.secret.weizhi.username;
weizhi.access_token = storage.secret.weizhi.access_token;
weizhi.Add( window.location.href, title, html, ( result, error ) => {
exp.svcCbWrapper( result, error, weizhi.name, type, new Notify() )
});
});
break;
}
};
@ -241,15 +358,40 @@ function action( type, title, desc, content ) {
} else if ( type.startsWith( "fullscreen" ) ) {
document.documentElement.requestFullscreen();
} else if ( type.startsWith( "webdav_" ) ) {
const id = type.replace( "webdav_", "" );
const id = type.replace( "webdav_", "" ),
covernt = ( type, callback ) => {
if ( type == "html" ) {
styles( csses => {
const html = offline.HTML( title, desc, content, csses );
callback( html );
});
} else if ( type == "ofhtml" ) {
const notify2 = new Notify().Render({ content: "图片转换中吗,请稍等...", state: "loading" });
offline.getImages( () => {
notify2.complete();
new Notify().Render( 0, "全部图片已经转换完毕,开始发送,请稍等。" );
styles( csses => {
const html = offline.HTML( title, desc, $( "sr-rd-content" ).html(), csses );
offline.restoreImg();
callback( html );
});
});
} else {
toMarkdown( markdown => {
callback( markdown );
});
}
};
storage.Safe( () => {
storage.secret.webdav.forEach( item => {
item = JSON.parse( item );
item.format == undefined && ( item.format = "md" );
if ( item.name == id ) {
exp.MDWrapper( util.ClearMD( content ) , undefined, new Notify() ).done( markdown => {
title = title.replace( /[|@!#$%^&*()<>/,.+=\\]/ig, "-" );
covernt( item.format, str => {
title = title.replace( /[|@!#$%^&*()<>/,.+=\\]/ig, "-" );
const suffix = item.format.endsWith( "html" ) ? ".html" : ".md";
new Notify().Render( `开始保存到 ${ item.name},请稍等...` );
exp.webdav.Add( item.url, item.user, item.password, `${title}.md`, markdown, result => {
exp.webdav.Add( item.url, item.user, item.password, `${title}${suffix}`, str, result => {
let error = undefined;
if ( result && ( result.status != 201 && result.status != 204 )) {
error = `导出到 ${item.name} 失败,请稍后再试。`;
@ -266,6 +408,20 @@ function action( type, title, desc, content ) {
}
}
/**
* Open and Remove CORB iframe
*
* @param {string} include: load & remove
*/
function corbLoader( state, callback ) {
if ( state == "load" ) {
if ( $( '#sr-corb' ).length == 0 ) {
$( 'html' ).append( `<iframe id="sr-corb" src="${browser.runtime.getURL('options/corb.html')}" width="0" height="0" frameborder="0"></iframe>` );
$( '#sr-corb' ).on( "load", event => callback());
} else callback();
} else $( '#sr-corb' ).remove();
}
export {
action as Action,
}

21
src/service/permission.js Normal file
View File

@ -0,0 +1,21 @@
import {browser} from 'browser';
function Get( permissions, callback ) {
browser.permissions.contains({ permissions: permissions.permissions }, result => {
result == false ? chrome.permissions.request( permissions, granted => {
callback( granted );
}): callback( result );
});
}
function Remove( permissions, callback ) {
browser.permissions.remove( { permissions: permissions.permissions }, result => {
callback( result )
})
}
export {
Get,
Remove
}

63
src/service/snapshot.js Normal file
View File

@ -0,0 +1,63 @@
console.log( "=== simpread snapshot load ===" )
let dtd, startPos, endPos, dragStart = false, position;
function start() {
dtd = $.Deferred();
dragStart = false;
$( ".simpread-read-root" ).append( `<simpread-snapshot><sr-mask></sr-mask></simpread-snapshot>` );
$( "simpread-snapshot" )
.on( "mousemove", event => {
if ( dragStart == false ) return;
endPos = { left: event.clientX, top: event.clientY };
const width = endPos.left - startPos.left,
height = endPos.top - startPos.top;
position = {
left : width >= 0 ? startPos.left : endPos.left,
top : height >= 0 ? startPos.top : endPos.top,
width : Math.abs( width ),
height: Math.abs( height ),
}
$( event.currentTarget ).find( "sr-mask" ).css( position );
})
.on( "mousedown", event => {
startPos = { left: event.clientX, top: event.clientY };
dragStart = true;
})
.on( "mouseup", event =>{
dragStart = false;
controlbar();
});
return dtd;
}
function remove() {
$( ".simpread-read-root" ).find( "simpread-snapshot" ).remove();
}
function controlbar() {
if ( $( "simpread-snapshot sr-highlight-ctl" ).length > 0 ) return;
const html = `<sr-snapshot-ctlbar>
<sr-highlight-ctl class="done"><svg t="1560496955945" viewBox="0 0 1024 1024" version="1.1" width="15" height="15"><defs><style type="text/css"></style></defs><path d="M416.832 798.08C400.64 798.08 384.512 791.872 372.16 779.52L119.424 525.76C94.784 500.992 94.784 460.8 119.424 436.032 144.128 411.264 184.128 411.264 208.768 436.032L416.832 644.928 814.4 245.76C839.04 220.928 879.04 220.928 903.744 245.76 928.384 270.528 928.384 310.656 903.744 335.424L461.504 779.52C449.152 791.872 432.96 798.08 416.832 798.08Z" p-id="1755" fill="#ffffff"></path></svg></sr-highlight-ctl>
<sr-highlight-ctl class="none"><svg t="1560499513561" viewBox="0 0 1024 1024" version="1.1" width="15" height="15"><defs><style type="text/css"></style></defs><path d="M649.179 512l212.839-212.84c37.881-37.881 37.881-99.298 0-137.179s-99.298-37.881-137.179 0L512 374.821l-212.839-212.84c-37.881-37.881-99.298-37.881-137.179 0s-37.881 99.298 0 137.179L374.821 512 161.982 724.84c-37.881 37.881-37.881 99.297 0 137.179 18.94 18.94 43.765 28.41 68.589 28.41 24.825 0 49.649-9.47 68.589-28.41L512 649.179l212.839 212.84c18.94 18.94 43.765 28.41 68.589 28.41s49.649-9.47 68.59-28.41c37.881-37.882 37.881-99.298 0-137.179L649.179 512z" p-id="1990" fill="#ffffff"></path></svg></sr-highlight-ctl>
<sr-highlight-ctl class="help"><svg t="1560573280563" viewBox="0 0 1024 1024" version="1.1" width="15" height="15"><defs><style type="text/css"></style></defs><path d="M512 958.326255c247.255337 0 447.696462-200.441125 447.696462-447.696462s-200.441125-447.696462-447.696462-447.696462-447.696462 200.441125-447.696462 447.696462S264.74364 958.326255 512 958.326255zM512 217.681788c35.32146 0 63.956637 28.635177 63.956637 63.956637 0 35.323507-28.635177 63.956637-63.956637 63.956637s-63.956637-28.633131-63.956637-63.956637C448.043363 246.316965 476.67854 217.681788 512 217.681788zM448.043363 510.629793c0-35.32146 28.635177-63.956637 63.956637-63.956637s63.956637 28.635177 63.956637 63.956637l0 223.848231c0 35.323507-28.635177 63.956637-63.956637 63.956637s-63.956637-28.633131-63.956637-63.956637L448.043363 510.629793z" p-id="1979" fill="#ffffff"></path></svg></sr-highlight-ctl>
</sr-snapshot-ctlbar>`;
$( "simpread-snapshot" ).append( html );
$( "simpread-snapshot" ).on( "click", "sr-highlight-ctl", event => {
const cls = $( event.currentTarget ).attr( "class" );
if ( cls == "done" ) {
dtd.resolve( position );
} else if ( cls == "none" ) {
remove();
} else if ( cls == "help" ) {
const $a = $( `<a style="display:none" target="_blank" href="http://ksria.com/simpread/docs/#/截图"></a>` ).appendTo( "body" );
$a[0].click();
$a.remove();
}
});
}
export {
start as Start,
remove as End,
}

View File

@ -128,6 +128,7 @@ const name = "simpread",
whitelist: false,
exclusion: false,
blacklist: false,
lazyload: false,
unrdist: false,
},
origins : [],
@ -140,8 +141,9 @@ const name = "simpread",
"simpread.ksria.cn"
],
plugins : [], // plugin id, e.g. kw36BtjGu0
urlscheme : true,
},
statistics = {
/*statistics = { remove by 1.1.4
"focus" : 0,
"read" : 0,
"service" : {
@ -163,8 +165,9 @@ const name = "simpread",
"temp" : 0,
"yuque" : 0,
"jianguo" : 0,
"weizhi" : 0,
}
},
},*/
user = {
uid : "",
name : "",
@ -207,8 +210,14 @@ let current = {},
user,
},
plugins = {},
unrdist = [],
statistics= {
"focus" : 0,
"read" : 0,
"service" : {},
},
secret = {
version : "2019-06-08",
version : "2019-12-20",
"dropbox" : {
"access_token": ""
},
@ -241,11 +250,24 @@ let current = {},
access_token : "",
repos_id: "",
},
"notion" : {
access_token : "",
folder_id: "",
},
"youdao" : {
access_token : "",
folder_id : "",
},
"jianguo" : {
username : "",
password : "",
access_token : "",
},
"weizhi" : {
username : "",
password : "",
access_token : "",
},
"webdav" : []
};
//stcode = -1;
@ -305,7 +327,7 @@ class Storage {
* @return {array} unread list
*/
get unrdist() {
return simpread[ mode.unrdist ];
return unrdist;
}
/**
@ -350,7 +372,7 @@ class Storage {
* @return {object} statistics object
*/
get statistics() {
return simpread.statistics;
return statistics;
}
/**
@ -458,14 +480,17 @@ class Storage {
* @param {function} callback
*/
Read( callback ) {
browser.storage.local.get( [name], function( result ) {
browser.storage.local.get( [name], result => {
let firstload = true;
if ( result && !$.isEmptyObject( result )) {
simpread = result[name];
firstload = false;
}
origin = clone( simpread );
callback( firstload );
this.Statistics( undefined, undefined, "read" );
this.UnRead( undefined, undefined, () => {
callback( firstload );
}, "read" );
console.log( "chrome storage read success!", simpread, origin, result );
});
}
@ -642,16 +667,46 @@ class Storage {
*
* @param {string} include: create, focus, read, service
* @param {string} include: service type, e.g. pdf png onenote
* @param {boolean} include: read & write
*/
Statistics( type, service ) {
Statistics( type, service, state = "write" ) {
if ( type == "create" ) {
simpread.option.create = now();
} else {
service ? simpread.statistics.service[ service ]++ : simpread.statistics[ type ]++;
save( undefined, type == "create" );
return;
}
const write = () => {
browser.storage.local.set( { ["statistics"] : statistics }, () => {
console.log( "chrome storage statistics set success!", statistics );
});
},
read = cb => {
browser.storage.local.get( ["statistics"], result => {
console.log( "chrome storage statistics get success!", result );
result && !$.isEmptyObject( result ) && ( statistics = result["statistics"] );
cb && cb();
});
};
if ( state == "read" ) {
if ( !$.isEmptyObject( simpread.statistics ) ) {
statistics = clone( simpread.statistics );
simpread.statistics = {};
write();
} else read();
} else {
read( () => {
if ( type == "create" ) {
simpread.option.create = now();
} else {
service && statistics.service[ service ] == undefined && ( statistics.service[ service ] = 0 );
service ? statistics.service[ service ]++ : statistics[ type ]++;
}
console.log( "current statistics is ",statistics )
write();
});
}
console.log( "current statistics is ", simpread.statistics )
browser.runtime.sendMessage({ type: "track", value: { eventAction: type, eventCategory: "read mode", eventLabel: "click" } });
save( undefined, type == "create" );
}
/**
@ -660,25 +715,51 @@ class Storage {
* @param {type} include: add remove
* @param {any} include: object( @see unread ) or index
* @param {function} callback
* @param {boolean} include: read & write
*/
UnRead( type, args, callback ) {
UnRead( type, args, callback, state = "write" ) {
let success = true;
switch ( type ) {
case "add":
const len = simpread.unrdist.length;
args.create = now();
args.idx = len > 0 ? simpread.unrdist[0].idx + 1 : 0;
simpread.unrdist.findIndex( item => item.url == args.url ) == -1 ?
simpread.unrdist.splice( 0, 0, args ) : success = false;
break;
case "remove":
const idx = simpread.unrdist.findIndex( item => item.idx == args );
idx != -1 && simpread.unrdist.splice( idx, 1 );
idx == -1 && ( success = false );
break;
const write = () => {
browser.storage.local.set( { ["unrdist"] : unrdist }, () => {
console.log( "chrome storage unrdist set success!", unrdist );
callback && callback( success );
});
},
read = cb => {
browser.storage.local.get( ["unrdist"], result => {
console.log( "chrome storage unrdist get success!", result );
result && !$.isEmptyObject( result ) && ( unrdist = result["unrdist"] );
cb && cb();
!cb && callback && callback( success );
});
};
if ( state == "read" ) {
if ( simpread.unrdist.length > 0 ) {
unrdist = $.extend( true, [], simpread.unrdist );
simpread.unrdist = [];
write();
} else read();
} else {
read( () => {
switch ( type ) {
case "add":
const len = unrdist.length;
args.create = now();
args.idx = len > 0 ? unrdist[0].idx + 1 : 0;
unrdist.findIndex( item => item.url == args.url ) == -1 ?
unrdist.splice( 0, 0, args ) : success = false;
break;
case "remove":
const idx = unrdist.findIndex( item => item.idx == args );
idx != -1 && unrdist.splice( idx, 1 );
idx == -1 && ( success = false );
break;
}
write();
});
}
callback && save( callback( success ) );
}
}
/**
* Verify simpread data structure

View File

@ -197,6 +197,39 @@ function vfyCustom( type, styles ) {
}
}
function getCustomCSS() {
let styles = $( "style#simpread-site-css" ).text() || "";
$( "head" ).find( "style" ).map( (index, item) => {
item.id.startsWith( "simpread-custom-" ) && ( styles += item.innerHTML );
});
return styles;
}
/**
* Get special style
*
* @param {boolean} mathjax
* @param {func} callback
*/
function specialCSS( mathjax, callback ) {
let css = "";
if ( mathjax && location.hostname == "blog.csdn.net" ) {
$.get("https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-b6c3c6d139.css", result=> {
callback( result );
})
} else if ( mathjax ) {
$( "head" ).find( "style" ).map( (index, item) => {
const $target = $(item),
cls = $target.attr( "class" ),
html = $target.text();
if ( cls == "simpread-offline-special" || html.search( ".MathJax" ) > -1 || html.search( ".mathjax" ) > -1 || html.search( ".MJX" ) > -1 ) {
css += html;
}
});
callback( css );
} else callback( css );
}
export {
iconPath as IconPath,
getColor as GetColor,
@ -210,4 +243,6 @@ export {
custom as Custom,
css as CSS,
vfyCustom as VerifyCustom,
getCustomCSS as GetCustomCSS,
specialCSS as SpecialCSS,
}

View File

@ -66,9 +66,18 @@ class Theme {
tocTheme( theme );
}
Get( theme ) {
return themes[theme];
}
GetAll() {
findThemeStyle();
}
constructor() {
require( `../assets/css/theme_common.css` );
names.forEach( name => require( `../assets/css/theme_${name}.css` ) );
require( `../assets/css/theme_mobile.css` );
findThemeStyle( ( name, content ) => themes[name] = content );
}
}
@ -85,7 +94,13 @@ function findThemeStyle( callback ) {
if ( css.startsWith( flag ) ) {
const arr = css.replace( flag, "" ).match( /\w+/ ),
name = arr[ arr.length - 1 ];
callback( name, css, $target );
callback && callback( name, css, $target );
} else if ( css.search( ".simpread-font" ) > -1 ) {
!themes["global"] && ( themes["global"] = css );
} else if ( css.search( "(pointer:coarse)" ) == -1 && css.search( ".simpread-theme-root" ) > -1 ) {
!themes["common"] && ( themes["common"] = css );
} else if ( css.search( "(pointer:coarse)" ) > -1 && css.search( "sr-read" ) > -1 ) {
!themes["mobile"] && ( themes["mobile"] = css );
}
});
}

87
src/service/tips.js Normal file
View File

@ -0,0 +1,87 @@
console.log( "=== simpread tips load ===" )
import Notify from 'notify';
import * as msg from 'message';
import {browser} from 'browser';
/**
* Verify current page and some plugin exist
*
* @param {array} plugins ids
*/
function Render( plugins ) {
const notify = code => {
new Notify().Render( messages[code], "不再提示", () => {
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.tips_norepeat, { code }));
});
},
pushMessage = code => {
browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.tips, { code }), result => {
if ( result ) {
notify( code );
}
});
},
messages = {
"klGUASLasg": '检测到当前环境有代码段,请使用 <a target="blank" href="https://simpread.ksria.cn/plugins/details/klGUASLasg">代码增强插件</a> 辅助阅读',
"VQOZdNET2d": '检测到当前环境有大量的图片,可以使用 <a target="blank" href="https://simpread.ksria.cn/plugins/details/VQOZdNET2d">点击查看大图</a> 辅助阅读',
"DxlFcL52iy": '如果你想换个论坛类页面风格,可以使用 <a target="blank" href="https://simpread.ksria.cn/plugins/details/DxlFcL52iy">Materail Design 风格</a> 辅助阅读',
}
// verify klGUASLasg
if ( $( "sr-read" ).find( "pre" ).length > 0 && plugins.findIndex( item => item == "klGUASLasg" ) == -1 ) {
pushMessage( "klGUASLasg" );
}
// verify VQOZdNET2d
if ( $( "sr-read" ).find( "img" ).length > 5 && plugins.findIndex( item => item == "VQOZdNET2d" ) == -1 ) {
pushMessage( "VQOZdNET2d" );
}
// verify DxlFcL52iy
if ( ( location.hostname == "www.zhihu.com" && location.pathname.startsWith( "/question/" ) ) && plugins.findIndex( item => item == "DxlFcL52iy" ) == -1 ) {
pushMessage( "DxlFcL52iy" );
}
}
/**
* Help
*
* @param {object} storage.statistics
*/
function Help( statistics ) {
if ( statistics.read == 1 ) {
new Notify().Render({ content: "嗨,很高兴第一次使用简悦的阅读模式,是否看看新手帮助?", action: "我要看", cancel: "老司机", callback: type => {
type == "action" && browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.new_tab, { url: "http://ksria.com/simpread/guide/#readmode" }));
type == "cancel" && browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.tips_norepeat, { code: "readmode" }));
}});
}
}
/**
* Background call
*
* @param {string} plugin id
* @param {func} callback true: tips; false: not tip
*/
function Verify( id, callback ) {
const tips = JSON.parse( localStorage[ "simpread-tips" ] || "{}" );
if ( !tips[id] ) {
callback( true );
} else callback( false );
}
/**
* Not repeat tips
*
* @param {string} tips id
*/
function Done( id ) {
const tips = JSON.parse( localStorage[ "simpread-tips" ] || "{}" );
tips[id] = true;
localStorage.setItem( "simpread-tips", JSON.stringify( tips ));
}
export {
Render,
Verify,
Done,
Help,
}

View File

@ -171,14 +171,17 @@ function clearHTML( str ) {
*
* @param {object} minimatch
* @param {object} simpread.read
* @return {boolen} true: not exist; false: exist
* @return {boolen} true: exist; false: not exist
*/
function exclusion( minimatch, data ) {
const url = window.location.origin + window.location.pathname;
return data.exclusion.findIndex( item => {
item == null && ( item = "" );
item = item.trim();
return item.startsWith( "http" ) ? minimatch( url, item ) : item == data.site.name;
}) == -1 ? true : false;
if ( item.startsWith( "[[/" ) && item.endsWith( "/]]" ) ) {
return location.href.replace( new RegExp( item.replace( /\[\[\/|\/\]\]/ig, "" ), "g" ), "" ) == "" ? true : false;
} else return item.startsWith( "http" ) ? minimatch( url, item ) : item == data.site.name;
}) != -1 ? true : false;
}
/**
@ -191,11 +194,62 @@ function exclusion( minimatch, data ) {
function whitelist( minimatch, data ) {
const url = window.location.origin + window.location.pathname;
return data.whitelist.findIndex( item => {
item == null && ( item = "" );
item = item.trim();
return item.startsWith( "http" ) ? minimatch( url, item ) : item == data.site.name;
if ( item.startsWith( "[[/" ) && item.endsWith( "/]]" ) ) {
return location.href.replace( new RegExp( item.replace( /\[\[\/|\/\]\]/ig, "" ), "g" ), "" ) == "" ? true : false;
} else return item.startsWith( "http" ) ? minimatch( url, item ) : item == data.site.name;
}) != -1 ? true : false;
}
/**
* Blacklist
*
* @param {object} minimatch
* @param {object} simpread.read
* @return {boolean} true: is blacklist; false: is't blacklist
*/
function blacklist( minimatch, data ) {
return data.blacklist.findIndex( item => {
item == null && ( item = "" );
item = item.trim();
if ( item.startsWith( "[[/" ) && item.endsWith( "/]]" ) ) {
return location.href.replace( new RegExp( item.replace( /\[\[\/|\/\]\]/ig, "" ), "g" ), "" ) == "" ? true : false;
} else return item.startsWith( "http" ) ? minimatch( location.href, item ) : location.hostname.includes( item );
}) != -1 ? true : false;
}
/**
* Lazyload
*
* @param {object} minimatch
* @param {object} simpread.read
* @return {boolean} true: is blacklist; false: is't blacklist
*/
function lazyload( minimatch, data ) {
return data.lazyload.findIndex( item => {
item == null && ( item = "" );
item = item.trim();
if ( item.startsWith( "[[/" ) && item.endsWith( "/]]" ) ) {
return location.href.replace( new RegExp( item.replace( /\[\[\/|\/\]\]/ig, "" ), "g" ), "" ) == "" ? true : false;
} else return item.startsWith( "http" ) ? minimatch( location.href, item ) : location.hostname.includes( item );
}) != -1 ? true : false;
}
/**
* Get page info
*
* @return {object} include: url, title, favicon, img, desc
*/
function getPageInfo() {
const url = location.href,
title = $( "sr-read" ).find( "sr-rd-title" ).text() || $( "head" ).find( "title" ).text() || "",
favicon = $( `head link[rel~=icon]` ).attr( "href" ) || "",
img = $( `head meta[property="og:image"]` ).attr( "content" ) || $( "sr-read" ).find( "img" ).attr( "src" ) || "",
desc = $( "sr-read" ).find( "sr-rd-desc" ).text() || $( `head meta[property="og:description"]` ).attr( "content" ) || $( 'meta[name=description]' ).attr( 'content' ) || "";
return { url, title: title.trim(), favicon, img, desc: desc.trim() };
}
export {
verifyHtml as verifyHtml,
html2enml as HTML2ENML,
@ -205,4 +259,7 @@ export {
clearHTML as ClearHTML,
exclusion as Exclusion,
whitelist as Whitelist,
blacklist as Blacklist,
lazyload as Lazyload,
getPageInfo as GetPageInfo,
}

View File

@ -19,6 +19,7 @@ const version = browser.runtime.getManifest().version.replace( /.\d{2,}/, "" ),
[ "1.1.1", "Mon Jun 11 2018 15:10:12 GMT+0800 (CST)" ],
[ "1.1.2", "Tue Jun 19 2018 14:15:12 GMT+0800 (CST)" ],
[ "1.1.3", "Thu Jun 06 2019 15:47:44 GMT+0800 (CST)" ],
[ "1.1.4", "Thu Jan 16 2020 14:24:53 GMT+0800 (CST)" ],
]),
details = new Map([
[ "1.0.0", "" ],
@ -32,9 +33,44 @@ const version = browser.runtime.getManifest().version.replace( /.\d{2,}/, "" ),
[ "1.1.1", "新增「黑名单,全新的控制栏面板,更丰富的中文定制化,无障碍阅读等」," ],
[ "1.1.2", "新增「插件中心,站点集市等」," ],
[ "1.1.3", "新增「消息中心,帮助中心,入门指引,支持导入语雀 / 坚果云,预加载机制,增强插件 API 等」," ],
[ "1.1.4", "新增「反馈中心,支持导入 Notion, 有道笔记,为知笔记,离线下载,截图 等」," ],
]),
tips = {
"root" : value => `.version-tips[data-hits='${value}']`,
"1.1.4" : {
target: 'labs',
idx: 2,
items: [
{
id: '',
intro: '简悦 1.1.4 功能描述:<br>' + details.get( "1.1.4" ) + '详细说明 <a target="_blank" href="http://ksria.com/simpread/welcome/version_1.1.4.html">请看这里</a> 。' ,
},
{
id: 'lazyload',
intro: '现在可通过右键菜单发送「延迟加载」了',
},
{
id: 'urlscheme',
intro: '【黑名单 · 白名单 · 排除列表 · 延迟加载】加入 <b>正则表达式</b> 的方式,同时也新增加了 <a target="_blank" href="http://ksria.com/simpread/docs/#/右键菜单?id=URL编辑器">URL 编辑器</a>。',
},
{
id: 'notion',
intro: '简悦支持导出 Markdown 格式到 Notion详细说明 <a target="_blank" href="http://ksria.com/simpread/docs/#/Notion">请看这里</a>',
},
{
id: 'youdao',
intro: '简悦支持导出 Markdown 格式到 有道云笔记,详细说明 <a target="_blank" href="http://ksria.com/simpread/docs/#/有道云笔记">请看这里</a>',
},
{
id: 'weizhi',
intro: '简悦支持导出 HTML 格式到 为知笔记,详细说明 <a target="_blank" href="http://ksria.com/simpread/docs/#/为知笔记">请看这里</a>',
},
{
id: 'webdav',
intro: 'WebDAV 增加了导出格式的定制化,包括 <span>Markdown</span> <span>HTML</span>,详细说明 <a target="_blank" href="http://ksria.com/simpread/docs/#/WebDAV?id=定制">请看这里</a>',
}
]
},
"1.1.3" : {
target: 'labs',
idx: 2,
@ -434,6 +470,12 @@ function Verify( curver, data ) {
curver = "1.1.3";
}
if ( curver == "1.1.3" ) {
data.option.urlscheme = true;
data.option.menu.lazyload = false;
curver = "1.1.4";
}
/*
if ( curver == "1.0.1" ) {
data.option.pocket = { "consumer": "", "access": "" };
@ -455,15 +497,11 @@ function Verify( curver, data ) {
*/
function Incompatible( ver, data ) {
let is_changed = false;
if ( ver == "1.1.3" ) {
if ( ver == "1.1.4" ) {
data.option.origins = data.option.origins.filter( item => item != "http://sr.ksria.cn/origins/website_list_en.json" && item != "http://sr.ksria.cn/origins/website_list_tw.json" )
if ( data.option.origins.length > 0 ) {
is_changed = true;
new Notify().Render({ type: 2, content: `检测到你曾经修改过第三方适配源,<b>务必刷新后重新导入</b><a target="_blank" href="http://ksria.com/simpread/docs/#/站点适配源?id=第三方适配源">详细说明</a>`, state: "holdon" });
}
if ( VerifyPlugins( ver, data.option )) {
is_changed = true;
new Notify().Render({ type: 2, content: `已清理失效的插件,<b>务必刷新后重新导入</b>,详细请看 <a href="http://ksria.com/simpread/welcome/version_${version}.html#badplugins" target="_blank">删除失效的插件</a>`, state: "holdon" });
new Notify(); // hack code
}
}
return is_changed;
@ -526,20 +564,18 @@ function FixSubver( patch, target ) {
/**
* Verify current version plugins
*
* @param {string} version
* @param {object} option
* @return {boolean}
*/
function VerifyPlugins( ver, option ) {
function VerifyPlugins( option ) {
try {
if ( option.plugins.length == 0 ) return false;
const str = option.plugins.join( "," );
if ( ver == "1.1.3" ) {
const newStr = str.replace( /(E0j1nYBmDD,?|SumEaxStWE,?|UsayAKSuwe,?)/g, "" );
if ( str != newStr ) {
option.plugins = newStr.replace( /,$/, "" ).split( "," );
return true;
}
} else return false;
const newStr = str.replace( /(E0j1nYBmDD,?|SumEaxStWE,?|EHLtCwBy6c,?|UsayAKSuwe,?)/g, "" );
if ( str != newStr ) {
option.plugins = newStr.replace( /,$/, "" ).split( "," );
return true;
}
} catch( error ) {
console.error( "version::VerifyPlugin catch", error )
return false;

9
src/vender/axios.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -110,13 +110,13 @@ Instapaper = (function() {
// Creates new Ajax request
// Always uses POST
request(options) {
var auth, req;
var auth, req, settings;
req = options.req || (options.req = this.makeRequestObject({
url: options.url,
data: options.data
}));
auth = this.authTemplate(options.req);
return $.ajax({
settings = {
url: `${this.baseUrl}${options.url}`,
dataType: (function() {
return options.dataType || "json";
@ -126,7 +126,11 @@ Instapaper = (function() {
headers: {
Authorization: auth
}
});
};
if ( options.url == "bookmarks/add" ) {
return settings;
}
return $.ajax(settings);
}
// ## Specific API Methods

View File

@ -1,8 +1,8 @@
/*!
* React Material Design: Button
*
* @version : 0.0.4
* @update : 2018/06/21
* @version : 0.0.4.1231
* @update : 2019/12/31
* @homepage: https://github.com/kenshin/mduikit-ui
* @license : MIT https://github.com/kenshin/mduikit/blob/master/LICENSE
* @author : Kenshin Wang <kenshin@ksria.com>
@ -218,6 +218,7 @@ export default class Button extends React.Component {
onMouseOut() {
const [ style, $mask ] = [ { ...this.style }, $( this.refs.mask ) ];
this.props.shape == "circle" && ( style.mask.borderRadius = "50%" );
$mask.css({ ...style.mask });
}
@ -278,13 +279,15 @@ export default class Button extends React.Component {
},
tooltip = this.props.tooltip;
this.props.shape == "circle" && ( style.mask.borderRadius = "50%" );
return (
<a style={ style.root } className={ this.props.waves }
<a style={ style.root }
href={ this.props.href } target={ this.props.target }
type={ this.props.type } mode={ this.props.mode }
type={ this.props.type } mode={ this.props.mode }
data-tooltip={ tooltip.text ? tooltip.text : this.props[ tooltip.target ] } data-tooltip-position={ tooltip.position } data-tooltip-delay={ tooltip.delay }
{ ...events }>
<button-mask ref="mask" style={ style.mask }>
<button-mask ref="mask" style={ style.mask } class={ this.props.waves }>
<button-span style={ style.span }>
<button-icon style={ style.icon } dangerouslySetInnerHTML={{__html: this.props.fontIcon }} ></button-icon>
<button-text style={ style.text }>{ this.props.text }</button-text>

View File

@ -1,8 +1,8 @@
/*!
* React Material Design: FAB( Floating Action Button )
*
* @version : 0.0.3
* @update : 2018/04/26
* @version : 0.0.3.0109
* @update : 2020/01/09
* @homepage: https://github.com/kenshin/mduikit
* @license : MIT https://github.com/kenshin/mduikit/blob/master/LICENSE
* @author : Kenshin Wang <kenshin@ksria.com>
@ -40,6 +40,7 @@ const cssinjs = () => {
width: '100px',
height: '100%',
zIndex: 2147483647,
},
origin : {

View File

@ -1,7 +1,7 @@
/*!
* React Material Design: FAP( Floating Action Panel )
*
* @version : 0.0.1
* @version : 0.0.1.1231
* @update : 2018/04/19
* @homepage: https://github.com/kenshin/mduikit
* @license : MIT https://github.com/kenshin/mduikit/blob/master/LICENSE
@ -193,6 +193,7 @@ const cssinjs_panel = () => {
groups: {
display: 'block',
width: '100%',
overflowX: 'hidden',
overflowY: 'auto',
},

View File

@ -1,8 +1,8 @@
/*!
* React Material Design: List
*
* @version : 0.0.3
* @update : 2018/04/26
* @version : 0.0.3.0116
* @update : 2020/01/16
* @homepage: https://github.com/kenshin/mduikit
* @license : MIT https://github.com/kenshin/mduikit/blob/master/LICENSE
* @author : Kenshin Wang <kenshin@ksria.com>
@ -251,7 +251,8 @@ const cssinjs = () => {
height: '32px',
color,
fontSize: '1.6rem',
fontSize: '1.2rem',
fontWeight: 400,
overflow: 'hidden',
textOverflow: 'ellipsis',
@ -351,7 +352,7 @@ const ListItem = props => {
return (
<list-item idx={ idx } style={ style.list_item }>
<pri-item style={ pri_style } onClick={ (e)=>events.priOnClick( e, props ) }>{ pri_value }</pri-item>
<content style={ content_style }>
<content style={ content_style } data-tooltip={ true_title } data-tooltip-position="up">
<a style={ style.link } href={ url } target="_blank">{ true_title }</a>
<subtitle style={ style.subtitle }>{ desc }</subtitle>
</content>

View File

@ -0,0 +1,147 @@
/*!
* React Material Design Style
*
* @version : 0.0.1
* @update : 2019/12/29
* @homepage: https://github.com/kenshin/mduikit
* @author : Kenshin Wang <kenshin@ksria.com>
*
* @copyright 2019
*/
/**
* Sidebar
*/
sidebar side content a {
transition: all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;
}
sidebar side content a:hover {
background-color: rgba(0,0,0,.04);
}
sidebar side content a.active {
font-weight: bold;
}
sidebar side toc {
position: relative;
width: 100%;
}
sidebar side toc i {
position: absolute;
left: 35px;
top: 0;
bottom: 0;
display: block;
width: 2px;
background: rgba(189,189,189,.4);
}
sidebar side toc outline {
position: relative;
display: -webkit-box!important;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
padding: 12px 0 12px 60px;
min-height: 21px;
line-height: 21px;
text-align: left;
cursor: pointer;
}
sidebar side toc outline:hover {
background-color: rgba(0,0,0,.04)!important;
}
sidebar side .toc-level-h1 {
padding-left: 60px;
}
sidebar side .toc-level-h2 {
padding-left: 70px;
}
sidebar side .toc-level-h3 {
padding-left: 75px;
}
sidebar side .toc-level-h4 {
padding-left: 80px;
}
/**
* Source from https://jonsuh.com/hamburgers/
*/
.hamburger {
font: inherit;
display: inline-block;
overflow: visible;
margin: 0;
padding: 15px;
cursor: pointer;
transition-timing-function: linear;
transition-duration: .15s;
transition-property: opacity,filter;
text-transform: none;
color: inherit;
border: 0;
background-color: transparent;
transform: scale(.5);
}
.hamburger-box {
position: relative;
display: inline-block;
width: 40px;
height: 24px;
}
.hamburger-inner {
top: 50%;
display: block;
margin-top: -2px;
}
.hamburger-inner, .hamburger-inner:after, .hamburger-inner:before {
position: absolute;
width: 40px;
height: 4px;
transition-timing-function: ease;
transition-duration: .15s;
transition-property: transform;
border-radius: 4px;
background-color: #9E9E9E;
}
.hamburger-inner:after, .hamburger-inner:before {
content: "";
display: block;
}
.hamburger-inner:before {
top: -10px;
}
.hamburger-inner:after {
bottom: -10px;
}
.hamburger:hover .hamburger-inner, .hamburger:hover .hamburger-inner:after, .hamburger:hover .hamburger-inner:before {
background-color: #9E9E9E;
transform: scale(.7);
}
.hamburger--arrow:hover .hamburger-inner:before {
transform: translate3d(-8px,0,0) rotate(-45deg) scaleX(.7);
}
.hamburger--arrow:hover .hamburger-inner:after {
transform: translate3d(-8px,0,0) rotate(45deg) scaleX(.7);
}

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,8 @@
/*!
* React Material Design: Sidebar
*
* @version : 0.0.3
* @update : 2018/04/26
* @version : 0.0.4.0104
* @update : 2019/12/30
* @homepage: https://github.com/kenshin/mduikit
* @license : MIT https://github.com/kenshin/mduikit/blob/master/LICENSE
* @author : Kenshin Wang <kenshin@ksria.com>
@ -69,14 +69,11 @@ const cssinjs = () => {
display: 'block',
position: 'relative',
marginTop: '8px',
paddingRight: paddingLeft,
paddingLeft,
width: '100%',
height: '100%',
fontSize: '1.3rem',
overflowY: 'auto',
},
footer: {
@ -84,8 +81,6 @@ const cssinjs = () => {
alignItems: 'center',
marginTop: '8px',
paddingLeft,
paddingRight: paddingLeft,
width: '100%',
height,
@ -148,12 +143,18 @@ const cssinjs = () => {
alignItems: 'center',
margin: 0,
padding: 0,
padding: '12px 48px 12px 24px',
width: '100%',
minHeight: itemHeight,
color,
fontSize: '1.4rem',
},
large_link: {
paddingLeft: 0,
fontSize: '2.2rem',
},
icon: {
@ -191,6 +192,46 @@ const cssinjs = () => {
zIndex: 2000,
},
font_icon: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
marginRight: '12px',
fontSize: '18px',
color: '#9E9E9E',
order: -1,
display: 'block',
width: '24px',
height: '24px',
fontSize: '14px',
border: 'none',
},
close_icon: {
position: 'absolute',
top: '0',
left: '-256px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '48px',
height: '48px',
color: '#9E9E9E',
backgroundColor: '#fff',
fontSize: '2rem',
border: 'none',
cursor: 'pointer',
},
};
return styles;
@ -200,29 +241,39 @@ const cssinjs = () => {
* React stateless component
*
* @param {object} react props, include:
* - large : [PropTypes.boolean]
* - name : [PropTypes.string] <a> text
* - value : [PropTypes.string] <a> value
* - route : [PropTypes.string] <a> href
* - icon : [PropTypes.string] icon
* - fontIcon : [PropTypes.string] icon
* - style : [PropTypes.object] include: icon link text
* - tooltip : [PropTypes.string] tooltip
* - waves : [PropTypes.string] waves
* - onClick : [PropTypes.func] event handler
*/
const Item = ( props ) => {
if ( props.icon ) {
props.style.icon.display = "block";
props.style.icon.backgroundImage = `url(${props.icon })`;
let icon_style = {}, link_style = { ...props.style.link };
if ( props.fontIcon ) {
icon_style = { ...props.style.font_icon };
icon_style.display = "flex";
} else if ( props.icon ) {
icon_style = { ...props.style.icon };
icon_style.display = "block";
icon_style.backgroundImage = `url(${props.icon })`;
} else {
props.style.icon.display = "none";
icon_style.display = "none";
}
if ( props.large ) {
link_style = { ...props.style.link, ...props.style.large_link };
}
const tooltip = props.tooltip;
return (
<a style={ props.style.link } className={ props.route && props.waves }
<a style={ link_style } className={ props.route && props.waves } target={ props.route && props.route.startsWith( "#" ) ? "_self" : "_blank" }
href={ props.route } value={ props.value }
data-tooltip={ tooltip.text ? tooltip.text : props[ tooltip.target ] } data-tooltip-position={ tooltip.position } data-tooltip-delay={ tooltip.delay }
onClick={ props.route && props.onClick && ( evt=>props.onClick(evt)) } >
<icon style={ props.style.icon }></icon>
<icon style={ icon_style } dangerouslySetInnerHTML={{__html: props.fontIcon || "" }} ></icon>
<text style={ props.style.text }>{ props.name }</text>
</a>
);
@ -253,6 +304,8 @@ class Sidebar extends React.Component {
footerStyle: undefined,
maskStyle : undefined,
waves : "",
autoClose : true,
showClose : false,
tooltip : {},
};
@ -269,6 +322,8 @@ class Sidebar extends React.Component {
contentStyle: React.PropTypes.object,
footerStyle: React.PropTypes.object,
maskStyle : React.PropTypes.object,
autoClose : React.PropTypes.bool,
showClose : React.PropTypes.bool,
waves : React.PropTypes.string,
tooltip : React.PropTypes.object,
onClick : React.PropTypes.func,
@ -281,8 +336,10 @@ class Sidebar extends React.Component {
let $target = $( event.target );
while ( !$target.is( "a" ) ) { $target = $target.parent(); }
const [ name, value, href ] = [ $target.text(), $target.attr( "value" ), $target.attr( "href" ) ];
$target.parent().parent().find( "a" ).removeClass( "active" );
$target.addClass( "active" );
this.props.onClick && this.props.onClick( $target, { name, value, href } );
this.maskOnClick();
this.props.autoClose && this.maskOnClick();
}
liOnClick( event ) {
@ -327,6 +384,7 @@ class Sidebar extends React.Component {
complete: () => {
$( "sidebar" ).css( "left", 0 - Number.parseInt( $( "side" ).width() ));
$( "mask" ).css( "display", "none" );
$( "side close" ).velocity({ left: 0 - Number.parseInt( $( "side" ).width() ) });
this.props.onExit && this.props.onExit();
}
});
@ -336,7 +394,7 @@ class Sidebar extends React.Component {
let menu = [];
const style = { ...this.style },
{ items, width,
header, icon, footer,
header, icon, footer, showClose,
color, bgColor,
headerStyle, contentStyle, footerStyle, maskStyle } = this.props;
@ -358,7 +416,8 @@ class Sidebar extends React.Component {
<li style={ style.li } onClick={ item.items && ( evt=>this.liOnClick(evt) ) } >
<Item style={ style }
waves={ this.props.waves } tooltip={ this.props.tooltip }
icon={ item.icon } name={ item.name } value={ item.value } route={ item.route }
icon={ item.icon } fontIcon={ item.fontIcon || "" }
name={ item.name } value={ item.value } route={ item.route }
onClick={ !item.items && ( evt=>this.onClick(evt) ) } />
{ item.items && item.items.length > 0 &&
<sub-menu style={ style.sub_menu }>
@ -377,7 +436,7 @@ class Sidebar extends React.Component {
<side style={ style.root }>
{ header &&
<header style={ style.header }>
<Item style={ style } icon={ icon } name={ header }
<Item style={ style } icon={ icon } name={ header } large={ true }
waves={ this.props.waves } tooltip={ this.props.tooltip }
onClick={ evt=>this.onClick(evt) }/>
</header>
@ -390,7 +449,16 @@ class Sidebar extends React.Component {
<Item style={ style } name={ footer }
waves={ this.props.waves } tooltip={ this.props.tooltip }
onClick={ evt=>this.onClick(evt) }/>
</footer>
</footer> }
{
showClose &&
<close className={ this.props.waves } style={ style.close_icon } onClick={ ()=>this.maskOnClick() }>
<div className="hamburger hamburger--arrow js-hamburger is-active">
<div className="hamburger-box">
<div className="hamburger-inner"></div>
</div>
</div>
</close>
}
</side>
<mask style={ style.mask } onClick={ evt=>this.maskOnClick(evt) }></mask>
@ -410,6 +478,64 @@ function Open() {
$( "mask" ).css( "opacity", complete ).css( "display", "block" );
}
});
$( "side close" ).velocity( { left: 256 });
tocRender();
activeRender();
}
/**
* TocRender
*/
function tocRender() {
if ( $( "sidebar content toc" ).length > 0 ) return;
const ids = [], tocs = new Map();
$( "tabs" ).find( "tab-label a" ).map( ( idx, item ) => ids.push( $(item).attr("value") ));
ids.forEach( ( id, idx ) => {
const levels = [];
$($( "tabs tab-group" )[idx]).find( "[data-head-level]" ).map( ( idx, item ) => {
const $item = $( item ),
id = "sr-toc-" + idx,
level = $item.attr( "data-head-level" ),
text = $item.attr( "data-head-title" ) || $item.text();
levels.push({ id, level, text });
$item.attr( "id", id );
});
tocs.set( id, levels );
});
$( "sidebar content" ).find( "a" ).map( ( idx, item ) => {
let html = "";
const $item = $( item ),
id = $item.attr( "value" ),
levels = tocs.get( id );
ids[idx] && levels.forEach( value => {
html += `<outline class="md-waves-effect" data-trigger="${ids[idx]}" data-id="${value.id}" class="toc-level-${ value.level }">${value.text}</outline>`;
});
html.length > 0 && $item.after( `<toc><i></i>${html}</to>` );
});
$( "sidebar content toc outline" ).on( "click", event => {
const id = $( event.currentTarget ).attr( "data-id" ),
trigger = $( event.currentTarget ).attr( "data-trigger" );
if ( !location.hash.endsWith( trigger ) ) {
$( "tabs" ).find( `tab-label a[value=${trigger}]` )[0].click();
}
// hack code
$( "tabs" ).find( "tab-group[active=true]" ).find( "#" + id )[0].scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'start' });
});
}
/**
* Active Render
*/
function activeRender() {
$( "sidebar content" ).find( "a" ).map( ( idx, item ) => {
const $item = $( item ),
id = $item.attr( "value" );
if ( location.hash.endsWith( id ) ) {
$item.addClass( "active" );
} else {
$item.removeClass( "active" );
}
});
}
export {

View File

@ -1,8 +1,8 @@
/*!
* React Material Design: Tooltip
*
* @version : 0.0.2
* @update : 2018/05/01
* @version : 0.0.3
* @update : 2019/12/31
* @homepage: https://github.com/kenshin/mduikit
* @license : MIT https://github.com/kenshin/mduikit/blob/master/LICENSE
* @author : Kenshin Wang <kenshin@ksria.com>
@ -10,12 +10,15 @@
* @reference:
* - https://material.io/guidelines/components/tooltips.html
* - http://materializecss.com/dialogs.html
* - https://kazzkiq.github.io/balloon.css/
*
* @copyright 2017
*/
console.log( "==== simpread component: ToolTip ====" )
import 'mintooltip';
let started = false, timeout, $target, $back, style, styles = new Map();
const cssinjs = () => {
const styles = {
@ -245,17 +248,27 @@ class ToolTip extends React.Component {
*
* @param {string} element, e.g. class: .xxx; id: #xxxx; tag: xxx
* @param {string} id
* @param {boolean} usage mintooltip default
*/
function Render( root, id ) {
function Render( root, id, is_mini = true ) {
setTimeout( () => {
const $root = !id ? $(root) : $(id);
$root.find( "[data-tooltip]" ).map( ( idx, item )=>{
$root.find( "[data-tooltip]" ).map( ( idx, item ) => {
const $item = $(item),
position = $item.attr( "data-tooltip-position" ),
delay = $item.attr( "data-tooltip-delay" ),
text = $item.attr( "data-tooltip" );
text && text != "" &&
if ( is_mini ) {
$item
.removeAttr( "data-tooltip-position" )
.removeAttr( "data-tooltip-delay" )
.removeAttr( "data-tooltip" )
.attr( "aria-label", text )
.attr( "data-balloon-pos", position || "up" );
} else {
text && text != "" &&
ReactDOM.render( <ToolTip root={ root } text={ text } position={ position } delay={ delay } $item={ $item } />, getTooltipRoot( $(root), id ) );
}
});
}, 500 );
}

View File

@ -36,11 +36,12 @@ notify-gp notify {
min-width: 288px;
max-width: 568px;
height: 48px;
max-height: 48px;
/*height: 48px;
max-height: 48px;*/
min-height: 48px;
color: rgba(255, 255, 255, .7);
background-color: rgba(50, 50, 50, 1);
color: rgba(255, 255, 255, 0.9);
background-color: #000;
box-sizing: border-box;
border-radius: 4px;
@ -50,9 +51,9 @@ notify-gp notify {
opacity: 0;
transform: scaleY(0);
transform-origin: left top 0px;
transition: transform 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms, opacity 1s cubic-bezier(0.23, 1, 0.32, 1) 0ms;
transition: all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms, opacity 1s cubic-bezier(0.23, 1, 0.32, 1) 0ms;
box-shadow: 0 1px 3px 0 rgba(60,64,67,0.302), 0 4px 8px 3px rgba(60,64,67,0.149);
box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12);
}
notify-gp notify-title {
@ -64,11 +65,12 @@ notify-gp notify-content {
display: block;
font-size: 14px;
font-weight: 400;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
/*text-overflow: ellipsis;
white-space: nowrap;*/
}
notify-gp notify-content a,
@ -98,6 +100,8 @@ notify-gp notify-content a:hover {
notify-gp notify-i {
display: none;
justify-content: center;
align-items: center;
margin: 0 10px 0 0;
@ -112,25 +116,34 @@ notify-gp notify-action,
notify-gp notify-cancel {
display: none;
margin: 0 0 0 24px;
margin: 0 8px;
max-width: 80px;
min-width: 56px;
height: 36px;
line-height: 34px;
color: #8ab4f8;
color: #bb86fc;
font-weight: 500;
font-size: inherit;
text-transform: uppercase;
text-align: right;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
transition: all 500ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;
cursor: pointer;
}
notify-gp notify-action:active,
notify-gp notify-cancel:active {
border-radius: 4px;
background-color: rgba(98, 0, 238, .3);
}
notify-gp notify-cancel {
margin: 0;
}
@ -145,11 +158,39 @@ notify-gp notify-a {
cursor: pointer;
}
notify-gp notify-exit {
display: none;
justify-content: center;
align-items: center;
margin-left: 5px;
width: 36px;
height: 36px;
min-width: 36px;
min-height: 36px;
background-color: transparent;
border-radius: 50%;
transition: all 500ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;
cursor: pointer;
}
notify-gp notify-exit:hover {
background-color: rgba(255, 255, 255, 0.4);
}
notify-gp notify-exit:active {
background-color: rgba(255, 255, 255, 0.2);
}
notify-gp notify-a notify-span {
display: block;
width: 16px;
height: 16px;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABpFBMVEUAAADl5eXj4+NSVFRTVVVaXFxLTU1hY2NdX18pLCwhJCSdnp5sbm6HiYmjpKSDhYX///+rrKytrq6XmJgzNTUoKyt3eXlydHRlZ2dbXV1ucHB4enrv7++KjIyIiort7e1oamosLy8aHR0VGBgUFxcbHh4rLi5oamprbGwgIyMKDQ0KDQ0iJSVjZWWfoaEkJiYICwsLDg4KDQ0MDw8iJSWMjo41ODgMDw8JDAw2OTkvMTELDg4LDg4xMzM1NzcJDAwLDg40NjYeISEHCgoeISFkZmYtLy8yNDRvcXEWGRkHCgoaHR3///8RFBQHCgohJCShoqLIyMgaHR0HCgoZGxv4+PgRFBQLDg4xMzOWl5eam5ssLi4bHh7///8fIiIJDAwwMzNzdHQXGhoeISFlZmYsLi4KDQ0gIiI6PDwOEREuMDAXGhoHCgodHx8pLCwNEBA1ODj///8nKSkICwsICwsJDAwnKSnZ2dl9fn4pKysNDw8OEREpLCxyc3ORkpIzNTUjJSUVGBgUFxcgIyM5PDyanJwEBwcDBwcDBgYFCAgGCQn///+5RDDmAAAAhnRSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQUFAQU+i7S0jkAGEYrw8Y8SBIn++Pr3jQQ67fx8dvX6iWr27z+B/YsOcoMPdPiEAaL7iAgEcfWsA6D7iAkGcawDef2LDnOFD3T4gTLnfHb6iWrqNQJ4+ff7fQILd+ToewsCLHWZmXUwAyFsKwcAAAABYktHRBCVsg0sAAAAzElEQVQY02NgwAoYZWTl5JngXGYFRSVlFVU1dRYIn1VDU6sNCLR1dNlAfHY9fQNDw/YOI2MDE1MOoACnmbmFpZW1ja2dvYMjFwMDN4NTp7OLq5u7h6dXpzcDDwOvj29bm59/QGBQcFtbSCgfA79AWFtHeERkVLR1W1tMrCCDEENcZ3xCYlJySmpaZzqDMAODSEamRVZ2cE5unn1+gSjQFrHCIqNir7a2nJLSsnJxkEMkKiqrutrauqpraiUhTpWqq29obGpuaZVmIAYAAO06McffKEk8AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDEzLTA0LTAzVDE3OjE4OjAzKzA4OjAwRdgB9wAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMS0wNS0xOFQyMDowMTowMCswODowMB0r3XkAAABNdEVYdHNvZnR3YXJlAEltYWdlTWFnaWNrIDYuOC44LTcgUTE2IHg4Nl82NCAyMDE0LTAyLTI4IGh0dHA6Ly93d3cuaW1hZ2VtYWdpY2sub3JnWaRffwAAABh0RVh0VGh1bWI6OkRvY3VtZW50OjpQYWdlcwAxp/+7LwAAABh0RVh0VGh1bWI6OkltYWdlOjpIZWlnaHQAMTI4Q3xBgAAAABd0RVh0VGh1bWI6OkltYWdlOjpXaWR0aAAxMjjQjRHdAAAAGXRFWHRUaHVtYjo6TWltZXR5cGUAaW1hZ2UvcG5nP7JWTgAAABd0RVh0VGh1bWI6Ok1UaW1lADEzMDU3MjAwNjArP9HVAAAAE3RFWHRUaHVtYjo6U2l6ZQAxLjAzS0JCZtQvXwAAAFx0RVh0VGh1bWI6OlVSSQBmaWxlOi8vL2hvbWUvZnRwLzE1MjAvZWFzeWljb24uY24vZWFzeWljb24uY24vY2RuLWltZy5lYXN5aWNvbi5jbi9wbmcvMTcvMTc4Ni5wbmcRsze7AAAAAElFTkSuQmCC);
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABDklEQVQ4T6VT0VFCQQzcrQA7ECoRK1AqEDugA6ECsQPsADvgVSAlaAlWEGdvkjchczI45Osud9nc7m2IEmY2BfAEYA5A6xsARwAHAB8ktR6DeWNmKwAvXlSxY78i+RabEcDM9gAe/qoq+T3JhXINwDu/Xlgc1zYk13TOn+XZA4C7AvgN4LbkZgJYO+84O5C8N7Odi6n8O8llh+ZGAD3uO5LPDgIvzoDRbBDAV+dputBAXKNecQM5B9CefQlAj0JwVmdLdGSwHI1CFXEgOS8ihia1WRNRdpU9JwlatpWVc0gr3c0xu95IAfdPK2uoHkcrJxANkzTJdPKTf3ROchvJk2n0LxNPfV9vnDVEJ+P8C6jMhLeGEqMKAAAAAElFTkSuQmCC);
opacity: .9;
}
notify-gp notify-i.holdon {
@ -165,24 +206,29 @@ notify-gp notify-i.holdon {
notify-gp .notify-show {
opacity: 1;
transform: scaleY(1);
transform: scaleY(1)!important;
}
notify-gp .notify-hide {
opacity: 0;
transform: scaleY(0);
animation-name: fadeOutUp;
animation-duration: 450ms;
animation-fill-mode: both;
}
notify-gp .notify-success {
color: rgba(118, 255, 3, .8);
background-color: rgb(76, 175, 80);
}
notify-gp .notify-warning {
color: rgba(255, 238, 88, 1);
background-color: rgb(255, 160, 0);
}
notify-gp .notify-error {
color: rgba(239, 83, 80, 1);
background-color: rgba(239, 83, 80, 1);
}
notify-gp .notify-info {
background-color: rgb(25, 118, 210);
}
notify-gp .notify-modal {
@ -261,3 +307,42 @@ notify-gp .notify-snackbar {
bottom: 0;
right: 0;
}
@keyframes fadeOutUp {
from {
opacity: 1;
}
to {
margin-top: 0;
padding: 0;
height: 0;
min-height: 0;
opacity: 0;
transform: scaleY(0);
}
}
@media (pointer: coarse) {
notify-gp {
top: initial;
bottom: 0;
left: 0;
margin: 0 10px 10px 10px;
}
notify-gp notify {
width: 100%;
max-width: 600px;
}
notify-gp .notify-show,
notify-gp .notify-hide {
transform-origin: bottom!important;
}
notify-gp .notify-snackbar {
position: initial;
}
}

View File

@ -6,7 +6,7 @@
*
* - content ( string, required)
*
* - type ( int, NORMAL/SUCCESS/WARING/ERROR)
* - type ( int, NORMAL/SUCCESS/WARING/ERROR/INFO)
* ( optional, default is NORMAL )
*
* - mode ( string, toast/modal/snackbar)
@ -58,7 +58,7 @@
*
*/
var Notify = ( function () {
var VERSION = "2.0.1",
var VERSION = "2.0.2.0105",
name = "notify",
root = "notify-gp",
roottmpl= "<" + root + ">",
@ -67,6 +67,7 @@ var Notify = ( function () {
SUCCESS = 1,
WARNING = 2,
ERROR = 3,
INFO = 4,
MODE = {
toast : "toast",
modal : "modal",
@ -93,6 +94,7 @@ var Notify = ( function () {
icon : "",
action : "",
cancel : "",
exit : undefined,
callback: undefined,
complete: undefined,
},
@ -106,7 +108,9 @@ var Notify = ( function () {
<notify-content></notify-content>\
<notify-action></notify-action>\
<notify-cancel></notify-cancel>\
<notify-exit></notify-exit>\
</notify>',
exit = '<svg t="1577940123220" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1411" width="24" height="24"><path d="M512 421.490332 331.092592 240.582924C306.351217 215.841549 265.464551 215.477441 240.470996 240.470996 215.303191 265.638801 215.527553 306.037221 240.582924 331.092592L421.490332 512 240.582925 692.907407C215.84155 717.648782 215.477441 758.535449 240.470996 783.529004 265.638801 808.696809 306.037222 808.472446 331.092593 783.417075L512 602.509668 692.907407 783.417075C717.648782 808.15845 758.535449 808.522559 783.529004 783.529004 808.696809 758.361199 808.472446 717.962778 783.417075 692.907407L602.509668 512 783.417076 331.092592C808.158451 306.351217 808.522559 265.464551 783.529004 240.470996 758.361199 215.303191 717.962779 215.527553 692.907408 240.582924L512 421.490332Z" p-id="1412" fill="#ffffff"></path></svg>',
loading = '\
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="lds-rolling">\
<circle stroke="#fff" stroke-width="10" cx="50" cy="50" fill="none" ng-attr-stroke="{{config.color}}" ng-attr-stroke-width="{{config.width}}" ng-attr-r="{{config.radius}}" ng-attr-stroke-dasharray="{{config.dasharray}}" r="30" stroke-dasharray="141.37166941154067 49.12388980384689" transform="rotate(102 50 50)">\
@ -139,10 +143,11 @@ var Notify = ( function () {
hidden( this );
},
hidden = function( target ) {
target.addClass( "notify-hide" ).slideUp( 500, function() {
target[0].addEventListener( 'animationend', function(e) {
target.remove();
if ($root.children().length === 0 ) $root.css( "z-index", 0 );
});
}, false );
target.css({ width: target[0].offsetWidth }).addClass( 'notify-hide' );
},
render = function() {
var $target = $( TMPL ),
@ -152,8 +157,29 @@ var Notify = ( function () {
$icon = $target.find(prefix( "i" )),
$action = $target.find(prefix( "action" )),
$cancel = $target.find(prefix( "cancel" )),
$exit = $target.find(prefix( "exit" )),
item = "notify-item-" + num++,
position = this.constructor.Position;
position = this.constructor.Position,
isMobile = {
Android: function() {
return navigator.userAgent.match(/Android/i);
},
BlackBerry: function() {
return navigator.userAgent.match(/BlackBerry/i);
},
iOS: function() {
return navigator.userAgent.match(/iPhone|iPad|iPod/i);
},
Opera: function() {
return navigator.userAgent.match(/Opera Mini/i);
},
Windows: function() {
return navigator.userAgent.match(/IEMobile/i);
},
verify: function() {
return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows()) == null ? false : true;
}
};
this.title ? $title.text( this.title ) : $title.hide();
this.content ? $content.html( this.content ) : $content.hide();
@ -167,18 +193,28 @@ var Notify = ( function () {
this.mode == MODE.snackbar && $target.addClass( "notify-snackbar" );
}
this.mode !== MODE.modal && this.icon !== "" &&
$icon.css({ "background-image": "url(" + this.icon + ")", "display": "block" });
if ( this.mode !== MODE.modal && this.icon !== "" ) {
if ( this.icon.indexOf( '<i' ) > -1 ) {
$icon.html( this.icon ).css({ display: 'flex' });
} else $icon.css({ "background-image": "url(" + this.icon + ")", "display": "block" });
}
switch( this.type ) {
case 1:
$content.addClass( "notify-success" );
this.state != STATE.holdon && this.icon == "" && $icon.html( '<i class="fas fa-check"></i>' ).css({ display: 'flex' });
$target.addClass( "notify-success" );
break;
case 2:
$content.addClass( "notify-warning" );
this.state != STATE.holdon && this.icon == "" && $icon.html( '<i class="fas fa-exclamation"></i>' ).css({ display: 'flex' });
$target.addClass( "notify-warning" );
break;
case 3:
$content.addClass( "notify-error" );
this.state != STATE.holdon && this.icon == "" && $icon.html( '<i class="fas fa-bug"></i>' ).css({ display: 'flex' });
$target.addClass( "notify-error" );
break;
case 4:
this.state != STATE.holdon && this.icon == "" && $icon.html( '<i class="fas fa-info"></i>' ).css({ display: 'flex' });
$target.addClass( "notify-info" );
break;
}
@ -194,6 +230,15 @@ var Notify = ( function () {
$root.on( "click", "." + item + " notify-cancel", [ item, this.callback, "cancel" ], callbackHander );
}
if ( this.type != 0 && this.icon.indexOf( '<i' ) > -1 ) {
var css = function( element, property ) {
return window.getComputedStyle( element, null ).getPropertyValue( property ).toLowerCase().replace( / /g, "" );
}, $span = $( '<span style="display:none;" class="verify-fas fas"></span>' )
$( 'body' ).append( $span );
!/fontawesome/.test( css( $span[0], 'font-family' ) ) && $icon.remove();
$span.remove();
}
this.mode !== MODE.modal && this.state !== STATE.loading && this.state !== STATE.holdon && ( this.action == "" || !this.callback || typeof this.callback != "function" ) &&
( timer[item] = setTimeout( delayHandler.bind( $target, item ), this.delay ) );
@ -223,8 +268,16 @@ var Notify = ( function () {
}
$target.addClass( item );
$root.append( $target ).css( "z-index", 2147483647 );
this.mode == MODE.snackbar && $target.css( "margin-left", "-" + $target.width()/2 + "px" );
$root.css( "z-index", 2147483647 );
isMobile.verify() ? $root.prepend( $target ) : $root.append( $target );
if ( this.mode == MODE.snackbar || this.exit ) {
$target.css( "margin-left", "-" + $target.width()/2 + "px" );
if ( this.cancel == "" ) {
$exit.html( exit ).css( "display", "flex" );
$root.on( "click", "." + item + " notify-exit", closeHandle );
}
}
setTimeout( function() { $target.addClass( "notify-show" ); }, 200 );
};
@ -284,6 +337,7 @@ var Notify = ( function () {
this.content = arguments[0];
this.action = arguments[1];
this.callback = arguments[2];
this.exit = true;
break;
case 4:
if ( arguments[0] == MODE.snackbar ) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

126
src/vender/wiz.js Normal file
View File

@ -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(/<script[^<>]*\/>/ig, "").replace(/<script[^<>]*>(((?!<\/script>).)|(\r?\n))*<\/script>/ig, "");
};
if (!str || str.length < 1) {
return "";
}
var base64str = Base64.encode(scriptFilter(str));
return base64str;
}
var genGuid = function() {
return (genGuidItem() + genGuidItem() + "-" + genGuidItem() + "-" + genGuidItem() + "-" + genGuidItem() + "-" + genGuidItem() + genGuidItem() + genGuidItem());
}
var genGuidItem = function() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
function getParams( url, title, htmlStr ) {
var params = "";
var docType = document.doctype;
var source_url = wiz_base64Encode( url );
var source_html = "";
var source_title = wiz_base64Encode( title );
if (!!docType && !!docType.systemId && !!docType.publicId) {
docType = '<!DOCTYPE HTML PUBLIC "' + docType.publicId + '" "' + docType.systemId + '" >';
} else {
docType = '<!DOCTYPE HTML>';
}
source_html = wiz_base64Encode( docType + htmlStr );
params = "param-location='" + source_url + "' ";
params += "param-title='" + source_title + "' ";
params += "0_FrameURL='" + source_url + "' ";
params += "0_FrameHtml='" + source_html + "' ";
params = "param-fcount='1' " + params;
return params;
}
function getInfos( info, access_token ) {
var docGuid = genGuid();
info.params = info.params + ' save-command="' + info.cmd + '" userid="' + info.userid +
'" location="' + wiz_base64Encode(info.category) + '" comment="' + wiz_base64Encode('') +
'" tag="' + wiz_base64Encode(info.tag) + '"';
info.params = "myWiz='" + access_token + "@userguid' SaveResources='true' document_guid='" + docGuid + "' " + info.params;
var params = {
type : 'clipper',
data : info.params,
customId: docGuid
};
return params;
}
if ( typeof module !== 'undefined' ) {
module.exports = {
getParams: getParams,
getInfos : getInfos,
};
}

View File

@ -32,6 +32,24 @@
"<div class='author-share'>",
"<div class='embed-control'>"
]
},{
"name" : "topic.readhub.cn",
"url" : "https://readhub.cn/topic/*",
"title" : "<h2 class='topicTitle___3DA7c'>",
"desc" : "",
"include" : "[[{$('.content___2CL42').find('.summary___3oqrM').parent().html()}]]",
"exclude" : [
""
]
},{
"name" : "newsflashes.36kr.com",
"url" : "https://36kr.com/newsflashes/*",
"title" : "<a class='item-title'>",
"desc" : "",
"include" : "<pre class='pre-item-des'>",
"exclude" : [
""
]
},{
"name" : "36kr.com",
"url" : "http://36kr.com/p/",
@ -46,20 +64,29 @@
"<div class='share-nav'>"
]
},{
"name" : "pingwest.com",
"url" : "http*://www.pingwest.com/a/*",
"name" : "s.pingwest.com",
"url" : "http*://www.pingwest.com/s/*",
"title" : "<title>",
"desc" : "",
"include" : "<article class=\"article-style\">",
"include" : "[[{$($('section.content')[1]).html()}]]",
"exclude" : [
""
]
},{
"name" : "wire.pingwest.com",
"url" : "http*://www.pingwest.com/wire/",
"title" : "<h1 class='title'>",
"desc" : "",
"include" : "<div id='sc-container'>",
"exclude" : [
"<p class='post-footer-wx'>"
]
},{
"name" : "pingwest.com",
"url" : "http://www.pingwest.com/wire/",
"title" : "<h1 class='title'>",
"url" : "http*://www.pingwest.com/a/*",
"title" : "<title>",
"desc" : "",
"include" : "<div id='sc-container'>",
"include" : "<article class=\"article-style\">",
"exclude" : [
"<p class='post-footer-wx'>"
]
@ -201,9 +228,9 @@
},{
"name" : "sspai.com",
"url" : "https://sspai.com/post/",
"title" : "<h1 class='title'>",
"title" : "[[{$('title').text().replace( ' - 少数派', '' )}]]",
"desc" : "[[{$('meta[name=description]').attr('content')}]]",
"include" : "[[[$('.content')]]]",
"include" : "[[[$('.articleWidth-content').find('.content')]]]",
"exclude" : [
"<img id='s1' >",
"<hr>",
@ -225,7 +252,7 @@
"url" : "http*://www.dgtle.com/article-*.html",
"title" : "<title>",
"desc" : "[[{$('meta[name=description]').attr('content')}]]",
"include" : "[[{$('.view_content').html()||$('#view_content').html()}]]",
"include" : "[[{$('.view_content').html()||$('#view_content').html()||$('#articleContent').html()||$('.forum-viewthread-article-box').html()}]]",
"exclude" : [
"<div id='comments_top'>",
"[[/src=\\S+(xxxxxbbs)\\S+'/]]"
@ -280,7 +307,8 @@
"include" : "[[{$('.RichContent-inner')}]]",
"exclude" : [
"<i class='icon-external'>"
]
],
"css" : ".MCNLinkCard-info { margin-left: 12px;}"
},{
"name" : "geekpark.net",
"url" : "http://www.geekpark.net/topics/",
@ -367,6 +395,24 @@
"exclude" : [
""
]
},{
"name" : "creatorsdaily.com",
"url" : "[[/https://creatorsdaily.com/posts/\\w+/]]",
"title" : "<span class='sub-title'>",
"desc" : "[[{$('meta[name=Description]').attr('content')||$('meta[name=description]').attr('content')}]]",
"include" : "[[`//*[@id='__next']/section[1]/main[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[1]`]]",
"exclude" : [
"[[`/html[1]/div[1]/sr-read[1]/sr-rd-content[1]/div[1]`]]"
]
},{
"name" : "spaces.ac.cn",
"url" : "https://spaces.ac.cn/archives/*",
"title" : "<span class='sub-title'>",
"desc" : "[[{$('meta[name=Description]').attr('content')||$('meta[name=description]').attr('content')}]]",
"include" : "<div class='PostContent'>",
"exclude" : [
""
]
},{
"name" : "huxiu.com",
"url" : "https://www.huxiu.com/article/",
@ -386,6 +432,24 @@
"exclude" : [
""
]
},{
"name" : "movie.douban.com",
"url" : "[[/https:\\/\\/movie.douban.com\\/subject\\/\\d+\\/?/]]",
"title" : "<title>",
"desc" : "",
"include" : "<div id='link-report'>",
"exclude" : [
""
]
},{
"name" : "note.douban.com",
"url" : "[[/https?:\\/\\/www.douban.com\\/note\\/\\d+\\/?/]]",
"title" : "<title>",
"desc" : "",
"include" : "<div id='link-report'>",
"exclude" : [
""
]
},{
"name" : "m.douban.com",
"url" : "https://m.douban.com/*",
@ -655,7 +719,8 @@
"<table class='navbox'>",
"<div class='thumb'>",
"<div class='dablink'>",
"<table class='metadata'>"
"<table class='metadata'>",
"<math>"
]
},{
"name" : "article.pmcaff.com",
@ -909,6 +974,15 @@
"exclude" : [
""
]
},{
"name" : "infoq.cn",
"url" : "http*://www.infoq.cn/article/*",
"title" : "<title>",
"desc" : "",
"include" : "<div class='article-content'>",
"exclude" : [
""
]
},{
"name" : "infoq.com",
"url" : "http://www.infoq.com/cn/articles/",
@ -1120,7 +1194,9 @@
"desc" : "",
"include" : "<div class='article_content'>",
"exclude" : [
"<div class='meau-gotop-box'>"
"<div class='meau-gotop-box'>",
"<div class='more-toolbox'>",
"<div class='person-messagebox'>"
],
"css" : ".markdown_views pre code{background-color:transparent!important;}"
},{
@ -1159,6 +1235,16 @@
"exclude" : [
"[['<p>(完)</p>']]"
]
},{
"name" : "ruanyf.yuque.com",
"url" : "[[/https://www.yuque.com/ruanyf/weekly/issue-\\d+/]]",
"title" : "<h1 id='page-title'>",
"desc" : "[[{$('meta[name=Description]').attr('content')||$('meta[name=description]').attr('content')}]]",
"include" : "[[`//*[@id='content']/div[2]/div[1]/div[1]`]]",
"exclude" : [
""
],
"css": "span svg { display: none; }"
},{
"name" : "v2ex.com",
"url" : "https://www.v2ex.com/t/",
@ -1838,11 +1924,12 @@
"url" : "http*://post.smzdm.com/p/*",
"title" : "<title>",
"desc" : "",
"include" : "<div class='news_content'>",
"include" : "[[`//*[@id='articleId']`]]",
"exclude" : [
"<h1 class='item-name'>",
"<span class='embed-card'>"
]
],
"css" : ".embed-card-logo { margin-right: 14px }"
},{
"name" : "news.mydrivers.com",
"url" : "http://news.mydrivers.com/*/*/*.htm",

View File

@ -49,10 +49,12 @@ const webpack = require( 'webpack' ),
{ from : "src/manifest.json" , to : '../' },
{ from : "src//help_tips.json" , to : '../' },
{ from : "src/website_list.json" , to : '../' },
{ from : "src/ga.js" , to : '../' },
{ from : 'src/options/options.html', to : '../options/' },
{ from : 'src/options/custom.html', to : '../options/' },
{ from : 'src/options/sitemgr.html', to : '../options/' },
{ from : 'src/options/notice.html', to : '../options/' },
{ from : 'src/options/corb.html', to : '../options/' },
{ context: 'src/assets/images/', from : "*" , to : '../assets/images' },
{ context: 'src/_locales/', from : "*/*" , to : '../_locales/' },
])
@ -174,6 +176,7 @@ const webpack = require( 'webpack' ),
custom : './src/options/custom.js',
sitemgr : './src/options/sitemgr.js',
notice : './src/options/notice.js',
corb : './src/options/corb.js',
},
output: {
@ -229,6 +232,7 @@ const webpack = require( 'webpack' ),
nanoid : __dirname + '/node_modules/nanoid/generate.js',
jquery : __dirname + '/src/vender/jquery-2.1.1.min.js',
axios : __dirname + '/src/vender/axios.min.js',
mousetrap : __dirname + '/src/vender/mousetrap.min.js',
velocity : __dirname + '/src/vender/velocity.min.js',
timeago : __dirname + '/src/vender/timeago.min.js',
@ -237,6 +241,7 @@ const webpack = require( 'webpack' ),
filesaver : __dirname + '/src/vender/filesaver.min.js',
instapaper : __dirname + '/src/vender/instapaper.js',
webdav : __dirname + '/src/vender/webdav.js',
wiz : __dirname + '/src/vender/wiz.js',
markdown : __dirname + '/src/vender/turndown/turndown.js',
mdgfm : __dirname + '/src/vender/turndown/turndown-plugin-gfm.js',
intro : __dirname + '/src/vender/intro/intro.min.js',
@ -257,6 +262,10 @@ const webpack = require( 'webpack' ),
highlight : __dirname + '/src/service/highlight.js',
output : __dirname + '/src/service/output.js',
runtime : __dirname + '/src/service/runtime.js',
permission : __dirname + '/src/service/permission.js',
offline : __dirname + '/src/service/offline.js',
snapshot : __dirname + '/src/service/snapshot.js',
tips : __dirname + '/src/service/tips.js',
focus : __dirname + '/src/focus/focus.js',
controlbar : __dirname + '/src/focus/controlbar.jsx',
@ -288,6 +297,8 @@ const webpack = require( 'webpack' ),
sharecard : __dirname + '/src/module/sharecard.jsx',
notice : __dirname + '/src/module/notice.jsx',
guide : __dirname + '/src/module/guide.jsx',
urlscheme : __dirname + '/src/module/urlscheme.jsx',
feedback : __dirname + '/src/module/feedback.jsx',
editor : __dirname + '/src/module/common/editor.jsx',
themesel : __dirname + '/src/module/common/theme.jsx',
shortcuts : __dirname + '/src/module/common/shortcuts.jsx',
@ -299,6 +310,7 @@ const webpack = require( 'webpack' ),
wavess : __dirname + '/src/vender/waves/waves.js',
notify : __dirname + '/src/vender/notify/notify.js',
mduikit_css: __dirname + '/src/vender/mduikit/mduikit.css',
textfield : __dirname + '/src/vender/mduikit/textfield.jsx',
fab : __dirname + '/src/vender/mduikit/fab.jsx',
fap : __dirname + '/src/vender/mduikit/fap.jsx',