Former-commit-id: 1c0fa07b90b199638e40d714d6d25ce935abf593
This commit is contained in:
troyeguo
2021-06-18 22:13:50 +08:00
43 changed files with 308 additions and 460 deletions

View File

@@ -4,8 +4,8 @@
</div>
<div align="center" width="128px" height="128px">
<img src="https://i.loli.net/2020/04/26/wrO8EPokvUQWaf5.png" />
<div align="center" >
<img src="./assets/icons/256x256.png" width="96px" height="96px"/>
</div>
<h1 align="center">
@@ -34,7 +34,7 @@
## Feature
Format support: **epub**, **pdf**, **mobi**, **azw3**, **txt**, **markdown**, **djvu**, **docx**, **rtf**, **cbz**, **cbr**, **cbt**, **fb2**, **html** and **xml**
Format support: **epub**, **pdf**, **mobi**, **azw3**, **txt**, **md**, **djvu**, **docx**, **rtf**, **cbz**, **cbr**, **cbt**, **fb2**, **html** and **xml**
Platform support: **Windows** , **macOS**, **Linux** and **Web**
@@ -52,7 +52,7 @@ Origanize your books and notes with shelf and tag
Adjust font size, font family, line-spacing, paragraph spacing, background color, text color, margins, and brightness
Night mode and Theme color
Night mode and theme color
Text highlight, underline, boldness, italics and shadow

View File

@@ -4,8 +4,8 @@
</div>
<div align="center" width="128px" height="128px">
<img src="https://i.loli.net/2020/04/26/wrO8EPokvUQWaf5.png" />
<div align="center">
<img src="./assets/icons/256x256.png" width="96px" height="96px"/>
</div>
<h1 align="center">
@@ -34,7 +34,7 @@
## 特色
支持阅读 **epub**, **pdf**, **mobi**, **azw3**, **txt**, **markdown**, **djvu**, **docx**, **rtf**, **cbz**, **cbr**, **cbt**, **fb2**, **html****xml** 格式的图书
支持阅读 **epub**, **pdf**, **mobi**, **azw3**, **txt**, **md**, **djvu**, **docx**, **rtf**, **cbz**, **cbr**, **cbt**, **fb2**, **html****xml** 格式的图书
支持 **Windows****macOS****Linux** 和 **网页版**

View File

@@ -4,8 +4,8 @@
</div>
<div align="center" width="128px" height="128px">
<img src="https://i.loli.net/2020/04/26/wrO8EPokvUQWaf5.png" />
<div align="center" >
<img src="./assets/icons/256x256.png" width="96px" height="96px"/>
</div>
<h1 align="center">
@@ -34,7 +34,7 @@
## 特色
支持閱讀 **epub**, **pdf**, **mobi**, **azw3**, **txt**, **markdown**, **djvu**, **docx**, **rtf**, **cbz**, **cbr**, **cbt**, **fb2**, **html****xml** 格式的圖書
支持閱讀 **epub**, **pdf**, **mobi**, **azw3**, **txt**, **md**, **djvu**, **docx**, **rtf**, **cbz**, **cbr**, **cbt**, **fb2**, **html****xml** 格式的圖書
支持 **Windows****macOS****Linux** 和**網頁版**

View File

@@ -7,20 +7,14 @@ branches:
image:
- Visual Studio 2019
- macos
- Ubuntu
- Ubuntu2004
stack: node 10
cache:
- node_modules
- '%APPDATA%\npm-cache'
- '%USERPROFILE%\.electron'
- '%USERPROFILE%\AppData\Local\Yarn\cache'
init:
- git config --global core.autocrlf input
- sh: |
if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" == "Ubuntu" ]
if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" == "Ubuntu2004" ]
then
sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils
sudo apt-get install snapd

14
main.js
View File

