From dcf100bb28fce84f7c9616471f447e5d47c0c29f Mon Sep 17 00:00:00 2001 From: cdhigh Date: Sat, 1 Jun 2024 21:19:29 -0300 Subject: [PATCH] 3.1.0 add online reading --- application/back_end/db_models.py | 5 +- application/lib/build_ebook.py | 18 +- .../lib/calibre/customize/conversion.py | 4 - .../lib/calibre/ebooks/conversion/plumber.py | 60 ++-- application/static/base.js | 4 +- application/static/reader.css | 73 ++--- application/static/reader.js | 262 +++++++++++++----- application/templates/reader.html | 20 +- application/templates/reader_404.html | 76 +++-- application/translations/messages.pot | 46 +-- .../tr_TR/LC_MESSAGES/messages.mo | Bin 28487 -> 28610 bytes .../tr_TR/LC_MESSAGES/messages.po | 46 +-- .../translations/zh/LC_MESSAGES/messages.mo | Bin 26733 -> 26829 bytes .../translations/zh/LC_MESSAGES/messages.po | 46 +-- application/utils.py | 13 +- application/view/reader.py | 100 ++++--- docs/Chinese/faq.md | 20 +- docs/English/faq.md | 19 +- readme.md | 36 +-- readme_zh.md | 10 +- tests/runtests.py | 2 +- tests/simple_in_email.py | 42 +++ 22 files changed, 597 insertions(+), 305 deletions(-) create mode 100644 tests/simple_in_email.py diff --git a/application/back_end/db_models.py b/application/back_end/db_models.py index 4d62d9a6..10c72a7b 100644 --- a/application/back_end/db_models.py +++ b/application/back_end/db_models.py @@ -23,7 +23,7 @@ class KeUser(MyBaseModel): # kindleEar User created_time = DateTimeField(default=datetime.datetime.utcnow) #email,sender,kindle_email,secret_key,enable_send,timezone,inbound_email, - #keep_in_email_days,delivery_mode,webshelf_days + #keep_in_email_days,delivery_mode,webshelf_days,reader_params #sender: 可能等于自己的email,也可能是管理员的email #delivery_mode: 推送模式:['email' | 'local' | 'email,local'] base_config = JSONField(default=JSONField.dict_default) @@ -43,7 +43,8 @@ def cfg(self, item, default=None): if value is None: return {'email': '', 'kindle_email': '', 'secret_key': '', 'timezone': 0, 'inbound_email': 'save,forward', 'keep_in_email_days': 1, - 'delivery_mode': 'email,local', 'webshelf_days': 7}.get(item, value) + 'delivery_mode': 'email,local', 'webshelf_days': 7, + 'reader_params': {}}.get(item, value) else: return value def set_cfg(self, item, value): diff --git a/application/lib/build_ebook.py b/application/lib/build_ebook.py index 759031e7..38a1ef00 100644 --- a/application/lib/build_ebook.py +++ b/application/lib/build_ebook.py @@ -22,8 +22,8 @@ def recipes_to_ebook(recipes: list, user, options=None, output_fmt=''): recipes = [recipes] output = io.BytesIO() output_fmt=output_fmt if output_fmt else user.book_cfg('type') - plumber = Plumber(recipes, output, input_fmt='recipe', output_fmt=output_fmt) - plumber.merge_ui_recommendations(ke_opts(user, options)) + options = ke_opts(user, options) + plumber = Plumber(recipes, output, input_fmt='recipe', output_fmt=output_fmt, options=options) plumber.run() return output.getvalue() @@ -98,18 +98,16 @@ def clearPrevDownloads(): #退出时清理临时文件 def html_to_book(html: str, title: str, user, imgs=None, options=None, output_fmt='', language=''): input_ = {'html': html, 'imgs': imgs, 'title': title, 'language': language} output = io.BytesIO() - output_fmt=output_fmt if output_fmt else user.book_cfg('type') - plumber = Plumber(input_, output, input_fmt='html', output_fmt=output_fmt) - plumber.merge_ui_recommendations(ke_opts(user, options)) + output_fmt = output_fmt if output_fmt else user.book_cfg('type') + options = ke_opts(user, options) + plumber = Plumber(input_, output, input_fmt='html', output_fmt=output_fmt, options=options) plumber.run() return output.getvalue() #获取KindleEar定制的电子书转换参数 def ke_opts(user, options=None): - opt = user.custom.get('calibre_options', {}) - if not isinstance(opt, dict): - opt = {} - opt = opt.copy() + opt = user.custom.get('calibre_options') + opt = opt.copy() if isinstance(opt, dict) else {} opt.update(options or {}) opt.setdefault('output_profile', user.book_cfg('device')) opt.setdefault('input_profile', 'kindle') @@ -117,6 +115,8 @@ def ke_opts(user, options=None): opt.setdefault('epub_inline_toc', True) opt.setdefault('dont_compress', True) opt.setdefault('dont_split_on_page_breaks', True) + opt.setdefault('dont_save_webshelf', False) + opt.setdefault('keep_images', True) opt['user'] = user #opt.setdefault('debug_pipeline', os.getenv('KE_TEMP_DIR')) diff --git a/application/lib/calibre/customize/conversion.py b/application/lib/calibre/customize/conversion.py index f5a318a7..4bf000f7 100644 --- a/application/lib/calibre/customize/conversion.py +++ b/application/lib/calibre/customize/conversion.py @@ -174,10 +174,6 @@ class InputFormatPlugin(Plugin): 'document itself. Particularly useful for documents that ' 'do not declare an encoding or that have erroneous ' 'encoding declarations.')), - OptionRecommendation(name='user', recommended_value=None, - help='Keuser instance.'), - OptionRecommendation(name='keep_images', recommended_value=True, - help='If keep the images.'), } #: Options to customize the behavior of this plugin. Every option must be an diff --git a/application/lib/calibre/ebooks/conversion/plumber.py b/application/lib/calibre/ebooks/conversion/plumber.py index 75edb5c2..a744632e 100644 --- a/application/lib/calibre/ebooks/conversion/plumber.py +++ b/application/lib/calibre/ebooks/conversion/plumber.py @@ -17,13 +17,14 @@ from calibre.ptempfile import PersistentTemporaryDirectory from calibre.utils.date import parse_date from calibre.utils.zipfile import ZipFile +from calibre.utils.filenames import ascii_filename from calibre import (extract, walk, isbytestring, filesystem_encoding, get_types_map) from calibre.constants import __version__ from polyglot.builtins import string_or_bytes from filesystem_dict import FsDictStub -from application.utils import sanitize_filename, get_directory_size +from application.utils import get_directory_size from application.base_handler import save_delivery_log DEBUG_README=b''' @@ -90,10 +91,11 @@ class Plumber: #input_: 输入,编译好的recipes列表或包含html和相关图像的一个字典 #output: 输出文件绝对路径名,也可能是一个BytesIO - def __init__(self, input_, output, input_fmt, output_fmt=None, abort_after_input_dump=False): + def __init__(self, input_, output, input_fmt, output_fmt=None, options=None, abort_after_input_dump=False): self.input_ = input_ self.output = output self.log = default_log + self.user_options = options or {} self.abort_after_input_dump = abort_after_input_dump self.pipeline_options = _pipeline_options @@ -190,8 +192,6 @@ def merge_plugin_recommendations(self): for source in (self.input_plugin, self.output_plugin): self.merge_plugin_recs(source) - #在外面设置电子书生成的参数 - # {'name1': value1, 'name2': value2} def merge_ui_recommendations(self, recommendations: dict): ''' Merge recommendations from the UI. As long as the UI recommendation @@ -213,10 +213,10 @@ def eq(name, a, b): if rec is not None: rec.recommended_value = val - def opts_to_mi(self, mi): + def opts_to_mi(self, opts, mi): from calibre.ebooks.metadata import string_to_authors for x in self.metadata_option_names: - val = getattr(self.opts, x, None) + val = getattr(opts, x, None) if val is not None: if x == 'authors': val = string_to_authors(val) @@ -252,7 +252,7 @@ def download_cover(self, url): img.convert('RGB').save(pt.name) return pt.name - def read_user_metadata(self): + def read_user_metadata(self, opts): ''' Read all metadata specified by the user. Command line options override metadata from a specified OPF file. @@ -266,7 +266,7 @@ def read_user_metadata(self): # with open(self.opts.read_metadata_from_opf, 'rb') as stream: # opf = OPF(stream, os.path.dirname(self.opts.read_metadata_from_opf)) # mi = opf.to_book_metadata() - self.opts_to_mi(mi) + self.opts_to_mi(opts, mi) #if mi.cover: # if mi.cover.startswith('http:') or mi.cover.startswith('https:'): # mi.cover = self.download_cover(mi.cover) @@ -282,44 +282,49 @@ def setup_options(self): ''' Setup the `self.opts` object. ''' - self.opts = OptionValues() + opts = OptionValues() for group in (self.input_options, self.pipeline_options, self.output_options): for rec in group: - setattr(self.opts, rec.option.name, rec.recommended_value) + setattr(opts, rec.option.name, rec.recommended_value) + + for name, val in self.user_options.items(): + setattr(opts, name, val) def set_profile(profiles, which): attr = which + '_profile' - sval = getattr(self.opts, attr) + sval = getattr(opts, attr) for x in profiles(): if x.short_name == sval: - setattr(self.opts, attr, x) + setattr(opts, attr, x) return self.log.warn( 'Profile (%s) %r is no longer available, using default'%(which, sval)) for x in profiles(): if x.short_name == 'default': - setattr(self.opts, attr, x) + setattr(opts, attr, x) break set_profile(input_profiles, 'input') set_profile(output_profiles, 'output') - self.read_user_metadata() + self.read_user_metadata(opts) - self.opts.no_inline_navbars = self.opts.output_profile.supports_mobi_indexing \ + opts.no_inline_navbars = opts.output_profile.supports_mobi_indexing \ and self.output_fmt == 'mobi' - if self.opts.verbose > 1: + if opts.verbose > 1: self.log.debug('Resolved conversion options') try: self.log.debug('calibre version:', __version__) - odict = dict(self.opts.__dict__) + odict = dict(opts.__dict__) for x in ('username', 'password'): odict.pop(x, None) self.log.debug(pprint.pformat(odict)) except: self.log.exception('Failed to get resolved conversion options') + self.opts = opts + def flush(self): try: sys.stdout.flush() @@ -409,7 +414,7 @@ def run(self): # self.dump_input(self.oeb, tdir) # if self.abort_after_input_dump: # return - self.opts_to_mi(self.user_metadata) + self.opts_to_mi(self.opts, self.user_metadata) if not hasattr(self.oeb, 'manifest'): #从一堆文件里面创建OEBBook实例 try: self.oeb = create_oebbook(self.log, self.oeb, self.opts, encoding=self.input_plugin.output_encoding, @@ -579,15 +584,20 @@ def run(self): def save_oeb_if_need(self, oeb): user = self.opts.user #type:ignore oebDir = os.environ.get('EBOOK_SAVE_DIR') - if not (oebDir and ('local' in user.cfg('delivery_mode'))): + if getattr(self.opts, 'dont_save_webshelf') or not (oebDir and ('local' in user.cfg('delivery_mode'))): return - title = sanitize_filename(oeb.metadata.title[0].value or 'Untitled') - bookDir = _bookDir = os.path.join(oebDir, user.name, user.local_time('%Y-%m-%d'), title) - cnt = 0 - while os.path.exists(bookDir): #一天可以保存多个同名推送 - cnt += 1 - bookDir = f'{_bookDir} [{cnt}]' + #提取字符串开头的数字 + def prefixNum(txt): + match = re.search(r'^(\d+)', txt) + return int(match.group(1)) if match else 0 + + dateDir = os.path.join(oebDir, user.name, user.local_time('%Y-%m-%d')) + maxIdx = max([prefixNum(item) for item in os.listdir(dateDir)]) if os.path.exists(dateDir) else 0 + title = oeb.metadata.title[0].value or 'Untitled' + title = ascii_filename(title).replace(' ', '_') + bookDir = os.path.join(dateDir, f'{maxIdx + 1:03}_{title}') + try: os.makedirs(bookDir) except Exception as e: diff --git a/application/static/base.js b/application/static/base.js index 16827f56..8605d4c9 100644 --- a/application/static/base.js +++ b/application/static/base.js @@ -1150,7 +1150,7 @@ var AjaxFileUpload = { } }, error: function(xhr, status, error) { - alert(status); + alert(status + '\n' + error); } }); }, @@ -1312,7 +1312,7 @@ function startUploadCoversToServer(url) { $("#up_cover_progress").hide(); $("#up_cover_progress_bar").css("width", "0px"); $("#up_cover_progress_bar").html(''); - alert(status); + alert(status + '\n' + error); } }); } diff --git a/application/static/reader.css b/application/static/reader.css index 8af6a284..f014c8d5 100644 --- a/application/static/reader.css +++ b/application/static/reader.css @@ -1,48 +1,61 @@ -body { +* { padding: 0px; margin: 0px; - font-family: Arial, sans-serif; - overflow: hidden; +} +html, body { + padding: 0px; + margin: 0px; + height: 100%; scrollbar-width: none; -ms-overflow-style: none; } -::-webkit-scrollbar { +body::-webkit-scrollbar { display: none; width: 0px; height: 0px; background: transparent; } -::-webkit-scrollbar-thumb { +body::-webkit-scrollbar-thumb { background: transparent; display: none; } .container { margin: 0px; - padding: 5px; + padding: 0px; position: relative; height: 100%; width: 100%; box-sizing: border-box; } .content { - margin-right: 10px; - padding: 15px; + margin: 0px; + padding: 0px; overflow-y: auto; height: 100%; width: 100%; - scrollbar-width: none; box-sizing: border-box; - /*-webkit-overflow-scrolling: touch;*/ } -.content::-webkit-scrollbar { - display: none; +.embedded-iframe { + padding: 10px 20px 10px 10px; + margin: 0px; + width: 100%; + height: 100%; + border: none; + white-space: normal; + word-wrap: break-word; + overflow-wrap: break-word; + overflow: hidden; + hyphens: auto; + box-sizing: border-box; + scrollbar-width: none; + -ms-overflow-style: none; } .pos-indicator { position: absolute; - right: 15px; + right: 5px; top: 5px; - width: 10px; + width: 15px; height: 50px; background-color: rgba(0, 0, 0, 0.5); border-radius: 5px; @@ -52,6 +65,7 @@ body { position: fixed; left: 0px; top: 0px; + margin: 0px; padding: 5px 10px 5px 5px; background-color: white; overflow-x: hidden; @@ -62,13 +76,22 @@ body { /* small screen, ink mode, pw3/voyage=1448x1072 */ @media (max-width: 1072px) { + ::-webkit-scrollbar { + display: none; + width: 0px; + height: 0px; + background: transparent; + } + ::-webkit-scrollbar-thumb { + background: transparent; + display: none; + } .navbar { display: none; right: 20px; - bottom: 10px; + bottom: 0px; } .container { - width: 100%; margin: 0px 10px 0px 0px; overflow: hidden; -webkit-overflow-scrolling: touch; @@ -90,13 +113,10 @@ body { } .container { width: auto; - overflow-y: scroll; - margin-left: 400px; /* width of .navbar */ + margin-left: 410px; /* width of .navbar */ } - .pos-indicator { - display: none; - } - button#closeNavBtn { + + .pos-indicator, .nav-indicator, button#closeNavBtn { display: none; } .nav-footer button { @@ -264,12 +284,3 @@ body { text-align: center; font-size: 0.9em; } -.embedded-iframe { - padding: 0px; - margin: 0px; - width: 100%; - height: 100%; - border: none; - scrollbar-width: none; - -ms-overflow-style: none; -} diff --git a/application/static/reader.js b/application/static/reader.js index 8b74d631..bfd88269 100644 --- a/application/static/reader.js +++ b/application/static/reader.js @@ -2,10 +2,8 @@ //If you need to make some changes, //Please use legacy JavaScript syntax only, avoid using any modern syntax and feature. -var g_allowLinks = ''; //all,web,ke,'' -var g_inkMode = true; var g_iframeScrollHeight = 500; //在 iframeLoadEvent 里更新 -var g_iframeClientHeight = 500; +//var g_iframeClientHeight = 500; var g_currentArticle = {}; //对古董浏览器兼容性最好的判断一个变量是否为空的语法 @@ -66,10 +64,10 @@ function ajax(url, options) { } if (type == "GET") { - xhr.open("GET", options.url + "?" + params, true); + xhr.open("GET", url + "?" + params, true); //第三个参数true表示异步请求 xhr.send(null); } else if (type == "POST") { - xhr.open("POST", options.url, true); + xhr.open("POST", url, true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send(params); } @@ -132,39 +130,60 @@ function updateNavIndicator() { } //屏幕点击事件的处理 -function clickEvent(event, clientHeight, scrollHeight) { +function clickEvent(event) { var content = document.getElementById('content'); var navbar = document.getElementById('navbar'); var navPopMenu = document.getElementById('nav-popmenu') - var scrollTop = content.scrollTop; - var scrollHeight = scrollHeight || content.scrollHeight; var x = event.clientX; var y = event.clientY - content.scrollTop; - var ww = getViewportWidth(); - var wh = content.clientHeight; //getViewportHeight(); + var ww = content.clientWidth; + var wh = content.clientHeight; //alert(x + ',' + event.clientY + ',' + content.scrollTop + ',' + content.clientHeight); navPopMenu.style.display = 'none'; - if ((y < wh / 5) && isMobile()) { //上部弹出菜单 (20%) - navbar.style.display = (navbar.style.display == "block") ? "none" : "block"; - } else if (x < ww / 3) { //左侧往回翻页 (30%) - if (navbar.style.display == "block") { - navbar.style.display = 'none'; - } else if (g_inkMode) { - if (scrollTop <= 0) { - openPrevArticle(); - } else { - content.scrollTop = Math.max(0, scrollTop - wh + 40); - } + if (y < wh / 5) { //上部 (20%) + if (x < ww * 0.15) { //左上 15%,上一篇文章 + openPrevArticle(); + } else if (x > ww * 0.80) { //右上 20%,下一篇文章 + openNextArticle(); + } else if (isMobile()) { //中间65%,弹出菜单 + navbar.style.display = (navbar.style.display == "block") ? "none" : "block"; } + } else if (x < ww / 3) { //左侧往回翻页 (30%) + pageUp(content, navbar); } else { //右侧往前翻页 - if (navbar.style.display == "block") { - navbar.style.display = 'none'; - } else if (g_inkMode) { - if (scrollTop >= scrollHeight - wh) { - openNextArticle(); - } else { - content.scrollTop = Math.min(scrollTop + wh - 40, scrollHeight); - } + pageDown(content, navbar); + } +} + +//往上翻页 +function pageUp(content, navbar) { + content = content || document.getElementById('content'); + navbar = navbar || document.getElementById('navbar'); + if (isMobile() && (navbar.style.display == "block")) { + navbar.style.display = 'none'; + } else if (g_inkMode) { + var scrollTop = content.scrollTop; + if (scrollTop <= 0) { + openPrevArticle(); + } else { + content.scrollTop = Math.max(0, scrollTop - content.clientHeight + 40); + } + } +} + +//往下翻页 +function pageDown(content, navbar) { + content = content || document.getElementById('content'); + navbar = navbar || document.getElementById('navbar'); + if (isMobile() && (navbar.style.display == "block")) { + navbar.style.display = 'none'; + } else if (g_inkMode) { + var scrollTop = content.scrollTop; + var scrollHeight = g_iframeScrollHeight || content.scrollHeight; + if (scrollTop >= scrollHeight - content.clientHeight) { + openNextArticle(); + } else { + content.scrollTop = Math.min(scrollTop + content.clientHeight - 40, scrollHeight); } } } @@ -176,14 +195,14 @@ function iFrameEvent(event) { var data = event.data; //console.log('iFrameEvent: ' + JSON.stringify(data)); g_iframeScrollHeight = data.scrollHeight; - g_iframeClientHeight = data.clientHeight; + //g_iframeClientHeight = data.clientHeight; if (data.type == 'iframeLoaded') { document.getElementById('iframe').style.height = g_iframeScrollHeight + 'px'; } else if (data.type == 'click') { if (data.href && g_allowLinks) { window.location.href = data.href; //覆盖原先的阅读界面 } else { - clickEvent(data.event, g_iframeClientHeight, g_iframeScrollHeight); + clickEvent(data.event); } } } @@ -199,7 +218,8 @@ function getViewportWidth() { //oasis分辨率(1680x1264) //pw5分辨率(1648x1236) function isMobile() { - return getViewportWidth() <= 1072; + var width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; + return width <= 1072; } //返回屏幕高度 @@ -238,6 +258,11 @@ function adjustContentHeight() { if (navbar.offsetHeight && footer.offsetHeight) { navContent.style.height = (navbar.offsetHeight - footer.offsetHeight) + 'px'; } + if (!isMobile()) { + navbar.style.display = "block"; + } + container.style.height = getViewportHeight() + 'px'; + content.style.height = getViewportHeight() + 'px'; } //导航栏往上翻页 @@ -345,18 +370,20 @@ function navDeleteBooks(event) { } var books = []; + var titles = [] for (var i = 0; i < chks.length; i++) { - books.push(chks[i].value); + books.push(chks[i].value); //bookDir + titles.push(chks[i].nextElementSibling.textContent); } - var booksStr = books.slice(0, 5).join('\n'); - if (books.length > 5) { - booksStr += '\n...'; + var titleStr = titles.slice(0, 5).join('\n'); + if (titles.length > 5) { + titleStr += '\n...'; } - if (!(event.ctrlKey || event.metaKey) && !confirm(i18n.areYouSureDelete + '\n' + booksStr)) { + if (!(event.ctrlKey || event.metaKey) && !confirm(i18n.areYouSureDelete + '\n' + titleStr)) { return; } - ajax_post('/reader/delete', {books: JSON.stringify(books)}, function (resp) { + ajax_post('/reader/delete', {books: books.join('|')}, function (resp) { if (resp.status == 'ok') { deleteBooksAndUpdateUi(books); } else { @@ -371,8 +398,7 @@ function deleteBooksAndUpdateUi(books) { var removeSet = new Set(books); g_books = g_books.filter(function (entry) { entry.books = entry.books.filter(function (book) { - var key = entry.date + '/' + book.title; - return !removeSet.has(key); + return !removeSet.has(book.bookDir); }); return entry.books.length > 0; }); @@ -382,13 +408,38 @@ function deleteBooksAndUpdateUi(books) { //显示/隐藏导航设置菜单 function toggleNavPopMenu() { var menu = document.getElementById('nav-popmenu'); - var inkIcon = document.getElementById('ink-mode').querySelector('.check-icon'); + //var inkIcon = document.getElementById('ink-mode').querySelector('.check-icon'); + //inkIcon.innerHTML = g_inkMode ? '✔' : '☐'; var allowIcon = document.getElementById('allow-links').querySelector('.check-icon'); - inkIcon.innerHTML = g_inkMode ? '✔' : '☐'; allowIcon.innerHTML = g_allowLinks ? '✔' : '☐'; menu.style.display = (menu.style.display == 'block') ? 'none' : 'block'; } +//增加iframe的字号 +function increaseFontSize() { + g_fontSize = parseFloat(Math.min(g_fontSize * 1.2, 3.0).toFixed(1)); + adjustIFrameStyle(); + if (isMobile()) { + hideNavbar(); + } + saveSettings(); +} + +//减小iframe的字号 +function decreaseFontSize() { + g_fontSize = parseFloat(Math.max(g_fontSize * 0.8, 0.5).toFixed(1)); + adjustIFrameStyle(); + if (isMobile()) { + hideNavbar(); + } + saveSettings(); +} + +//将目前的配置保存到服务器 +function saveSettings() { + ajax_post('/reader/settings', {fontSize: g_fontSize, allowLinks: g_allowLinks, inkMode: g_inkMode}); +} + //显示触摸区域图示 function showTouchHint() { hidePopMenu(); @@ -396,7 +447,8 @@ function showTouchHint() { document.getElementById('navbar').style.display = 'none'; } var iframe = document.getElementById('iframe'); - iframe.style.height = 'auto'; //规避iframe只能变大不能变小的bug + //iframe.style.height = 'auto'; //规避iframe只能变大不能变小的bug + iframe.style.display = "none"; //加载完成后再显示 iframe.src = '/reader/404?tips='; } @@ -407,6 +459,7 @@ function hidePopMenu() { //隐藏左侧导航栏 function hideNavbar() { + hidePopMenu(); if (isMobile()) { document.getElementById('navbar').style.display = 'none'; } @@ -417,16 +470,19 @@ function toggleAllowLinks() { g_allowLinks = !g_allowLinks; var allowIcon = document.getElementById('allow-links').querySelector('.check-icon'); allowIcon.innerHTML = g_allowLinks ? '✔' : '☐'; + saveSettings(); } //是否允许墨水屏模式 function toggleInkMode() { g_inkMode = !g_inkMode; setInkMode(g_inkMode); + saveSettings(); } //根据是否使能墨水屏模式,设置相应的元素属性 function setInkMode(enable) { + return; //暂时先禁用 var container = document.getElementById('container'); var content = document.getElementById('content'); var indicator = document.getElementById('pos-indicator'); @@ -437,21 +493,21 @@ function setInkMode(enable) { container.style.height = getViewportHeight() + 'px'; content.style.height = getViewportHeight() + 'px'; content.style.scrollbarWidth = "none"; - body.style.overflow = 'hidden'; - body.style.scrollbarWidth = 'none'; - body.style.scrollbarColor = 'transparent'; - body.style.msOverflowStyle = 'none'; - indicator.style.display = 'block'; + //body.style.overflow = 'hidden'; + //body.style.scrollbarWidth = 'none'; + //body.style.scrollbarColor = 'transparent'; + //body.style.msOverflowStyle = 'none'; + //indicator.style.display = 'block'; } else { icon.innerHTML = '☐'; container.style.height = g_iframeScrollHeight + 'px'; content.style.height = g_iframeScrollHeight + 'px'; content.style.scrollbarWidth = "auto"; - body.style.overflow = 'auto'; - body.style.scrollbarWidth = 'auto'; - body.style.scrollbarColor = 'auto'; - body.style.msOverflowStyle = 'scrollbar'; - indicator.style.display = 'none'; + //body.style.overflow = 'auto'; + //body.style.scrollbarWidth = 'auto'; + //body.style.scrollbarColor = 'auto'; + //body.style.msOverflowStyle = 'scrollbar'; + //indicator.style.display = 'none'; } } @@ -482,7 +538,7 @@ function populateBooks(expandLevel) { ostr.push( ' -