fetch太慢去除历史提交记录
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
.editor {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
.setbox,
|
||||
.menu,
|
||||
.outbox {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
max-height: 100vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.menu {
|
||||
justify-content: center;
|
||||
max-width: 90px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
.menu .button {
|
||||
width: 90px;
|
||||
height: 30px;
|
||||
min-height: 30px;
|
||||
margin: 5px 0px;
|
||||
cursor: pointer;
|
||||
}
|
||||
@keyframes stroker {
|
||||
0% {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
100% {
|
||||
stroke-dashoffset: -240;
|
||||
}
|
||||
}
|
||||
.button rect {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
fill: transparent;
|
||||
stroke: #666;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
.button rect.busy {
|
||||
stroke: #fd1850;
|
||||
stroke-dasharray: 30 90;
|
||||
animation: stroker 1s linear infinite;
|
||||
}
|
||||
.button text {
|
||||
text-anchor: middle;
|
||||
dominant-baseline: middle;
|
||||
}
|
||||
.setbox {
|
||||
min-width: 40em;
|
||||
}
|
||||
.rules {
|
||||
overflow: auto;
|
||||
}
|
||||
.tabbox {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
.rules > * {
|
||||
display: flex;
|
||||
margin: 2px 0;
|
||||
}
|
||||
.rules textarea {
|
||||
flex: 1;
|
||||
margin-left: 5px;
|
||||
}
|
||||
.rules > *,
|
||||
.rules > * > div,
|
||||
.rules textarea {
|
||||
min-height: 1em;
|
||||
}
|
||||
textarea {
|
||||
word-break: break-all;
|
||||
}
|
||||
.tabtitle {
|
||||
display: flex;
|
||||
z-index: 1;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.tabtitle > div {
|
||||
cursor: pointer;
|
||||
padding: 1px 10px 0 10px;
|
||||
border-bottom: 3px solid transparent;
|
||||
font-weight: bold;
|
||||
}
|
||||
.tabtitle > .this {
|
||||
color: #4f9da6;
|
||||
border-bottom-color: #4ebbe4;
|
||||
}
|
||||
.tabbody {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
margin-top: -1px;
|
||||
border: 1px solid #a9a9a9;
|
||||
height: 0;
|
||||
}
|
||||
.tabbody > * {
|
||||
flex: 1;
|
||||
flex-flow: column;
|
||||
display: none;
|
||||
}
|
||||
.tabbody > .this {
|
||||
display: flex;
|
||||
}
|
||||
.tabbody > * > .titlebar {
|
||||
display: flex;
|
||||
}
|
||||
.tabbody > * > .titlebar > * {
|
||||
flex: 1;
|
||||
margin: 1px 1px 1px 1px;
|
||||
}
|
||||
.tabbody > * > .context {
|
||||
flex: 1;
|
||||
flex-flow: column;
|
||||
border: 0;
|
||||
padding: 5px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.tabbody > * > .inputbox {
|
||||
border: 0;
|
||||
border-bottom: #a9a9a9 solid 1px;
|
||||
height: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
.link > * {
|
||||
display: flex;
|
||||
margin: 5px;
|
||||
border-bottom: 1px solid;
|
||||
text-decoration: none;
|
||||
}
|
||||
#RuleList > label > * {
|
||||
background: #eee;
|
||||
padding-left: 3px;
|
||||
margin: 2px 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
#RuleList input[type="radio"] {
|
||||
display: none;
|
||||
}
|
||||
#RuleList input[type="radio"]:checked + * {
|
||||
background: #15cda8;
|
||||
}
|
||||
.isError {
|
||||
color: #ff0000;
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>阅读3.0源编辑器_V4.0</title>
|
||||
<link rel="icon" href="favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="index.css"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="editor">
|
||||
<div class="setbox">
|
||||
<div>
|
||||
<a href="../index.html">←主页</a>
|
||||
<b>书源</b>
|
||||
</div>
|
||||
<div class="rules">
|
||||
<div><b>基本</b></div>
|
||||
<div>
|
||||
<div>源域名 :</div>
|
||||
<textarea rows="1" id="bookSourceUrl" class="base" title="bookSourceUrl"
|
||||
placeholder="<必填>通常填写网站主页,例: https://www.qidian.com"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>源类型 :</div>
|
||||
<textarea rows="1" id="bookSourceType" class="base" title="bookSourceType"
|
||||
placeholder="<必填>0:文本 1:音频"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>源名称 :</div>
|
||||
<textarea rows="1" id="bookSourceName" class="base" title="bookSourceName"
|
||||
placeholder="<必填>会显示在源列表"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>源分组 :</div>
|
||||
<textarea rows="1" id="bookSourceGroup" class="base" title="bookSourceGroup"
|
||||
placeholder="<选填>描述源的特征信息"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>源注释 :</div>
|
||||
<textarea rows="1" id="bookSourceComment" class="base" title="bookSourceComment"
|
||||
placeholder="<选填>描述源作者和状态"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>登录地址:</div>
|
||||
<textarea rows="1" id="loginUrl" class="base" title="loginUrl"
|
||||
placeholder="<选填>填写网站登录网址,仅在需要登录的源有用"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>登录界面:</div>
|
||||
<textarea rows="3" id="loginUi" class="base" title="loginUi"
|
||||
placeholder="<选填>自定义登录界面"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>登录检测:</div>
|
||||
<textarea rows="3" id="loginCheckJs" class="base" title="loginCheckJs"
|
||||
placeholder="<选填>登录检测js"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>并发率 :</div>
|
||||
<textarea rows="1" id="concurrentRate" class="base" title="concurrentRate"
|
||||
placeholder="<选填>并发率"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>请求头 :</div>
|
||||
<textarea rows="3" id="header" class="base" title="header"
|
||||
placeholder="<选填>客户端标识"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>链接验证:</div>
|
||||
<textarea rows="1" id="bookUrlPattern" class="base" title="bookUrlPattern"
|
||||
placeholder="<选填>当详情页URL与源URL的域名不一致时有效,用于添加网址"></textarea>
|
||||
</div>
|
||||
<p></p>
|
||||
<div><b>搜索</b></div>
|
||||
<div>
|
||||
<div>搜索地址:</div>
|
||||
<textarea rows="1" id="searchUrl" class="base" title="searchUrl"
|
||||
placeholder="[域名可省略]/search.php@kw={{key}}"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>校验文字:</div>
|
||||
<textarea rows="1" id="ruleSearch_checkKeyWord" class="ruleSearch"
|
||||
title="checkKeyWord"
|
||||
placeholder="校验关键字"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>列表规则:</div>
|
||||
<textarea rows="1" id="ruleSearch_bookList" class="ruleSearch" title="bookList"
|
||||
placeholder="选择书籍节点 (规则结果为List<Element>)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>书名规则:</div>
|
||||
<textarea rows="1" id="ruleSearch_name" class="ruleSearch" title="name"
|
||||
placeholder="选择节点书名 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>作者规则:</div>
|
||||
<textarea rows="1" id="ruleSearch_author" class="ruleSearch" title="author"
|
||||
placeholder="选择节点作者 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>分类规则:</div>
|
||||
<textarea rows="1" id="ruleSearch_kind" class="ruleSearch" title="kind"
|
||||
placeholder="选择节点分类信息 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>字数规则:</div>
|
||||
<textarea rows="1" id="ruleSearch_wordCount" class="ruleSearch" title="wordCount"
|
||||
placeholder="选择节点字数信息 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>最新章节:</div>
|
||||
<textarea rows="1" id="ruleSearch_lastChapter" class="ruleSearch"
|
||||
title="lastChapter"
|
||||
placeholder="选择节点最新章节 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>简介规则:</div>
|
||||
<textarea rows="1" id="ruleSearch_intro" class="ruleSearch" title="intro"
|
||||
placeholder="选择节点书籍简介 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>封面规则:</div>
|
||||
<textarea rows="1" id="ruleSearch_coverUrl" class="ruleSearch" title="coverUrl"
|
||||
placeholder="选择节点书籍封面 (规则结果为String类型的url)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>详情地址:</div>
|
||||
<textarea rows="1" id="ruleSearch_bookUrl" class="ruleSearch" title="bookUrl"
|
||||
placeholder="选择书籍详情页网址 (规则结果为String类型的url)"></textarea>
|
||||
</div>
|
||||
<p></p>
|
||||
<div><b>发现</b></div>
|
||||
<div>
|
||||
<div>发现地址:</div>
|
||||
<textarea rows="6" id="exploreUrl" class="base" title="exploreUrl"
|
||||
placeholder="内容能显示在发现菜单 每行一条发现分类(网址域名可省略),例: 名称1::网址(Url)1 名称2::网址(Url)2 ..."></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>列表规则:</div>
|
||||
<textarea rows="1" id="ruleExplore_bookList" class="ruleExplore" title="bookList"
|
||||
placeholder="选择书籍节点 (规则结果为List<Element>)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>书名规则:</div>
|
||||
<textarea rows="1" id="ruleExplore_name" class="ruleExplore" title="name"
|
||||
placeholder="选择节点书名 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>作者规则:</div>
|
||||
<textarea rows="1" id="ruleExplore_author" class="ruleExplore" title="author"
|
||||
placeholder="选择节点作者 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>分类规则:</div>
|
||||
<textarea rows="1" id="ruleExplore_kind" class="ruleExplore" title="kind"
|
||||
placeholder="选择节点分类信息 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>字数规则:</div>
|
||||
<textarea rows="1" id="ruleExplore_wordCount" class="ruleExplore" title="wordCount"
|
||||
placeholder="选择节点字数信息 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>最新章节:</div>
|
||||
<textarea rows="1" id="ruleExplore_lastChapter" class="ruleExplore"
|
||||
title="lastChapter"
|
||||
placeholder="选择节点最新章节 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>简介规则:</div>
|
||||
<textarea rows="1" id="ruleExplore_intro" class="ruleExplore" title="intro"
|
||||
placeholder="选择节点书籍简介 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>封面规则:</div>
|
||||
<textarea rows="1" id="ruleExplore_coverUrl" class="ruleExplore" title="coverUrl"
|
||||
placeholder="选择节点书籍封面 (规则结果为String类型的url)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>详情地址:</div>
|
||||
<textarea rows="1" id="ruleExplore_bookUrl" class="ruleExplore" title="bookUrl"
|
||||
placeholder="选择书籍详情页网址 (规则结果为String类型的url)"></textarea>
|
||||
</div>
|
||||
<p></p>
|
||||
<div><b>详情</b></div>
|
||||
<div>
|
||||
<div>预处理 :</div>
|
||||
<textarea rows="3" id="ruleBookInfo_init" class="ruleBookInfo" title="init"
|
||||
placeholder="用于加速详情信息检索,只支持AllInOne规则"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>书名规则:</div>
|
||||
<textarea rows="1" id="ruleBookInfo_name" class="ruleBookInfo" title="name"
|
||||
placeholder="选择节点书名 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>作者规则:</div>
|
||||
<textarea rows="1" id="ruleBookInfo_author" class="ruleBookInfo" title="author"
|
||||
placeholder="选择节点作者 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>分类规则:</div>
|
||||
<textarea rows="1" id="ruleBookInfo_kind" class="ruleBookInfo" title="kind"
|
||||
placeholder="选择节点分类信息 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>字数规则:</div>
|
||||
<textarea rows="1" id="ruleBookInfo_wordCount" class="ruleBookInfo"
|
||||
title="wordCount"
|
||||
placeholder="选择节点字数信息 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>最新章节:</div>
|
||||
<textarea rows="1" id="ruleBookInfo_lastChapter" class="ruleBookInfo"
|
||||
title="lastChapter"
|
||||
placeholder="选择节点最新章节 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>简介规则:</div>
|
||||
<textarea rows="1" id="ruleBookInfo_intro" class="ruleBookInfo" title="intro"
|
||||
placeholder="选择节点书籍简介 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>封面规则:</div>
|
||||
<textarea rows="1" id="ruleBookInfo_coverUrl" class="ruleBookInfo" title="coverUrl"
|
||||
placeholder="选择节点书籍封面 (规则结果为String类型的url)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>目录地址:</div>
|
||||
<textarea rows="1" id="ruleBookInfo_tocUrl" class="ruleBookInfo" title="tocUrl"
|
||||
placeholder="选择书籍详情页网址 (规则结果为String类型的url, 与详情页相同时可省略)"></textarea>
|
||||
</div>
|
||||
<p></p>
|
||||
<div><b>目录</b></div>
|
||||
<div>
|
||||
<div>列表规则:</div>
|
||||
<textarea rows="3" id="ruleToc_chapterList" class="ruleToc" title="chapterList"
|
||||
placeholder="选择目录列表的章节节点 (规则结果为List<Element>)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>章节名称:</div>
|
||||
<textarea rows="1" id="ruleToc_chapterName" class="ruleToc" title="chapterName"
|
||||
placeholder="选择章节名称 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>章节地址:</div>
|
||||
<textarea rows="1" id="ruleToc_chapterUrl" class="ruleToc" title="chapterUrl"
|
||||
placeholder="选择章节链接 (规则结果为String类型的Url)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>收费标识:</div>
|
||||
<textarea rows="1" id="ruleToc_isVip" class="ruleToc" title="isVip"
|
||||
placeholder="章节是否为VIP章节 (规则结果为Bool)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>购买标识:</div>
|
||||
<textarea rows="1" id="ruleToc_isPay" class="ruleToc" title="isPay"
|
||||
placeholder="章节是否为已购买 (规则结果为Bool)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>章节信息:</div>
|
||||
<textarea rows="1" id="ruleToc_updateTime" class="ruleToc" title="updateTime"
|
||||
placeholder="选择章节信息 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>翻页规则:</div>
|
||||
<textarea rows="1" id="ruleToc_nextTocUrl" class="ruleToc" title="nextTocUrl"
|
||||
placeholder="选择目录下一页链接 (规则结果为List<String>或String)"></textarea>
|
||||
</div>
|
||||
<p></p>
|
||||
<div><b>正文</b></div>
|
||||
<div>
|
||||
<div>脚本注入:</div>
|
||||
<textarea rows="3" id="ruleContent_webJs" class="ruleContent" title="webJs"
|
||||
placeholder="注入javascript,用于模拟鼠标点击等,必须有返回值,一般为String类型"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>正文规则:</div>
|
||||
<textarea rows="1" id="ruleContent_content" class="ruleContent" title="content"
|
||||
placeholder="选择正文内容 (规则结果为String)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>翻页规则:</div>
|
||||
<textarea rows="1" id="ruleContent_nextContentUrl" class="ruleContent"
|
||||
title="nextContentUrl"
|
||||
placeholder="选择下一分页(不是下一章)链接 (规则结果为String类型的Url)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>资源正则:</div>
|
||||
<textarea rows="1" id="ruleContent_sourceRegex" class="ruleContent"
|
||||
title="sourceRegex"
|
||||
placeholder="匹配资源的url特征,用于嗅探"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>替换规则:</div>
|
||||
<textarea rows="1" id="ruleContent_replaceRegex" class="ruleContent"
|
||||
title="replaceRegex"
|
||||
placeholder="多页内容合并后替换,用于正文净化"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>图片样式:</div>
|
||||
<textarea rows="1" id="ruleContent_imageStyle" class="ruleContent"
|
||||
title="imageStyle"
|
||||
placeholder="FULL:铺满 不填:默认样式"></textarea>
|
||||
</div>
|
||||
<p></p>
|
||||
<div><b>其它规则</b></div>
|
||||
<div>
|
||||
<div>启用搜索:</div>
|
||||
<textarea rows="1" id="enabled" class="base" title="enabled"
|
||||
placeholder="启用: true 关闭: false (可选,默认true)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>启用发现:</div>
|
||||
<textarea rows="1" id="enabledExplore" class="base" title="enabledExplore"
|
||||
placeholder="启用: true 关闭: false (可选,默认true)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>搜索权重:</div>
|
||||
<textarea rows="1" id="weight" class="base" title="weight"
|
||||
placeholder="整数: 0~N (可选,默认0) | 数字越大越靠前"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>排序编号:</div>
|
||||
<textarea rows="1" id="customOrder" class="base" title="customOrder"
|
||||
placeholder="整数: 0~N (可选,默认0) | 数字越小越靠前"></textarea>
|
||||
</div>
|
||||
<div style="display:none;">
|
||||
<div>更新时间:</div>
|
||||
<textarea rows="1" id="lastUpdateTime" class="base" title="lastUpdateTime"
|
||||
placeholder="毫秒级时间戳 (自动生成) | 请勿手动填写"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="menu">
|
||||
<svg class="button">
|
||||
<text x="50%" y="55%">⇈推送源</text>
|
||||
<rect id="push"></rect>
|
||||
</svg>
|
||||
<svg class="button">
|
||||
<text x="50%" y="55%">⇊拉取源</text>
|
||||
<rect id="pull"></rect>
|
||||
</svg>
|
||||
<svg class="button">
|
||||
<text x="50%" y="55%">⋘编辑源</text>
|
||||
<rect id="editor"></rect>
|
||||
</svg>
|
||||
<svg class="button">
|
||||
<text x="50%" y="55%">⋙生成源</text>
|
||||
<rect id="conver"></rect>
|
||||
</svg>
|
||||
<svg class="button">
|
||||
<text x="50%" y="55%">✗清空表单</text>
|
||||
<rect id="initial"></rect>
|
||||
</svg>
|
||||
<svg class="button">
|
||||
<text x="50%" y="55%">↶撤销操作</text>
|
||||
<rect id="undo"></rect>
|
||||
</svg>
|
||||
<svg class="button">
|
||||
<text x="50%" y="55%">↷重做操作</text>
|
||||
<rect id="redo"></rect>
|
||||
</svg>
|
||||
<svg class="button">
|
||||
<text x="50%" y="55%">⇏调试源</text>
|
||||
<rect id="debug"></rect>
|
||||
</svg>
|
||||
<svg class="button">
|
||||
<text x="50%" y="55%">✓保存源</text>
|
||||
<rect id="accept"></rect>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="outbox">
|
||||
<div class="tabbox">
|
||||
<div class="tabtitle">
|
||||
<div name="编辑源" class="tab1 this">编辑源</div>
|
||||
<div name="调试源" class="tab2">调试源</div>
|
||||
<div name="源列表" class="tab3">源列表</div>
|
||||
<div name="帮助信息" class="tab4">帮助信息</div>
|
||||
</div>
|
||||
<div class="tabbody">
|
||||
<div class="tab1 this">
|
||||
<textarea class="context" id="RuleJsonString"
|
||||
placeholder="这里输出序列化的JSON数据,可直接导入'阅读'APP"></textarea>
|
||||
</div>
|
||||
<div class="tab2">
|
||||
<input type="text" class="inputbox" id="DebugKey" placeholder="输入搜索关键字,默认搜「我的」">
|
||||
<textarea class="context" id="DebugConsole" placeholder="这里用于输出调试信息"></textarea>
|
||||
</div>
|
||||
<div class="tab3">
|
||||
<input type="text" class="inputbox" id="Filter"
|
||||
placeholder="输入筛选关键词(源名称、源URL或源分组)后按回车筛选源">
|
||||
<div class="titlebar">
|
||||
<button id="Import">导入源文件</button>
|
||||
<button id="Export">导出源文件</button>
|
||||
<button id="Delete">删除选中源</button>
|
||||
<button id="ClrAll">清空列表</button>
|
||||
</div>
|
||||
<div class="context" id="RuleList"></div>
|
||||
</div>
|
||||
<div class="tab4">
|
||||
<div class="context link">
|
||||
<a target="_blank" href="https://alanskycn.gitee.io/teachme">源制作教程</a>
|
||||
<a target="_blank"
|
||||
href="https://zhuanlan.zhihu.com/p/29436838">Xpath基础教程</a>
|
||||
<a target="_blank"
|
||||
href="https://zhuanlan.zhihu.com/p/32187820">Xpath高级教程</a>
|
||||
<a target="_blank" href="https://www.w3cschool.cn/regex_rmjc">正则表达式教程</a>
|
||||
<a target="_blank" href="https://regexr.com">正则表达式在线验证工具</a>
|
||||
<div>^$()[]{}.?+*| 这些是Java正则特殊符号,匹配需转义
|
||||
<br>(?s) 前缀表示跨行解析
|
||||
<br>(?m) 前缀表示逐行匹配
|
||||
<br>(?i) 前缀表示忽略大小写
|
||||
</div>
|
||||
<a target="_blank" href="https://www.beta.browxy.com">代码在线运行工具</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="index.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,516 @@
|
||||
// 简化js原生选择器
|
||||
function $(selector) { return document.querySelector(selector); }
|
||||
function $$(selector) { return document.querySelectorAll(selector); }
|
||||
// 读写Hash值(val未赋值时为读取)
|
||||
function hashParam(key, val) {
|
||||
let hashstr = decodeURIComponent(window.location.hash);
|
||||
let regKey = new RegExp(`${key}=([^&]*)`);
|
||||
let getVal = regKey.test(hashstr) ? hashstr.match(regKey)[1] : null;
|
||||
if (val == undefined) return getVal;
|
||||
if (hashstr == '' || hashstr == '#') {
|
||||
window.location.hash = `#${key}=${val}`;
|
||||
}
|
||||
else {
|
||||
if (getVal) window.location.hash = hashstr.replace(getVal, val);
|
||||
else {
|
||||
window.location.hash = hashstr.indexOf(key) > -1 ? hashstr.replace(regKey, `${key}=${val}`) : `${hashstr}&${key}=${val}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 创建源规则容器对象
|
||||
function Container() {
|
||||
let ruleJson = {};
|
||||
let searchJson = {};
|
||||
let exploreJson = {};
|
||||
let bookInfoJson = {};
|
||||
let tocJson = {};
|
||||
let contentJson = {};
|
||||
|
||||
// 基本以及其他
|
||||
$$('.rules .base').forEach(item => ruleJson[item.title] = '');
|
||||
ruleJson.lastUpdateTime = 0;
|
||||
ruleJson.customOrder = 0;
|
||||
ruleJson.weight = 0;
|
||||
ruleJson.enabled = true;
|
||||
ruleJson.enabledExplore = true;
|
||||
|
||||
// 搜索规则
|
||||
$$('.rules .ruleSearch').forEach(item => searchJson[item.title] = '');
|
||||
ruleJson.ruleSearch = searchJson;
|
||||
|
||||
// 发现规则
|
||||
$$('.rules .ruleExplore').forEach(item => exploreJson[item.title] = '');
|
||||
ruleJson.ruleExplore = exploreJson;
|
||||
|
||||
// 详情页规则
|
||||
$$('.rules .ruleBookInfo').forEach(item => bookInfoJson[item.title] = '');
|
||||
ruleJson.ruleBookInfo = bookInfoJson;
|
||||
|
||||
// 目录规则
|
||||
$$('.rules .ruleToc').forEach(item => tocJson[item.title] = '');
|
||||
ruleJson.ruleToc = tocJson;
|
||||
|
||||
// 正文规则
|
||||
$$('.rules .ruleContent').forEach(item => contentJson[item.title] = '');
|
||||
ruleJson.ruleContent = contentJson;
|
||||
|
||||
return ruleJson;
|
||||
}
|
||||
// 选项卡Tab切换事件处理
|
||||
function showTab(tabName) {
|
||||
$$('.tabtitle>*').forEach(node => { node.className = node.className.replace(' this', ''); });
|
||||
$$('.tabbody>*').forEach(node => { node.className = node.className.replace(' this', ''); });
|
||||
$(`.tabbody>.${$(`.tabtitle>*[name=${tabName}]`).className}`).className += ' this';
|
||||
$(`.tabtitle>*[name=${tabName}]`).className += ' this';
|
||||
hashParam('tab', tabName);
|
||||
}
|
||||
// 源列表列表标签构造函数
|
||||
function newRule(rule) {
|
||||
return `<label for="${rule.bookSourceUrl}"><input type="radio" name="rule" id="${rule.bookSourceUrl}"><div>${rule.bookSourceName}<br>${rule.bookSourceUrl}</div></label>`;
|
||||
}
|
||||
// 缓存规则列表
|
||||
var RuleSources = [];
|
||||
if (localStorage.getItem('BookSources')) {
|
||||
RuleSources = JSON.parse(localStorage.getItem('BookSources'));
|
||||
RuleSources.forEach(item => $('#RuleList').innerHTML += newRule(item));
|
||||
}
|
||||
// 页面加载完成事件
|
||||
window.onload = () => {
|
||||
$$('.tabtitle>*').forEach(item => {
|
||||
item.addEventListener('click', () => {
|
||||
showTab(item.innerHTML);
|
||||
});
|
||||
});
|
||||
if (hashParam('tab')) showTab(hashParam('tab'));
|
||||
}
|
||||
// 获取数据
|
||||
function HttpGet(url) {
|
||||
return fetch(hashParam('domain') ? hashParam('domain') + url : url)
|
||||
.then(res => res.json()).catch(err => console.error('Error:', err));
|
||||
}
|
||||
// 提交数据
|
||||
function HttpPost(url, data) {
|
||||
return fetch(hashParam('domain') ? hashParam('domain') + url : url, {
|
||||
body: JSON.stringify(data),
|
||||
method: 'POST',
|
||||
mode: "cors",
|
||||
headers: new Headers({
|
||||
'Content-Type': 'application/json;charset=utf-8'
|
||||
})
|
||||
}).then(res => res.json()).catch(err => console.error('Error:', err));
|
||||
}
|
||||
// 将源表单转化为源对象
|
||||
function rule2json() {
|
||||
let RuleJSON = Container();
|
||||
// 转换base
|
||||
Object.keys(RuleJSON).forEach(key => {
|
||||
if (!key.startsWith("rule")) {
|
||||
RuleJSON[key] = $('#' + key).value;
|
||||
}
|
||||
});
|
||||
|
||||
// 转换搜索规则
|
||||
let searchJson = {};
|
||||
Object.keys(RuleJSON.ruleSearch).forEach(key => {
|
||||
if ($('#' + 'ruleSearch_' + key).value)
|
||||
searchJson[key] = $('#' + 'ruleSearch_' + key).value;
|
||||
});
|
||||
RuleJSON.ruleSearch = searchJson;
|
||||
|
||||
// 转换发现规则
|
||||
let exploreJson = {};
|
||||
Object.keys(RuleJSON.ruleExplore).forEach(key => {
|
||||
if ($('#' + 'ruleExplore_' + key).value)
|
||||
exploreJson[key] = $('#' + 'ruleExplore_' + key).value;
|
||||
});
|
||||
RuleJSON.ruleExplore = exploreJson;
|
||||
|
||||
// 转换详情页规则
|
||||
let bookInfoJson = {};
|
||||
Object.keys(RuleJSON.ruleBookInfo).forEach(key => {
|
||||
if ($('#' + 'ruleBookInfo_' + key).value)
|
||||
bookInfoJson[key] = $('#' + 'ruleBookInfo_' + key).value;
|
||||
});
|
||||
RuleJSON.ruleBookInfo = bookInfoJson;
|
||||
|
||||
// 转换目录规则
|
||||
let tocJson = {};
|
||||
Object.keys(RuleJSON.ruleToc).forEach(key => {
|
||||
if ($('#' + 'ruleToc_' + key).value)
|
||||
tocJson[key] = $('#' + 'ruleToc_' + key).value;
|
||||
});
|
||||
RuleJSON.ruleToc = tocJson;
|
||||
|
||||
// 转换正文规则
|
||||
let contentJson = {};
|
||||
Object.keys(RuleJSON.ruleContent).forEach(key => {
|
||||
if ($('#' + 'ruleContent_' + key).value)
|
||||
contentJson[key] = $('#' + 'ruleContent_' + key).value;
|
||||
});
|
||||
RuleJSON.ruleContent = contentJson;
|
||||
|
||||
RuleJSON.lastUpdateTime = new Date().getTime();
|
||||
RuleJSON.customOrder = RuleJSON.customOrder == '' ? 0 : parseInt(RuleJSON.customOrder);
|
||||
RuleJSON.weight = RuleJSON.weight == '' ? 0 : parseInt(RuleJSON.weight);
|
||||
RuleJSON.bookSourceType == RuleJSON.bookSourceType == '' ? 0 : parseInt(RuleJSON.bookSourceType);
|
||||
RuleJSON.enabled = RuleJSON.enabled == '' || String(RuleJSON.enabled).toLocaleLowerCase().replace(/^\s*|\s*$/g, '') == 'true';
|
||||
RuleJSON.enabledExplore = RuleJSON.enabledExplore == '' || String(RuleJSON.enabledExplore).toLocaleLowerCase().replace(/^\s*|\s*$/g, '') == 'true';
|
||||
return RuleJSON;
|
||||
}
|
||||
// 将源对象填充到源表单
|
||||
function json2rule(RuleEditor) {
|
||||
let RuleJSON = Container();
|
||||
// 转换base
|
||||
Object.keys(RuleJSON).forEach(key => {
|
||||
if (!key.startsWith("rule")) {
|
||||
let val = RuleEditor[key];
|
||||
if (typeof val == "number") {
|
||||
$("#" + key).value = val ? String(val) : '0';
|
||||
}
|
||||
else if (typeof val == "boolean") {
|
||||
$("#" + key).value = val ? String(val) : 'false';
|
||||
}
|
||||
else {
|
||||
$("#" + key).value = val ? String(val) : '';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 转换搜索规则
|
||||
if (RuleEditor.ruleSearch) {
|
||||
let searchJson = RuleEditor.ruleSearch;
|
||||
Object.keys(RuleJSON.ruleSearch).forEach(key => {
|
||||
$('#' + 'ruleSearch_' + key).value = searchJson[key] ? searchJson[key] : '';
|
||||
});
|
||||
}
|
||||
|
||||
// 转换发现规则
|
||||
if (RuleEditor.ruleExplore) {
|
||||
let exploreJson = RuleEditor.ruleExplore;
|
||||
Object.keys(RuleJSON.ruleExplore).forEach(key => {
|
||||
$('#' + 'ruleExplore_' + key).value = exploreJson[key] ? exploreJson[key] : '';
|
||||
});
|
||||
}
|
||||
|
||||
// 转换详情页规则
|
||||
if (RuleEditor.ruleBookInfo) {
|
||||
let bookInfoJson = RuleEditor.ruleBookInfo;
|
||||
Object.keys(RuleJSON.ruleBookInfo).forEach(key => {
|
||||
$('#' + 'ruleBookInfo_' + key).value = bookInfoJson[key] ? bookInfoJson[key] : '';
|
||||
});
|
||||
}
|
||||
|
||||
// 转换目录规则
|
||||
if (RuleEditor.ruleToc) {
|
||||
let tocJson = RuleEditor.ruleToc;
|
||||
Object.keys(RuleJSON.ruleToc).forEach(key => {
|
||||
$('#' + 'ruleToc_' + key).value = tocJson[key] ? tocJson[key] : '';
|
||||
});
|
||||
}
|
||||
|
||||
// 转换正文规则
|
||||
if (RuleEditor.ruleContent) {
|
||||
let contentJson = RuleEditor.ruleContent;
|
||||
Object.keys(RuleJSON.ruleContent).forEach(key => {
|
||||
$('#' + 'ruleContent_' + key).value = contentJson[key] ? contentJson[key] : '';
|
||||
});
|
||||
}
|
||||
}
|
||||
// 记录操作过程
|
||||
var course = { "old": [], "now": {}, "new": [] };
|
||||
if (localStorage.getItem('bookSourceCourse')) {
|
||||
course = JSON.parse(localStorage.getItem('bookSourceCourse'));
|
||||
json2rule(course.now);
|
||||
}
|
||||
else {
|
||||
course.now = rule2json();
|
||||
window.localStorage.setItem('bookSourceCourse', JSON.stringify(course));
|
||||
}
|
||||
function todo() {
|
||||
course.old.push(Object.assign({}, course.now));
|
||||
course.now = rule2json();
|
||||
course.new = [];
|
||||
if (course.old.length > 50) course.old.shift(); // 限制历史记录堆栈大小
|
||||
localStorage.setItem('bookSourceCourse', JSON.stringify(course));
|
||||
}
|
||||
function undo() {
|
||||
course = JSON.parse(localStorage.getItem('bookSourceCourse'));
|
||||
if (course.old.length > 0) {
|
||||
course.new.push(course.now);
|
||||
course.now = course.old.pop();
|
||||
localStorage.setItem('bookSourceCourse', JSON.stringify(course));
|
||||
json2rule(course.now);
|
||||
}
|
||||
}
|
||||
function redo() {
|
||||
course = JSON.parse(localStorage.getItem('bookSourceCourse'));
|
||||
if (course.new.length > 0) {
|
||||
course.old.push(course.now);
|
||||
course.now = course.new.pop();
|
||||
localStorage.setItem('bookSourceCourse', JSON.stringify(course));
|
||||
json2rule(course.now);
|
||||
}
|
||||
}
|
||||
function setRule(editRule) {
|
||||
let checkRule = RuleSources.find(x => x.bookSourceUrl == editRule.bookSourceUrl);
|
||||
if ($(`input[id="${editRule.bookSourceUrl}"]`)) {
|
||||
Object.keys(checkRule).forEach(key => { checkRule[key] = editRule[key]; });
|
||||
$(`input[id="${editRule.bookSourceUrl}"]+*`).innerHTML = `${editRule.bookSourceName}<br>${editRule.bookSourceUrl}`;
|
||||
} else {
|
||||
RuleSources.push(editRule);
|
||||
$('#RuleList').innerHTML += newRule(editRule);
|
||||
}
|
||||
}
|
||||
$$('input').forEach((item) => { item.addEventListener('change', () => { todo() }) });
|
||||
$$('textarea').forEach((item) => { item.addEventListener('change', () => { todo() }) });
|
||||
// 处理按钮点击事件
|
||||
$('.menu').addEventListener('click', e => {
|
||||
let thisNode = e.target;
|
||||
thisNode = thisNode.parentNode.nodeName == 'svg' ? thisNode.parentNode.querySelector('rect') :
|
||||
thisNode.nodeName == 'svg' ? thisNode.querySelector('rect') : null;
|
||||
if (!thisNode) return;
|
||||
if (thisNode.getAttribute('class') == 'busy') return;
|
||||
thisNode.setAttribute('class', 'busy');
|
||||
switch (thisNode.id) {
|
||||
case 'push':
|
||||
$$('#RuleList>label>div').forEach(item => { item.className = ''; });
|
||||
(async () => {
|
||||
await HttpPost(`/saveBookSources`, RuleSources).then(json => {
|
||||
if (json.isSuccess) {
|
||||
let okData = json.data;
|
||||
if (Array.isArray(okData)) {
|
||||
let failMsg = ``;
|
||||
if (RuleSources.length > okData.length) {
|
||||
RuleSources.forEach(item => {
|
||||
if (okData.find(x => x.bookSourceUrl == item.bookSourceUrl)) { }
|
||||
else { $(`#RuleList #${item.bookSourceUrl}+*`).className += 'isError'; }
|
||||
});
|
||||
failMsg = '\n推送失败的源将用红色字体标注!';
|
||||
}
|
||||
alert(`批量推送源到「阅读3.0APP」\n共计: ${RuleSources.length} 条\n成功: ${okData.length} 条\n失败: ${RuleSources.length - okData.length} 条${failMsg}`);
|
||||
}
|
||||
else {
|
||||
alert(`批量推送源到「阅读3.0APP」成功!\n共计: ${RuleSources.length} 条`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert(`批量推送源失败!\nErrorMsg: ${json.errorMsg}`);
|
||||
}
|
||||
}).catch(err => { alert(`批量推送源失败,无法连接到「阅读3.0APP」!\n${err}`); });
|
||||
thisNode.setAttribute('class', '');
|
||||
})();
|
||||
return;
|
||||
case 'pull':
|
||||
showTab('源列表');
|
||||
(async () => {
|
||||
await HttpGet(`/getBookSources`).then(json => {
|
||||
if (json.isSuccess) {
|
||||
$('#RuleList').innerHTML = ''
|
||||
localStorage.setItem('BookSources', JSON.stringify(RuleSources = json.data));
|
||||
RuleSources.forEach(item => {
|
||||
$('#RuleList').innerHTML += newRule(item);
|
||||
});
|
||||
alert(`成功拉取 ${RuleSources.length} 条源`);
|
||||
}
|
||||
else {
|
||||
alert(`批量拉取源失败!\nErrorMsg: ${json.errorMsg}`);
|
||||
}
|
||||
}).catch(err => { alert(`批量拉取源失败,无法连接到「阅读3.0APP」!\n${err}`); });
|
||||
thisNode.setAttribute('class', '');
|
||||
})();
|
||||
return;
|
||||
case 'editor':
|
||||
if ($('#RuleJsonString').value == '') break;
|
||||
try {
|
||||
json2rule(JSON.parse($('#RuleJsonString').value));
|
||||
todo();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
alert(error);
|
||||
}
|
||||
break;
|
||||
case 'conver':
|
||||
showTab('编辑源');
|
||||
$('#RuleJsonString').value = JSON.stringify(rule2json(), null, 4);
|
||||
break;
|
||||
case 'initial':
|
||||
$$('.rules textarea').forEach(item => { item.value = '' });
|
||||
todo();
|
||||
break;
|
||||
case 'undo':
|
||||
undo()
|
||||
break;
|
||||
case 'redo':
|
||||
redo()
|
||||
break;
|
||||
case 'debug':
|
||||
showTab('调试源');
|
||||
let wsOrigin = (hashParam('domain') || location.origin).replace(/^.*?:/, 'ws:').replace(/\d+$/, (port) => (parseInt(port) + 1));
|
||||
let DebugInfos = $('#DebugConsole');
|
||||
function DebugPrint(msg) { DebugInfos.value += `\n${msg}`; DebugInfos.scrollTop = DebugInfos.scrollHeight; }
|
||||
let saveRule = [rule2json()];
|
||||
HttpPost(`/saveBookSources`, saveRule).then(sResult => {
|
||||
if (sResult.isSuccess) {
|
||||
let sKey = DebugKey.value ? DebugKey.value : '我的';
|
||||
$('#DebugConsole').value = `源《${saveRule[0].bookSourceName}》保存成功!使用搜索关键字“${sKey}”开始调试...`;
|
||||
let ws = new WebSocket(`${wsOrigin}/bookSourceDebug`);
|
||||
ws.onopen = () => {
|
||||
ws.send(`{"tag":"${saveRule[0].bookSourceUrl}", "key":"${sKey}"}`);
|
||||
};
|
||||
ws.onmessage = (msg) => {
|
||||
console.log('[调试]', msg);
|
||||
DebugPrint(msg.data);
|
||||
};
|
||||
ws.onerror = (err) => {
|
||||
throw `${err.data}`;
|
||||
}
|
||||
ws.onclose = () => {
|
||||
thisNode.setAttribute('class', '');
|
||||
DebugPrint(`\n调试服务已关闭!`);
|
||||
}
|
||||
} else throw `${sResult.errorMsg}`;
|
||||
}).catch(err => {
|
||||
DebugPrint(`调试过程意外中止,以下是详细错误信息:\n${err}`);
|
||||
thisNode.setAttribute('class', '');
|
||||
});
|
||||
return;
|
||||
case 'accept':
|
||||
(async () => {
|
||||
let saveRule = [rule2json()];
|
||||
await HttpPost(`/saveBookSource`, saveRule[0]).then(json => {
|
||||
alert(json.isSuccess ? `源《${saveRule[0].bookSourceName}》已成功保存到「阅读3.0APP」` : `源《${saveRule[0].bookSourceName}》保存失败!\nErrorMsg: ${json.errorMsg}`);
|
||||
setRule(saveRule[0]);
|
||||
}).catch(err => { alert(`保存源失败,无法连接到「阅读3.0APP」!\n${err}`); });
|
||||
thisNode.setAttribute('class', '');
|
||||
})();
|
||||
return;
|
||||
default:
|
||||
}
|
||||
setTimeout(() => { thisNode.setAttribute('class', ''); }, 500);
|
||||
});
|
||||
$('#DebugKey').addEventListener('keydown', e => {
|
||||
if (e.keyCode == 13) {
|
||||
let clickEvent = document.createEvent('MouseEvents');
|
||||
clickEvent.initEvent("click", true, false);
|
||||
$('#debug').dispatchEvent(clickEvent);
|
||||
}
|
||||
});
|
||||
$('#Filter').addEventListener('keydown', e => {
|
||||
if (e.keyCode == 13) {
|
||||
let cashList = [];
|
||||
$('#RuleList').innerHTML = "";
|
||||
let sKey = Filter.value ? Filter.value : '';
|
||||
if (sKey == '') {
|
||||
cashList = RuleSources;
|
||||
} else {
|
||||
let patt = new RegExp(sKey);
|
||||
RuleSources.forEach(source => {
|
||||
if (patt.test(source.bookSourceUrl) || patt.test(source.bookSourceName) || patt.test(source.bookSourceGroup)) {
|
||||
cashList.push(source);
|
||||
}
|
||||
})
|
||||
}
|
||||
cashList.forEach(source => {
|
||||
$('#RuleList').innerHTML += newRule(source);
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// 列表规则更改事件
|
||||
$('#RuleList').addEventListener('click', e => {
|
||||
let editRule = null;
|
||||
if (e.target && e.target.getAttribute('name') == 'rule') {
|
||||
editRule = rule2json();
|
||||
json2rule(RuleSources.find(x => x.bookSourceUrl == e.target.id));
|
||||
} else return;
|
||||
if (editRule.bookSourceUrl == '') return;
|
||||
if (editRule.bookSourceName == '') editRule.bookSourceName = editRule.bookSourceUrl.replace(/.*?\/\/|\/.*/g, '');
|
||||
setRule(editRule);
|
||||
localStorage.setItem('BookSources', JSON.stringify(RuleSources));
|
||||
});
|
||||
// 处理列表按钮事件
|
||||
$('.tab3>.titlebar').addEventListener('click', e => {
|
||||
let thisNode = e.target;
|
||||
if (thisNode.nodeName != 'BUTTON') return;
|
||||
switch (thisNode.id) {
|
||||
case 'Import':
|
||||
let fileImport = document.createElement('input');
|
||||
fileImport.type = 'file';
|
||||
fileImport.accept = '.json';
|
||||
fileImport.addEventListener('change', () => {
|
||||
let file = fileImport.files[0];
|
||||
let reader = new FileReader();
|
||||
reader.onloadend = function (evt) {
|
||||
if (evt.target.readyState == FileReader.DONE) {
|
||||
let fileText = evt.target.result;
|
||||
try {
|
||||
let fileJson = JSON.parse(fileText);
|
||||
let newSources = [];
|
||||
newSources.push(...fileJson);
|
||||
if (window.confirm(`如何处理导入的源?\n"确定": 覆盖当前列表(不会删除APP源)\n"取消": 插入列表尾部(自动忽略重复源)`)) {
|
||||
localStorage.setItem('BookSources', JSON.stringify(RuleSources = newSources));
|
||||
$('#RuleList').innerHTML = ''
|
||||
RuleSources.forEach(item => {
|
||||
$('#RuleList').innerHTML += newRule(item);
|
||||
});
|
||||
}
|
||||
else {
|
||||
newSources = newSources.filter(item => !JSON.stringify(RuleSources).includes(item.bookSourceUrl));
|
||||
RuleSources.push(...newSources);
|
||||
localStorage.setItem('BookSources', JSON.stringify(RuleSources));
|
||||
newSources.forEach(item => {
|
||||
$('#RuleList').innerHTML += newRule(item);
|
||||
});
|
||||
}
|
||||
alert(`成功导入 ${newSources.length} 条源`);
|
||||
}
|
||||
catch (err) {
|
||||
alert(`导入源文件失败!\n${err}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}, false);
|
||||
fileImport.click();
|
||||
break;
|
||||
case 'Export':
|
||||
let fileExport = document.createElement('a');
|
||||
fileExport.download = `Rules${Date().replace(/.*?\s(\d+)\s(\d+)\s(\d+:\d+:\d+).*/, '$2$1$3').replace(/:/g, '')}.json`;
|
||||
let myBlob = new Blob([JSON.stringify(RuleSources, null, 4)], { type: "application/json" });
|
||||
fileExport.href = window.URL.createObjectURL(myBlob);
|
||||
fileExport.click();
|
||||
break;
|
||||
case 'Delete':
|
||||
let selectRule = $('#RuleList input:checked');
|
||||
if (!selectRule) {
|
||||
alert(`没有源被选中!`);
|
||||
return;
|
||||
}
|
||||
if (confirm(`确定要删除选定源吗?\n(同时删除APP内源)`)) {
|
||||
let selectRuleUrl = selectRule.id;
|
||||
let deleteSources = RuleSources.filter(item => item.bookSourceUrl == selectRuleUrl); // 提取待删除的源
|
||||
let laveSources = RuleSources.filter(item => !(item.bookSourceUrl == selectRuleUrl)); // 提取待留下的源
|
||||
HttpPost(`/deleteBookSources`, deleteSources).then(json => {
|
||||
if (json.isSuccess) {
|
||||
let selectNode = document.getElementById(selectRuleUrl).parentNode;
|
||||
selectNode.parentNode.removeChild(selectNode);
|
||||
localStorage.setItem('BookSources', JSON.stringify(RuleSources = laveSources));
|
||||
if ($('#bookSourceUrl').value == selectRuleUrl) {
|
||||
$$('.rules textarea').forEach(item => { item.value = '' });
|
||||
todo();
|
||||
}
|
||||
console.log(deleteSources);
|
||||
console.log(`以上源已删除!`)
|
||||
}
|
||||
}).catch(err => { alert(`删除源失败,无法连接到「阅读3.0APP」!\n${err}`); });
|
||||
}
|
||||
break;
|
||||
case 'ClrAll':
|
||||
if (confirm(`确定要清空当前源列表吗?\n(不会删除APP内源)`)) {
|
||||
localStorage.setItem('BookSources', JSON.stringify(RuleSources = []));
|
||||
$('#RuleList').innerHTML = ''
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user