@@ -1,4 +1,4 @@
const { app, BrowserWindow, dialog, shell } = require("electron");
const { app, BrowserWindow } = require("electron");
const { ebtMain } = require("electron-baidu-tongji");
let mainWin;
@@ -112,16 +112,10 @@ app.on("ready", () => {
readerWindow = null;
});
});
ipcMain.on("fonts-ready", (event, arg) => {
ipcMain.handle("fonts-ready", async (event, arg) => {
const fontList = require("font-list");
fontList
.getFonts({ disableQuoting: true })
.then((fonts) => {
event.returnValue = fonts;
})
.catch((err) => {
console.log(err);
});
const fonts = await fontList.getFonts({ disableQuoting: true });
return fonts;
});
ipcMain.on("storage-location", (event, arg) => {

View File

@@ -21,7 +21,7 @@
"copy-text-to-clipboard": "^2.2.0",
"electron-baidu-tongji": "^1.0.5",
"electron-is-dev": "^1.1.0",
"font-list": "^1.2.15",
"font-list": "1.2.15",
"fs-extra": "^9.1.0",
"i18next": "^20.2.4",
"iconv-lite": "^0.6.2",

View File

@@ -167,7 +167,8 @@ textarea::-ms-input-placeholder,
.message-box-container {
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.3);
}
::-webkit-scrollbar {
::-webkit-scrollbar,
.tag-list-item {
background-color: white;
}
.add-bookmark-button,

View File

@@ -20,133 +20,12 @@
height: 100%;
width: 100%;
}
.loading-cover {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.logo-container {
width: 200px;
}
.loading-cover img {
width: 80px;
position: relative;
left: 50%;
top: 50%;
margin-left: -40px;
margin-top: -80px;
}
.cover-spinner {
position: absolute;
left: 50%;
top: 50%;
margin-left: -15px;
margin-top: 40px;
}
.sk-chase {
width: 30px;
height: 30px;
animation: sk-chase 2.5s infinite linear both;
z-index: 20;
}
.sk-chase-dot {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
animation: sk-chase-dot 2s infinite ease-in-out both;
}
.sk-chase-dot:before {
content: "";
display: block;
width: 25%;
height: 25%;
border-radius: 100%;
animation: sk-chase-dot-before 2s infinite ease-in-out both;
}
.sk-chase-dot:nth-child(1) {
animation-delay: -1.1s;
}
.sk-chase-dot:nth-child(2) {
animation-delay: -1s;
}
.sk-chase-dot:nth-child(3) {
animation-delay: -0.9s;
}
.sk-chase-dot:nth-child(4) {
animation-delay: -0.8s;
}
.sk-chase-dot:nth-child(5) {
animation-delay: -0.7s;
}
.sk-chase-dot:nth-child(6) {
animation-delay: -0.6s;
}
.sk-chase-dot:nth-child(1):before {
animation-delay: -1.1s;
}
.sk-chase-dot:nth-child(2):before {
animation-delay: -1s;
}
.sk-chase-dot:nth-child(3):before {
animation-delay: -0.9s;
}
.sk-chase-dot:nth-child(4):before {
animation-delay: -0.8s;
}
.sk-chase-dot:nth-child(5):before {
animation-delay: -0.7s;
}
.sk-chase-dot:nth-child(6):before {
animation-delay: -0.6s;
}
@keyframes sk-chase {
100% {
transform: rotate(360deg);
}
}
@keyframes sk-chase-dot {
80%,
100% {
transform: rotate(360deg);
}
}
@keyframes sk-chase-dot-before {
50% {
transform: scale(0.4);
}
100%,
0% {
transform: scale(1);
}
}
</style>
<title>Koodo Reader</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div class="loading-cover">
<img src="./favicon.png" alt="logo" class="loading-logo" />
<div class="cover-spinner">
<div class="sk-chase">
<div class="sk-chase-dot"></div>
<div class="sk-chase-dot"></div>
<div class="sk-chase-dot"></div>
<div class="sk-chase-dot"></div>
<div class="sk-chase-dot"></div>
<div class="sk-chase-dot"></div>
</div>
</div>
</div>
<div id="root"></div>
<script>
const style = document.createElement("link");

View File

@@ -274,7 +274,7 @@
"Collapse sidebar": "收起侧边栏",
"Sync Successfully": "同步成功",
"Show sidebar": "打开侧边栏",
"File Size": "文件大小",
"File size": "文件大小",
"Take effect at next startup": "下次打开图书生效",
"Use the fonts from your local computer": "支持设置电脑中的字体",
"Backup your data with Webdav": "支持 Webdav 备份方式",

View File

@@ -247,7 +247,7 @@
"Turn on night mode": "Turn on night mode",
"Turn on auto update": "Turn on auto update",
"Auto Update relys on Github Release for package hosting, if your internet doesn't have stable connection to Github, we highly recommand you to turn off this option": "Auto Update relys on Github Release for package hosting, if your internet doesn't have stable connection to Github, we highly recommand you to turn off this option",
"File Size": "File Size",
"File size": "File size",
"Take effect at next startup": "Take effect at next startup",
"View Mode": "View Mode",
"Download Desktop Version": "Download Desktop Version",

View File

@@ -265,7 +265,7 @@
"Tips": "Tips",
"Turn on auto update": "Turn on auto update",
"Brightness": "Brightness",
"File Size": "File Size",
"File size": "File size",
"Take effect at next startup": "Take effect at next startup",
"Invert color": "Invert color",

View File

@@ -219,75 +219,75 @@
"Cover Mode": "封面模式",
"Update to": "更新至",
"Update Complete": "更新成功",
"Changelog": "更新日",
"Download": "前往下",
"Theme Color": "选择主题色",
"The deleted books will show up here": "被除的图书会出现在这里,清空回收站才会彻底删除",
"Disable update notification": "停接收更新",
"Use the fonts from your local computer": "使用电脑中的字",
"Backup your data with Webdav": "使用 Webdav 来备份和恢复数据",
"More formats supported": "支持更多的图书格式mobi、azw3、txt",
"Download Desktop Version": "下载客户端",
"Koodo Reader's web version are limited by the browser, for more powerful features, please download the desktop version.": "网页版功能受浏览器限,部分功能仅客户端支持",
"Do you want to backup or restore?": "选择您的操作",
"Where is your data?": "选择资料来源",
"Where to keep your data?": "选择资料存放位置",
"Not supported yet": "不支持",
"Unauthorize": "取消授",
"Unauthorize Successfully": "取消授成功",
"Change storage location": "更改存位置",
"Changelog": "更新日",
"Download": "前往下",
"Theme Color": "選擇主題色",
"The deleted books will show up here": "被除的圖書會出現在這裏,清空回收站才會徹底刪除",
"Disable update notification": "停接收更新",
"Use the fonts from your local computer": "使用電腦中的字",
"Backup your data with Webdav": "使用 Webdav 來備份和恢復數據",
"More formats supported": "支持更多的圖書格式mobi、azw3、txt",
"Download Desktop Version": "下載客戶端",
"Koodo Reader's web version are limited by the browser, for more powerful features, please download the desktop version.": "網頁版功能受瀏覽器限,部分功能僅客戶端支持",
"Do you want to backup or restore?": "選擇您的操作",
"Where is your data?": "選擇資料來源",
"Where to keep your data?": "選擇資料存放位置",
"Not supported yet": "不支持",
"Unauthorize": "取消授",
"Unauthorize Successfully": "取消授成功",
"Change storage location": "更改存位置",
"Change location": "更改",
"Change Successfully": "更改成功",
"Change Failed": "更改失",
"Change Failed": "更改失",
"You successfully update to": "您已成功更新到",
"Built-in font": "默认字体",
"View Mode": "视图模式",
"Letter Spacing": "字距",
"Built-in font": "默認字體",
"View Mode": "視圖模式",
"Letter Spacing": "字距",
"Voice": "音色",
"Unlock": "解",
"Lock": "定",
"Speed": "速",
"Collapse sidebar": "收起侧边栏",
"Show sidebar": "打开侧边栏",
"Unlock": "解",
"Lock": "定",
"Speed": "速",
"Collapse sidebar": "收起側邊欄",
"Show sidebar": "打開側邊欄",
"Sync": "同步",
"Help": "需要助",
"Feedback": "反馈建议",
"Default search engine": "默搜索引擎",
"Github Repo": "Github 仓库",
"Turn on auto update": "开启自动更新",
"Text Align": "文字对齐",
"left": "左对齐",
"justify": "两端对齐",
"right": "右对齐",
"Help": "需要助",
"Feedback": "反饋建議",
"Default search engine": "默搜索引擎",
"Github Repo": "Github 倉庫",
"Turn on auto update": "開啟自動更新",
"Text Align": "文字對齊",
"left": "左對齊",
"justify": "兩端對齊",
"right": "右對齊",
"Understand": "我知道了",
"Sync Successfully": "同步成功",
"Permanently Delete": "永久除",
"Roadmap": "开发计划",
"Paragraph Spacing": "段落距",
"Italic": "斜",
"Text Underline": "下划线",
"Text Shadow": "文字影",
"Speak the text": "朗文字",
"Try refresh or restart": "重启软件后生效",
"Search on the internet": "上搜索",
"Search in the book": "全搜索",
"Remember window's size from last read": "记忆阅读器窗口大小",
"Blue": "色",
"Customize": "自定",
"Red": "色",
"Permanently Delete": "永久除",
"Roadmap": "開發計劃",
"Paragraph Spacing": "段落距",
"Italic": "斜",
"Text Underline": "下劃線",
"Text Shadow": "文字影",
"Speak the text": "朗文字",
"Try refresh or restart": "重啟軟件後生效",
"Search on the internet": "上搜索",
"Search in the book": "全搜索",
"Remember window's size from last read": "記憶閱讀器窗口大小",
"Blue": "色",
"Customize": "自定",
"Red": "色",
"Brightness": "屏幕亮度",
"Green": "绿色",
"Green": "色",
"Purple": "紫色",
"Auto open book in fullscreen": "图书窗口自最大化",
"System Font": "系统字体",
"Auto open book in fullscreen": "圖書窗口自最大化",
"System Font": "系統字體",
"Tips": "提示",
"How sync works": "同步是如何实现的?",
"You need to manually change the storage location to the same sync folder on different computers. When you click the sync button, Koodo Reader will automatically upload or download the data from this folder according the timestamp.": "同步功能需要配合第三方同步盘实现,在不同电脑上把数据存储位置修改同一同步文件,手动点击同步按钮后Koodo把同步文件中的数据更新到件中,从而实现同步。",
"Please choose an empty folder": "请选择空文件",
"Data change detected, whether to update?": "检测到数据变化,是否更新",
"File Size": "文件大小",
"Take effect at next startup": "下次打开图书生效",
"Auto Update relys on Github Release for package hosting, if your internet doesn't have stable connection to Github, we highly recommand you to turn off this option": "自更新功能依Github如果您本地网络无法稳定访问Github不建议开启此功能,开启之后,将不再单独提供更新提醒。",
"Bold Font": "字加粗"
"How sync works": "同步是如何實現的?",
"You need to manually change the storage location to the same sync folder on different computers. When you click the sync button, Koodo Reader will automatically upload or download the data from this folder according the timestamp.": "同步功能需要配合第三方同步盤實現,在不同電腦上把數據存儲位置修改同一同步文件,手動點擊同步按鈕後Koodo把同步文件中的數據更新到件中,從而實現同步。",
"Please choose an empty folder": "請選擇空文件",
"Data change detected, whether to update?": "檢測到數據變化,是否更新",
"File size": "文件大小",
"Take effect at next startup": "下次打開圖書生效",
"Auto Update relys on Github Release for package hosting, if your internet doesn't have stable connection to Github, we highly recommand you to turn off this option": "自更新功能依Github如果您本地網絡無法穩定訪問Github不建議開啟此功能,開啟之後,將不再單獨提供更新提醒。",
"Bold Font": "字加粗"
}

View File

@@ -9,7 +9,7 @@
width: 105px;
height: 137px;
opacity: 1;
margin: 10px 15px 5px 15px;
margin: 15px 15px 5px 15px;
cursor: pointer;
overflow: hidden;
}

View File

@@ -26,12 +26,12 @@ class BookCardItem extends React.Component<BookCardProps, BookCardState> {
};
}
componentDidMount() {
async componentDidMount() {
let filePath = "";
//控制是否自动打开本书
if (isElectron) {
const { ipcRenderer } = window.require("electron");
filePath = ipcRenderer.sendSync("get-file-data");
filePath = await ipcRenderer.sendSync("get-file-data");
}
if (

View File

@@ -157,10 +157,13 @@ class ActionDialog extends React.Component<ActionDialogProps> {
</div>
<div>
<p className="action-dialog-book-publisher">
<Trans>File Size</Trans>:
<Trans>File size</Trans>:
</p>
<p className="action-dialog-book-title">
{parseInt(this.props.currentBook.size / 1024 + "")} Kb
{this.props.currentBook.size
? parseInt(this.props.currentBook.size / 1024 + "") + "Kb"
: // eslint-disable-next-line
"0" + "Kb"}
</p>
</div>
<div>

View File

@@ -14,6 +14,10 @@
z-index: 10;
animation: popup 0.1s ease-in-out 0s 1;
}
.backup-close-icon {
margin-top: 10px;
margin-right: 10px;
}
@keyframes popup {
0% {
opacity: 0;

View File

@@ -275,7 +275,7 @@ class BackupDialog extends React.Component<
this.handleClose();
}}
>
<span className="icon-close "></span>
<span className="icon-close backup-close-icon"></span>
</div>
{this.state.currentStep === 1 ? (

View File

@@ -163,7 +163,7 @@ class SettingDialog extends React.Component<
this.state.isDisplayDark ? "no" : "yes"
);
if (isElectron) {
this.props.handleMessage("Take effect at next startup");
this.props.handleMessage("Try refresh or restart");
this.props.handleMessageBox(true);
} else {
window.location.reload();
@@ -174,7 +174,7 @@ class SettingDialog extends React.Component<
this.setState({ currentThemeIndex: index });
OtherUtil.setReaderConfig("themeColor", name);
if (isElectron) {
this.props.handleMessage("Take effect at next startup");
this.props.handleMessage("Try refresh or restart");
this.props.handleMessageBox(true);
} else {
window.location.reload();

View File

@@ -160,13 +160,10 @@ class PopupMenu extends React.Component<PopupMenuProps, PopupMenuStates> {
renderHighlighters = () => {
let highlighters: any = this.props.notes;
if (!highlighters) return;
if (
!this.props.currentEpub ||
!this.props.currentEpub.rendition.currentLocation
) {
if (!this.props.rendition || !this.props.rendition.currentLocation) {
return;
}
const currentLocation = this.props.currentEpub.rendition.currentLocation();
const currentLocation = this.props.rendition.currentLocation();
if (!currentLocation || !currentLocation.start) return;
let chapterIndex = currentLocation.start.index;
let highlightersByChapter = highlighters.filter(

View File

@@ -8,6 +8,7 @@ import {
readerSettingList,
htmlSettingList,
} from "../../../constants/settingList";
import { isElectron } from "react-device-detect";
class SettingSwitch extends React.Component<
SettingSwitchProps,
@@ -29,6 +30,14 @@ class SettingSwitch extends React.Component<
handleRest = () => {
this.props.renderFunc();
};
_handleRest = () => {
if (isElectron) {
this.props.handleMessage("Take effect at next startup");
this.props.handleMessageBox(true);
} else {
window.location.reload();
}
};
handleBold = () => {
this.setState({ isBold: !this.state.isBold }, () => {
OtherUtil.setReaderConfig("isBold", this.state.isBold ? "yes" : "no");
@@ -83,7 +92,7 @@ class SettingSwitch extends React.Component<
: this.props.handleMessage("Turn On Successfully");
this.props.handleMessageBox(true);
setTimeout(() => {
this.handleRest();
this._handleRest();
}, 500);
};
handleFooter = () => {
@@ -97,7 +106,7 @@ class SettingSwitch extends React.Component<
: this.props.handleMessage("Turn Off Successfully");
this.props.handleMessageBox(true);
setTimeout(() => {
this.handleRest();
this._handleRest();
}, 500);
};
handleHeader = () => {
@@ -111,14 +120,14 @@ class SettingSwitch extends React.Component<
: this.props.handleMessage("Turn Off Successfully");
this.props.handleMessageBox(true);
setTimeout(() => {
this.handleRest();
this._handleRest();
}, 500);
};
render() {
return (
<>
{this.props.currentEpub && <TextToSpeech />}
{this.props.currentEpub.archived && <TextToSpeech />}
{(this.props.currentEpub.rendition
? readerSettingList
: htmlSettingList

View File

@@ -25,7 +25,7 @@ class SliderList extends React.Component<SliderListProps, SliderListState> {
};
}
handleRest = () => {
if (this.props.mode === "scale") {
if (this.props.mode === "scale" || this.props.mode === "margin") {
if (isElectron) {
this.props.handleMessage("Take effect at next startup");
this.props.handleMessageBox(true);

View File

@@ -103,10 +103,14 @@ class TextToSpeech extends React.Component<
msg.voice = window.speechSynthesis.getVoices()[voiceIndex];
msg.rate = speed;
window.speechSynthesis.speak(msg);
msg.onerror = (err) => {
console.log(err);
};
msg.onend = (event) => {
if (!(this.state.isAudioOn && this.props.isReading)) {
return;
}
this.props.currentEpub.rendition.next().then(() => {
this.handleAudio();
});

View File

@@ -19,11 +19,11 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
constructor(props: ReaderProps) {
super(props);
this.state = {
isOpenSettingPanel:
isOpenRightPanel:
OtherUtil.getReaderConfig("isSettingLocked") === "yes" ? true : false,
isOpenOperationPanel: false,
isOpenProgressPanel: false,
isOpenNavPanel:
isOpenTopPanel: false,
isOpenBottomPanel: false,
isOpenLeftPanel:
OtherUtil.getReaderConfig("isNavLocked") === "yes" ? true : false,
isMessage: false,
rendition: null,
@@ -64,9 +64,10 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
handleRenderBook = () => {
let page = document.querySelector("#page-area");
let epub = this.props.currentEpub;
if (page?.innerHTML) {
page.innerHTML = "";
if (page!.getElementsByTagName("*").length > 0) {
page!.innerHTML = "";
}
this.setState({ rendition: null }, () => {
(window as any).rangy.init(); // 初始化
this.rendition = epub.renderTo(page, {
@@ -84,38 +85,52 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
this.tickTimer = setInterval(() => {
let time = this.state.time;
time += 1;
let page = document.querySelector("#page-area");
//解决快速翻页过程中图书消失的bug
let renderedBook = document.querySelector(".epub-view");
if (renderedBook && !renderedBook.innerHTML) {
if (
(renderedBook &&
!renderedBook.innerHTML &&
this.state.readerMode !== "continuous") ||
page!.getElementsByClassName("epub-container").length > 1
) {
this.handleRenderBook();
}
this.setState({ time });
this.handleRecord();
}, 1000);
});
};
handleRecord() {
OtherUtil.setReaderConfig("isFullScreen", "no");
OtherUtil.setReaderConfig("windowWidth", document.body.clientWidth + "");
OtherUtil.setReaderConfig("windowHeight", document.body.clientHeight + "");
OtherUtil.setReaderConfig("windowX", window.screenX + "");
OtherUtil.setReaderConfig("windowY", window.screenY + "");
}
//进入阅读器
handleEnterReader = (position: string) => {
//控制上下左右的菜单的显示
switch (position) {
case "right":
this.setState({
isOpenSettingPanel: this.state.isOpenSettingPanel ? false : true,
isOpenRightPanel: this.state.isOpenRightPanel ? false : true,
});
break;
case "left":
this.setState({
isOpenNavPanel: this.state.isOpenNavPanel ? false : true,
isOpenLeftPanel: this.state.isOpenLeftPanel ? false : true,
});
break;
case "top":
this.setState({
isOpenOperationPanel: this.state.isOpenOperationPanel ? false : true,
isOpenTopPanel: this.state.isOpenTopPanel ? false : true,
});
break;
case "bottom":
this.setState({
isOpenProgressPanel: this.state.isOpenProgressPanel ? false : true,
isOpenBottomPanel: this.state.isOpenBottomPanel ? false : true,
});
break;
default:
@@ -130,7 +145,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
if (OtherUtil.getReaderConfig("isSettingLocked") === "yes") {
break;
} else {
this.setState({ isOpenSettingPanel: false });
this.setState({ isOpenRightPanel: false });
break;
}
@@ -138,14 +153,14 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
if (OtherUtil.getReaderConfig("isNavLocked") === "yes") {
break;
} else {
this.setState({ isOpenNavPanel: false });
this.setState({ isOpenLeftPanel: false });
break;
}
case "top":
this.setState({ isOpenOperationPanel: false });
this.setState({ isOpenTopPanel: false });
break;
case "bottom":
this.setState({ isOpenProgressPanel: false });
this.setState({ isOpenBottomPanel: false });
break;
default:
break;
@@ -163,10 +178,10 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
handleLeaveReader: this.handleLeaveReader,
handleEnterReader: this.handleEnterReader,
isShow:
this.state.isOpenNavPanel ||
this.state.isOpenOperationPanel ||
this.state.isOpenProgressPanel ||
this.state.isOpenSettingPanel,
this.state.isOpenLeftPanel ||
this.state.isOpenTopPanel ||
this.state.isOpenBottomPanel ||
this.state.isOpenRightPanel,
};
return (
<div
@@ -210,7 +225,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
<div
className="left-panel"
onMouseEnter={() => {
if (this.state.isTouch || this.state.isOpenNavPanel) {
if (this.state.isTouch || this.state.isOpenLeftPanel) {
return;
}
this.handleEnterReader("left");
@@ -222,7 +237,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
<div
className="right-panel"
onMouseEnter={() => {
if (this.state.isTouch || this.state.isOpenSettingPanel) {
if (this.state.isTouch || this.state.isOpenRightPanel) {
return;
}
this.handleEnterReader("right");
@@ -234,7 +249,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
<div
className="top-panel"
onMouseEnter={() => {
if (this.state.isTouch || this.state.isOpenOperationPanel) {
if (this.state.isTouch || this.state.isOpenTopPanel) {
return;
}
this.handleEnterReader("top");
@@ -246,7 +261,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
<div
className="bottom-panel"
onMouseEnter={() => {
if (this.state.isTouch || this.state.isOpenProgressPanel) {
if (this.state.isTouch || this.state.isOpenBottomPanel) {
return;
}
this.handleEnterReader("bottom");
@@ -265,7 +280,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
this.handleLeaveReader("right");
}}
style={
this.state.isOpenSettingPanel
this.state.isOpenRightPanel
? {}
: {
transform: "translateX(309px)",
@@ -280,7 +295,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
this.handleLeaveReader("left");
}}
style={
this.state.isOpenNavPanel
this.state.isOpenLeftPanel
? {}
: {
transform: "translateX(-309px)",
@@ -295,7 +310,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
this.handleLeaveReader("bottom");
}}
style={
this.state.isOpenProgressPanel
this.state.isOpenBottomPanel
? {}
: {
transform: "translateY(110px)",
@@ -310,7 +325,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
this.handleLeaveReader("top");
}}
style={
this.state.isOpenOperationPanel
this.state.isOpenTopPanel
? {}
: {
transform: "translateY(-110px)",

View File

@@ -13,10 +13,10 @@ export interface ReaderProps {
}
export interface ReaderState {
isOpenSettingPanel: boolean;
isOpenOperationPanel: boolean;
isOpenProgressPanel: boolean;
isOpenNavPanel: boolean;
isOpenRightPanel: boolean;
isOpenTopPanel: boolean;
isOpenBottomPanel: boolean;
isOpenLeftPanel: boolean;
isMessage: boolean;
isTouch: boolean;
readerMode: string;

View File

@@ -24,7 +24,6 @@ class Header extends React.Component<HeaderProps, HeaderState> {
};
}
componentDidMount() {
console.log(localStorage.getItem("lastSyncTime"), "localStorage1");
if (isElectron) {
const fs = window.require("fs");
const path = window.require("path");
@@ -80,7 +79,6 @@ class Header extends React.Component<HeaderProps, HeaderState> {
return;
}
const readerConfig = JSON.parse(data);
console.log(localStorage.getItem("lastSyncTime"), "localStorage2");
if (
localStorage.getItem("lastSyncTime") &&
parseInt(readerConfig.lastSyncTime) >
@@ -89,20 +87,6 @@ class Header extends React.Component<HeaderProps, HeaderState> {
this.setState({ isdataChange: true });
}
});
// try {
// const readerConfig = JSON.parse(
// fs.readFileSync(sourcePath, { encoding: "utf8", flag: "r" })
// );
// if (
// localStorage.getItem("lastSyncTime") &&
// parseInt(readerConfig.lastSyncTime) >
// parseInt(localStorage.getItem("lastSyncTime")!)
// ) {
// this.setState({ isdataChange: true });
// }
// } catch (error) {
// throw error;
// }
}
window.addEventListener("resize", () => {
@@ -113,15 +97,12 @@ class Header extends React.Component<HeaderProps, HeaderState> {
syncFromLocation = async () => {
const fs = window.require("fs");
const path = window.require("path");
const { zip } = window.require("zip-a-folder");
let storageLocation = localStorage.getItem("storageLocation")
? localStorage.getItem("storageLocation")
: window
.require("electron")
.ipcRenderer.sendSync("storage-location", "ping");
let sourcePath = path.join(storageLocation, "config");
let outPath = path.join(storageLocation, "config.zip");
await zip(sourcePath, outPath);
var data = fs.readFileSync(outPath);
@@ -130,22 +111,36 @@ class Header extends React.Component<HeaderProps, HeaderState> {
lastModified: new Date().getTime(),
type: blobTemp.type,
});
console.log(fileTemp);
RestoreUtil.restore(
fileTemp,
() => {
BackupUtil.backup(
this.props.books,
this.props.notes,
this.props.bookmarks,
() => {
this.props.handleMessage("Sync Successfully");
this.props.handleMessageBox(true);
this.setState({ isdataChange: false });
},
5,
() => {}
this.setState({ isdataChange: false });
//Check for data update
let storageLocation = localStorage.getItem("storageLocation")
? localStorage.getItem("storageLocation")
: window
.require("electron")
.ipcRenderer.sendSync("storage-location", "ping");
let sourcePath = path.join(
storageLocation,
"config",
"readerConfig.json"
);
fs.readFile(sourcePath, "utf8", (err, data) => {
if (err) {
console.error(err);
return;
}
const readerConfig = JSON.parse(data);
if (
localStorage.getItem("lastSyncTime") &&
readerConfig.lastSyncTime
) {
localStorage.setItem("lastSyncTime", readerConfig.lastSyncTime);
}
});
},
true
);
@@ -185,11 +180,6 @@ class Header extends React.Component<HeaderProps, HeaderState> {
}
const readerConfig = JSON.parse(data);
console.log(
localStorage.getItem("lastSyncTime"),
readerConfig.lastSyncTime,
"localStorage3"
);
if (
readerConfig &&
localStorage.getItem("lastSyncTime") &&
@@ -212,29 +202,6 @@ class Header extends React.Component<HeaderProps, HeaderState> {
);
}
});
//如果同步文件夹的记录较新就从同步文件夹同步数据到Koodo
// if (
// readerConfig &&
// localStorage.getItem("lastSyncTime") &&
// parseInt(readerConfig.lastSyncTime) >
// parseInt(localStorage.getItem("lastSyncTime")!)
// ) {
// this.syncFromLocation();
// } else {
// //否则就把Koodo中数据同步到同步文件夹
// BackupUtil.backup(
// this.props.books,
// this.props.notes,
// this.props.bookmarks,
// () => {
// this.props.handleMessage("Sync Successfully");
// this.props.handleMessageBox(true);
// },
// 5,
// () => {}
// );
// }
};
render() {

View File

@@ -11,12 +11,13 @@ import marked from "marked";
import iconv from "iconv-lite";
import chardet from "chardet";
import rtfToHTML from "@iarna/rtf-to-html";
import { xmlBookTagFilter, xmlBookToObj } from "../../utils/xmlUtil";
import { xmlBookTagFilter, xmlBookToObj, txtToHtml } from "../../utils/xmlUtil";
import HtmlParser from "../../utils/htmlParser";
import OtherUtil from "../../utils/otherUtil";
import RecordLocation from "../../utils/readUtils/recordLocation";
import { mimetype } from "../../constants/mimetype";
import styleUtil from "../../utils/readUtils/styleUtil";
import { setInterval } from "timers";
declare var window: any;
@@ -60,33 +61,29 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
});
});
this.props.handleRenderFunc(this.handleRenderHtml);
window.frames[0].document.addEventListener("wheel", (event) => {
RecordLocation.recordScrollHeight(
key,
document.body.clientWidth,
document.body.clientHeight,
window.frames[0].document.scrollingElement!.scrollTop,
window.frames[0].document.scrollingElement!.scrollHeight
);
});
setInterval(() => {
this.handleRecord();
}, 1000);
window.frames[0].document.addEventListener("click", (event) => {
this.props.handleLeaveReader("left");
this.props.handleLeaveReader("right");
this.props.handleLeaveReader("top");
this.props.handleLeaveReader("bottom");
});
window.onbeforeunload = () => {
this.handleExit();
};
}
handleExit() {
this.props.handleReadingState(false);
handleRecord() {
OtherUtil.setReaderConfig("windowWidth", document.body.clientWidth + "");
OtherUtil.setReaderConfig("windowHeight", document.body.clientHeight + "");
OtherUtil.setReaderConfig("windowX", window.screenX + "");
OtherUtil.setReaderConfig("windowY", window.screenY + "");
RecordLocation.recordScrollHeight(
this.state.key,
document.body.clientWidth,
document.body.clientHeight,
window.frames[0].document.scrollingElement!.scrollTop,
window.frames[0].document.scrollingElement!.scrollHeight
);
}
handleRest = (docStr: string) => {
let htmlParser = new HtmlParser(
@@ -119,7 +116,7 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
Buffer.from(result),
chardet.detect(Buffer.from(result)) as string
);
this.handleRest(`<p>${text}</p>`);
this.handleRest(txtToHtml(text));
};
handleMD = (result: ArrayBuffer) => {
var blob = new Blob([result], { type: "text/plain" });

View File

@@ -3,8 +3,9 @@
top: 115px;
left: 190px;
width: calc(100% - 190px);
height: calc(100% - 110px);
height: calc(100% - 115px);
overflow: visible;
margin-bottom: 5px;
}
.book-list-container {
width: 100%;

View File

@@ -40,11 +40,7 @@ class ContentList extends React.Component<ContentListProps, ContentListState> {
this.props.currentEpub.rendition.display(href);
} else {
let id = href.substr(1);
console.log(
id,
window.frames[0].document,
window.frames[0].document.getElementById(id)
);
var top = window.frames[0].document.getElementById(id)?.offsetTop;
if (!top) return;
window.frames[0].scrollTo(0, top);

View File

@@ -238,7 +238,7 @@ class NavigationPanel extends React.Component<
&nbsp;
<Trans>Minute</Trans>
</span>
{this.props.currentEpub && (
{this.props.currentEpub.archived && (
<div className="navigation-search-box">
<SearchBox {...searchProps} />
</div>

View File

@@ -57,7 +57,7 @@ class SettingPanel extends React.Component<
<Trans>Reading Option</Trans>
</div>
<div className="setting-panel">
{this.props.currentEpub && <ModeControl />}
{this.props.currentEpub.archived && <ModeControl />}
<ThemeList />
<SliderList
{...{
@@ -70,7 +70,7 @@ class SettingPanel extends React.Component<
title: "Font Size",
}}
/>
{this.props.currentEpub && (
{this.props.currentEpub.archived && (
<SliderList
{...{
maxValue: 80,
@@ -94,7 +94,7 @@ class SettingPanel extends React.Component<
title: "Letter Spacing",
}}
/>
{this.props.currentEpub && (
{this.props.currentEpub.archived && (
<SliderList
{...{
maxValue: 60,
@@ -107,7 +107,8 @@ class SettingPanel extends React.Component<
}}
/>
)}
{this.state.readerMode && this.state.readerMode !== "double" ? (
{(this.state.readerMode && this.state.readerMode !== "double") ||
!this.props.currentEpub.archived ? (
<SliderList
{...{
maxValue: 3,

View File

@@ -35,7 +35,16 @@ if (
navigator.appVersion.indexOf("NT 6.0") === -1
) {
const { ipcRenderer } = window.require("electron");
dropdownList[0].option = ipcRenderer.sendSync("fonts-ready", "ping");
dropdownList[0].option.push("Built-in font");
ipcRenderer.invoke("fonts-ready", "ping").then((result) => {
dropdownList[0].option = result;
dropdownList[0].option.push("Built-in font");
});
}
StyleUtil.applyTheme();
ReactDOM.render(
<Provider store={store}>
<Router />
</Provider>,
document.getElementById("root")
);

View File

@@ -31,6 +31,9 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
RecentBooks.setRecent(key);
});
});
document
.querySelector(".ebook-viewer")
?.setAttribute("style", "height:100%");
window.onbeforeunload = () => {
this.handleExit();
};

View File

@@ -17,11 +17,11 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
constructor(props: ReaderProps) {
super(props);
this.state = {
isOpenSettingPanel:
isOpenRightPanel:
OtherUtil.getReaderConfig("isSettingLocked") === "yes" ? true : false,
isOpenOperationPanel: false,
isOpenProgressPanel: false,
isOpenNavPanel:
isOpenTopPanel: false,
isOpenBottomPanel: false,
isOpenLeftPanel:
OtherUtil.getReaderConfig("isNavLocked") === "yes" ? true : false,
isMessage: false,
rendition: null,
@@ -53,22 +53,22 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
switch (position) {
case "right":
this.setState({
isOpenSettingPanel: this.state.isOpenSettingPanel ? false : true,
isOpenRightPanel: this.state.isOpenRightPanel ? false : true,
});
break;
case "left":
this.setState({
isOpenNavPanel: this.state.isOpenNavPanel ? false : true,
isOpenLeftPanel: this.state.isOpenLeftPanel ? false : true,
});
break;
case "top":
this.setState({
isOpenOperationPanel: this.state.isOpenOperationPanel ? false : true,
isOpenTopPanel: this.state.isOpenTopPanel ? false : true,
});
break;
case "bottom":
this.setState({
isOpenProgressPanel: this.state.isOpenProgressPanel ? false : true,
isOpenBottomPanel: this.state.isOpenBottomPanel ? false : true,
});
break;
default:
@@ -83,7 +83,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
if (OtherUtil.getReaderConfig("isSettingLocked") === "yes") {
break;
} else {
this.setState({ isOpenSettingPanel: false });
this.setState({ isOpenRightPanel: false });
break;
}
@@ -91,14 +91,14 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
if (OtherUtil.getReaderConfig("isNavLocked") === "yes") {
break;
} else {
this.setState({ isOpenNavPanel: false });
this.setState({ isOpenLeftPanel: false });
break;
}
case "top":
this.setState({ isOpenOperationPanel: false });
this.setState({ isOpenTopPanel: false });
break;
case "bottom":
this.setState({ isOpenProgressPanel: false });
this.setState({ isOpenBottomPanel: false });
break;
default:
break;
@@ -116,29 +116,13 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
handleLeaveReader: this.handleLeaveReader,
handleEnterReader: this.handleEnterReader,
isShow:
this.state.isOpenNavPanel ||
this.state.isOpenOperationPanel ||
this.state.isOpenProgressPanel ||
this.state.isOpenSettingPanel,
this.state.isOpenLeftPanel ||
this.state.isOpenTopPanel ||
this.state.isOpenBottomPanel ||
this.state.isOpenRightPanel,
};
return (
<div className="viewer">
<div
className="previous-chapter-single-container"
onClick={() => {
this.prevPage();
}}
>
<span className="icon-dropdown previous-chapter-single"></span>
</div>
<div
className="next-chapter-single-container"
onClick={() => {
this.nextPage();
}}
>
<span className="icon-dropdown next-chapter-single"></span>
</div>
<div
className="reader-setting-icon-container"
onClick={() => {
@@ -154,7 +138,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
<div
className="left-panel"
onMouseEnter={() => {
if (this.state.isTouch || this.state.isOpenNavPanel) {
if (this.state.isTouch || this.state.isOpenLeftPanel) {
return;
}
this.handleEnterReader("left");
@@ -166,7 +150,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
<div
className="right-panel"
onMouseEnter={() => {
if (this.state.isTouch || this.state.isOpenSettingPanel) {
if (this.state.isTouch || this.state.isOpenRightPanel) {
return;
}
this.handleEnterReader("right");
@@ -178,7 +162,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
<div
className="top-panel"
onMouseEnter={() => {
if (this.state.isTouch || this.state.isOpenOperationPanel) {
if (this.state.isTouch || this.state.isOpenTopPanel) {
return;
}
this.handleEnterReader("top");
@@ -187,18 +171,20 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
this.handleEnterReader("top");
}}
></div>
<div
className="bottom-panel"
onMouseEnter={() => {
if (this.state.isTouch || this.state.isOpenProgressPanel) {
return;
}
this.handleEnterReader("bottom");
}}
onClick={() => {
this.handleEnterReader("bottom");
}}
></div>
{this.props.currentEpub.archived && (
<div
className="bottom-panel"
onMouseEnter={() => {
if (this.state.isTouch || this.state.isOpenBottomPanel) {
return;
}
this.handleEnterReader("bottom");
}}
onClick={() => {
this.handleEnterReader("bottom");
}}
></div>
)}
<Viewer {...renditionProps} />
<div
className="setting-panel-container"
@@ -206,7 +192,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
this.handleLeaveReader("right");
}}
style={
this.state.isOpenSettingPanel
this.state.isOpenRightPanel
? {}
: {
transform: "translateX(309px)",
@@ -221,7 +207,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
this.handleLeaveReader("left");
}}
style={
this.state.isOpenNavPanel
this.state.isOpenLeftPanel
? {}
: {
transform: "translateX(-309px)",
@@ -230,30 +216,30 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
>
<NavigationPanel {...{ time: this.state.time }} />
</div>
<div
className="progress-panel-container"
onMouseLeave={(event) => {
this.handleLeaveReader("bottom");
}}
style={
this.state.isOpenProgressPanel
? {}
: {
transform: "translateY(110px)",
}
}
>
{this.props.currentEpub.rendition && (
{this.props.currentEpub.archived && (
<div
className="progress-panel-container"
onMouseLeave={(event) => {
this.handleLeaveReader("bottom");
}}
style={
this.state.isOpenBottomPanel
? {}
: {
transform: "translateY(110px)",
}
}
>
<ProgressPanel {...{ time: this.state.time }} />
)}
</div>
</div>
)}
<div
className="operation-panel-container"
onMouseLeave={(event) => {
this.handleLeaveReader("top");
}}
style={
this.state.isOpenOperationPanel
this.state.isOpenTopPanel
? {}
: {
transform: "translateY(-110px)",

View File

@@ -14,10 +14,10 @@ export interface ReaderProps {
}
export interface ReaderState {
isOpenSettingPanel: boolean;
isOpenOperationPanel: boolean;
isOpenProgressPanel: boolean;
isOpenNavPanel: boolean;
isOpenRightPanel: boolean;
isOpenTopPanel: boolean;
isOpenBottomPanel: boolean;
isOpenLeftPanel: boolean;
isMessage: boolean;
isTouch: boolean;
readerMode: string;

View File

@@ -1,4 +1,4 @@
const isTitle = (line: string) => {
export const isTitle = (line: string) => {
return (
line.length < 30 &&
line.indexOf("[") === -1 &&

View File

@@ -16,8 +16,8 @@ class HtmlParser {
let random = Math.floor(Math.random() * 900) + 100;
this.contentTitleList.push({
label: this.contentList[i].innerText,
id: this.contentList[i].innerText.replaceAll(" ", "_") + random,
href: "#" + this.contentList[i].innerText.replaceAll(" ", "_") + random,
id: this.contentList[i].innerText.replace(/ /g, "_") + random,
href: "#" + this.contentList[i].innerText.replace(/ /g, "_") + random,
subitems: [],
});
}

View File

@@ -66,7 +66,7 @@ class styleUtil {
let colors = ["#FBF1D1", "#EFEEB0", "#CAEFC9", "#76BEE9"];
let lines = ["#FF0000", "#000080", "#0000FF", "#2EFF2E"];
return `::selection{background:#f3a6a68c}::-moz-selection{background:#f3a6a68c}[class*=color-]:hover{cursor:pointer;background-image:linear-gradient(0,rgba(0,0,0,.075),rgba(0,0,0,.075))}.color-0{background-color:${colors[0]}}.color-1{background-color:${colors[1]}}.color-2{background-color:${colors[2]}}.color-3{background-color:${colors[3]}}.line-0{border-bottom:2px solid ${lines[0]}}.line-1{border-bottom:2px solid ${lines[1]}}.line-2{border-bottom:2px solid ${lines[2]}}.line-3{border-bottom:2px solid ${lines[3]}}}`;
return `::selection{background:#f3a6a68c}::-moz-selection{background:#f3a6a68c}[class*=color-]:hover{cursor:pointer;background-image:linear-gradient(0,rgba(0,0,0,.075),rgba(0,0,0,.075))}.color-0{background-color:${colors[0]}}.color-1{background-color:${colors[1]}}.color-2{background-color:${colors[2]}}.color-3{background-color:${colors[3]}}.line-0{border-bottom:2px solid ${lines[0]}}.line-1{border-bottom:2px solid ${lines[1]}}.line-2{border-bottom:2px solid ${lines[2]}}.line-3{border-bottom:2px solid ${lines[3]}}}::-webkit-scrollbar{width: 5px;height: 0.5rem;}::-webkit-scrollbar-track{border-radius: 0;}::-webkit-scrollbar-thumb{border-radius: 0;transition: all 0.2s;border-radius: 0.5rem;opacity: 0.5;}img{max-width:100%}`;
}
static getCustomCss(isJSON: boolean = true) {
if (isJSON) {

View File

@@ -40,7 +40,6 @@ class BackupUtil {
}
} else {
let timestamp = new Date().getTime().toString();
console.log(timestamp, "timestamp");
OtherUtil.setReaderConfig("lastSyncTime", timestamp);
localStorage.setItem("lastSyncTime", timestamp);

View File

@@ -62,24 +62,6 @@ export const moveData = (
if (driveIndex === 5) {
handleFinish();
}
// try {
// const fs = window.require("fs-extra");
// fs.remove(path.join(dirPath, file.name), async (err) => {
// if (err) console.log(err);
// if (driveIndex === 4) {
// let deleteBooks = books.map((item) => {
// return localforage.removeItem(item.key);
// });
// await Promise.all(deleteBooks);
// }
// if (driveIndex === 5) {
// handleFinish();
// }
// });
// } catch (e) {
// console.error(e, "移动失败");
// }
};
};

View File

@@ -50,7 +50,7 @@ class DropboxUitl {
return false;
}
static DownloadFile(
handleFinish: (mobileData: string) => void,
handleFinish: () => void,
showMessage: (message: string) => void,
isSync: boolean = false
) {

View File

@@ -4,11 +4,7 @@ import BookUtil from "../bookUtil";
let JSZip = (window as any).JSZip;
class RestoreUtil {
static restore = (
file: any,
handleFinish: (mobileData) => void,
isSync = false
) => {
static restore = (file: any, handleFinish: () => void, isSync = false) => {
let configArr = [
"notes",
"books",
@@ -27,25 +23,21 @@ class RestoreUtil {
"recordLocation",
];
let zip = new JSZip();
let mobileObject: Object = {};
// more files !
configArr.forEach((item) => {
zip
.loadAsync(file)
.then((content: any) => {
// you now have every files contained in the loaded zip
return content.files[
isSync ? `${item}.json` : `config/${item}.json`
].async("text"); // a promise of "Hello World\n"
return content.files[`config/${item}.json`].async("text"); // a promise of "Hello World\n"
})
.then((text: any) => {
if (text) {
if (item === "notes" || item === "books" || item === "bookmarks") {
localforage.setItem(item, JSON.parse(text));
mobileObject[item] = text;
} else {
localStorage.setItem(item, text);
mobileObject[item] = text;
}
}
})
@@ -89,7 +81,7 @@ class RestoreUtil {
});
});
setTimeout(() => {
handleFinish(JSON.stringify(mobileObject));
handleFinish();
}, 1000);
};
}

View File

@@ -1,4 +1,5 @@
import xml2js from "xml2js";
import { isTitle } from "./generateEpub";
export const xmlBookToObj = (xml) => {
var objBook: any = {};
var informBook;
@@ -50,3 +51,17 @@ export const xmlBookTagFilter = (bookString) => {
return bookBody;
};
export const txtToHtml = (text: string) => {
const lines = text.split("\n");
let html: string = "";
for (let item of lines) {
if (item.trim()) {
if (isTitle(item.trim())) {
html += `<h1>${item}</h1>`;
} else {
html += `<p>${item}</p>`;
}
}
}
return html;
};

View File

@@ -6525,7 +6525,7 @@ follow-redirects@^1.10.0:
resolved "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.13.1.tgz?cache=0&sync_timestamp=1607916846877&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7"
integrity sha1-X2m4Ezds7k/QR0o6uoNd8Eq3Y7c=
font-list@^1.2.15:
font-list@1.2.15:
version "1.2.15"
resolved "https://registry.nlark.com/font-list/download/font-list-1.2.15.tgz#dc5fa7038fa77aa60ed7faf66522aed872d9f395"
integrity sha1-3F+nA4+neqYO1/r2ZSKu2HLZ85U=