From 5aa89213361357926eec63f51f76a01d3ddb36ab Mon Sep 17 00:00:00 2001 From: cdhigh Date: Sun, 2 Jun 2024 21:48:13 -0300 Subject: [PATCH] improve online reading --- application/static/base.js | 13 +- application/static/reader.css | 41 ++ application/static/reader.js | 93 +++- application/templates/adv_base.html | 9 + application/templates/adv_reader.html | 85 +++ application/templates/base.html | 4 - application/templates/reader.html | 23 +- application/templates/reader_404.html | 3 +- application/templates/settings.html | 2 +- application/translations/messages.pot | 484 +++++++++-------- .../tr_TR/LC_MESSAGES/messages.mo | Bin 28610 -> 28775 bytes .../tr_TR/LC_MESSAGES/messages.po | 484 +++++++++-------- .../translations/zh/LC_MESSAGES/messages.mo | Bin 26829 -> 26979 bytes .../translations/zh/LC_MESSAGES/messages.po | 486 ++++++++++-------- application/view/adv.py | 62 ++- application/view/reader.py | 59 ++- docs/Chinese/README.md | 1 + docs/Chinese/changelog.md | 4 +- docs/Chinese/extension.md | 2 +- docs/Chinese/faq.md | 19 +- docs/Chinese/reader.md | 40 ++ docs/English/README.md | 1 + docs/English/changelog_en.md | 4 +- docs/English/extension.md | 2 +- docs/English/faq.md | 22 +- docs/English/reader.md | 50 ++ 26 files changed, 1248 insertions(+), 745 deletions(-) create mode 100644 application/templates/adv_reader.html create mode 100644 docs/Chinese/reader.md create mode 100644 docs/English/reader.md diff --git a/application/static/base.js b/application/static/base.js index 50d4324e..53d9f0a2 100644 --- a/application/static/base.js +++ b/application/static/base.js @@ -1318,7 +1318,8 @@ function startUploadCoversToServer(url) { } ///[end] adv_uploadcover.html ///[start] book_translator.html -//根据当前可选的翻译引擎列表 g_trans_engines 填充下拉框,currEngineName为Recipe的当前配置 +//根据当前可选的翻译引擎列表 g_trans_engines 填充下拉框, +//currEngineName: Recipe的当前配置 function PopulateTranslatorFields(currEngineName) { var engineSel = $('#translator_engine'); for (var name in g_trans_engines) { @@ -1400,6 +1401,16 @@ function TestTranslator(recipeId) { divDst.val(resp.text); }); } + +//测试在线阅读器的翻译器设置是否正确,这个是adv_reader.html的函数,放在这里是为了归类 +function TestReaderTranslator() { + var text = $('#translator_test_src_text').val(); + var divDst = $('#translator_test_dst_text'); + divDst.val(i18n.translating); + MakeAjaxRequest("/adv/reader/test", "POST", {text: text}, function (resp) { + divDst.val(resp.text); + }); +} ///[end] book_translator.html ///[start] book_audiolator.html diff --git a/application/static/reader.css b/application/static/reader.css index f014c8d5..3fc997c8 100644 --- a/application/static/reader.css +++ b/application/static/reader.css @@ -284,3 +284,44 @@ body::-webkit-scrollbar-thumb { text-align: center; font-size: 0.9em; } + +.tr-result { + position: absolute; + top: 50%; + left: 50%; + background-color: white; + border: 1px solid #ccc; + border-radius: 20px; + box-shadow: 0px 0px 3px #aaa; + display: none; + min-width: 200px; + max-width: 50%; + max-height: 50%; + cursor: pointer; +} +.tr-close-icon { + position: absolute; + top: 10px; + right: 10px; + width: 30px; + height: 30px; + text-align: center; + line-height: 30px; + color: #111; + border: 1px solid #000; + border-radius: 50%; + font-size: 20px; + font-weight: bolder; +} +.tr-word { + margin: 10px auto 10px auto; + padding: 10px 50px 10px 40px; + font-weight: bold; + text-align: center; + border-bottom: 1px dotted #ccc; +} +.tr-text { + margin: 10px auto 10px auto; + padding: 10px; + text-align: center; +} \ No newline at end of file diff --git a/application/static/reader.js b/application/static/reader.js index fb3857c7..f9812a92 100644 --- a/application/static/reader.js +++ b/application/static/reader.js @@ -5,6 +5,7 @@ var g_iframeScrollHeight = 500; //在 iframeLoadEvent 里更新 //var g_iframeClientHeight = 500; var g_currentArticle = {}; +var g_dictMode = false; //对古董浏览器兼容性最好的判断一个变量是否为空的语法 //支持基本类型/数组/对象 @@ -130,8 +131,8 @@ function updateNavIndicator() { } //获取最靠近点击位置的一个单词(以空格分隔的单词) -function getWordAtClick(event) { - iframe = document.getElementById('iframe'); +function getWordAtClick(event, iframe) { + iframe = iframe || document.getElementById('iframe'); var doc = iframe.contentDocument || iframe.contentWindow.document; const range = doc.caretRangeFromPoint(event.clientX, event.clientY); if (range) { @@ -155,12 +156,54 @@ function getWordAtClick(event) { return null; } +//连接服务器查询一个单词的释义然后显示出来 +//event: click event +//word: 要查的词 +//selection: 是否有选择区域 +function translateWord(event, word, selection) { + var language = isEmpty(g_currentArticle) ? '' : getBookLanguage(g_currentArticle); + ajax_post('/reader/dict', {word: word, key: g_shareKey, language: language}, function (resp) { + if (resp.status == 'ok') { + var content = document.getElementById('content'); + var dialog = document.getElementById('tr-result'); + var title = document.getElementById('tr-word'); + var text = document.getElementById('tr-text'); + title.innerHTML = word; + text.innerHTML = resp.text; + var x = event.clientX; + var y = Math.max(event.clientY - content.scrollTop, 0); + var width = content.clientWidth; + var height = content.clientHeight; + if (x > width * 0.8) { + dialog.style.left = 'auto'; + dialog.style.right = Math.max(width - x, 20) + 'px'; + } else { + dialog.style.right = 'auto'; + dialog.style.left = x + 'px'; + } + if (y > height * 0.8) { + dialog.style.top = 'auto'; + dialog.style.bottom = Math.max(height - y, 20) + 'px'; + } else { + dialog.style.bottom = 'auto'; + dialog.style.top = (y + 20) + 'px'; + } + dialog.style.display = 'block'; + if (selection) { + selection.removeAllRanges(); + } + } else { + alert(resp.status); + } + }); +} + //屏幕点击事件的处理 function clickEvent(event) { event.preventDefault(); var content = document.getElementById('content'); var navbar = document.getElementById('navbar'); - var navPopMenu = document.getElementById('nav-popmenu') + var navPopMenu = document.getElementById('nav-popmenu'); var x = event.clientX; var y = event.clientY - content.scrollTop; var ww = content.clientWidth; @@ -439,6 +482,8 @@ function toggleNavPopMenu() { //inkIcon.innerHTML = g_inkMode ? '✔' : '☐'; var allowIcon = document.getElementById('allow-links').querySelector('.check-icon'); allowIcon.innerHTML = g_allowLinks ? '✔' : '☐'; + //var dictIcon = document.getElementById('dict-mode').querySelector('.check-icon'); + //dictIcon.innerHTML = g_dictMode ? '✔' : '☐'; menu.style.display = (menu.style.display == 'block') ? 'none' : 'block'; } @@ -507,6 +552,19 @@ function toggleInkMode() { saveSettings(); } +//切换查词模式 +function toggleDictMode() { + g_dictMode = !g_dictMode; + document.getElementById('tr-result').style.display='none'; + hideNavbar(); +} + +//关闭查词窗口 +function closeDictDialog() { + document.getElementById('tr-result').style.display='none'; + g_dictMode = false; +} + //根据是否使能墨水屏模式,设置相应的元素属性 function setInkMode(enable) { return; //暂时先禁用 @@ -677,7 +735,7 @@ function pushCurrentArticle() { hidePopMenu(); } -//通过一个文章获取对应书本的语言 +//通过一个文章获取对应书本的语言,在调用时请保证art合法 function getBookLanguage(art) { for (var i = 0; i < g_books.length; i++) { var entry = g_books[i]; //date @@ -704,6 +762,7 @@ function openArticle(article) { g_currentArticle = article; } hideNavbar(); + closeDictDialog(); } //打开上一篇文章 @@ -765,7 +824,8 @@ function findNextArticle(art) { } //iframe每次加载一个新的文档后会调用此函数,注册一些事件并更新一些变量 -function iframeLoadEvent(iframe) { +function iframeLoadEvent(evt) { + var iframe = document.getElementById('iframe'); adjustIFrameStyle(iframe); var doc = iframe.contentDocument || iframe.contentWindow.document; doc.addEventListener('click', function(event) { @@ -780,7 +840,15 @@ function iframeLoadEvent(iframe) { return; } } - if (!doc.getSelection().toString()) { //没有选择文本才翻页 + var selection = doc.getSelection(); + var text = selection.toString(); + if (g_dictMode) { + g_dictMode = false; + text = text || getWordAtClick(event, iframe); + if (text) { + translateWord(event, text, selection); + } + } else if (!text) { //没有选择文本才翻页 clickEvent(event); } }); @@ -811,14 +879,22 @@ function adjustIFrameStyle(iframe) { function documentKeyDownEvent(event) { var key = event.key; //console.log('Key pressed:', key); - if ((key == ' ') || (key == 'ArrowDown') || (key == 'ArrowRight') || (key == 'PageDown')) { + if ((key == ' ') || (key == 'ArrowRight') || (key == 'PageDown')) { event.stopPropagation(); event.preventDefault(); pageDown(); - } else if ((key == 'ArrowUp') || (key == 'ArrowLeft') || (key == 'PageUp')) { + } else if (key == 'ArrowDown') { + event.stopPropagation(); + event.preventDefault(); + openNextArticle(); + } else if ((key == 'ArrowLeft') || (key == 'PageUp')) { event.stopPropagation(); event.preventDefault(); pageUp(); + } else if (key == 'ArrowUp') { + event.stopPropagation(); + event.preventDefault(); + openPrevArticle(); } } @@ -835,6 +911,7 @@ document.addEventListener('DOMContentLoaded', function() { content.addEventListener('scroll', updatePosIndicator); navContent.addEventListener('click', navClickEvent); navContent.addEventListener('scroll', updateNavIndicator); + iframe.addEventListener('load', iframeLoadEvent); populateBooks(1); iframe.style.display = "none"; //加载完成后再显示 iframe.src = iframe.src; //强制刷新一次,避免偶尔出现不能点击的情况 diff --git a/application/templates/adv_base.html b/application/templates/adv_base.html index ed52d5ed..6632c4a9 100644 --- a/application/templates/adv_base.html +++ b/application/templates/adv_base.html @@ -88,6 +88,15 @@ {{_("Stylesheet")}} {% endif -%} + {% if advCurr=='reader' -%} +
  • + {{_("Reader")}} +
  • + {% else -%} +
  • + {{_("Reader")}} +
  • + {% endif -%} {% if advCurr=='calibreOptions' -%}
  • {{_("Calibre Options")}} diff --git a/application/templates/adv_reader.html b/application/templates/adv_reader.html new file mode 100644 index 00000000..838365a0 --- /dev/null +++ b/application/templates/adv_reader.html @@ -0,0 +1,85 @@ +{% extends "adv_base.html" %} +{% block titleTag -%} +{{ _("Reader") }} - KindleEar +{% endblock -%} +{% set dict = params.get('dict', {}) %} +{% set src_lang = dict.get('src_lang', '') %} +{% set dst_lang = dict.get('dst_lang', '') %} +{% set api_host = dict.get('api_host', '') %} +{% set api_keys = dict.get('api_keys', [])|join('\n') %} + +{% block advcontent -%} +{% if g.allowReader -%} +
    + {% if tips -%} +
    {{tips}}
    + {% endif -%} +
    + {{_("Dictionary")}} +

    + {{_("Set up a dictionary for online reading.")}} +

    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +

    + +

    +
    +
    +
    +
    + {{_("Test (Please save settings firstly)")}} +
    + + +
    +
    + + +
    +
    +

    + +

    +
    +{% else %} +

    + {{_("Online reading feature has not been activated yet.")}} +

    +{% endif -%} +{% endblock -%} +{% block js -%} + +{% endblock -%} \ No newline at end of file diff --git a/application/templates/base.html b/application/templates/base.html index b4fc877c..0fc78bd4 100644 --- a/application/templates/base.html +++ b/application/templates/base.html @@ -143,9 +143,7 @@ {% block header -%}
    - {% if g.allowReader -%} Reader - {% endif %}
    {% block header_loginfo -%} {% endif -%} diff --git a/application/templates/reader.html b/application/templates/reader.html index b9cbc882..169c6705 100644 --- a/application/templates/reader.html +++ b/application/templates/reader.html @@ -9,9 +9,15 @@
    - +
    + +
    +
    X
    +
    +
    +
    --> + - @@ -116,18 +128,19 @@
    - Nothing here + {{comicTitle}}
    - + {% autoescape off -%}