diff --git a/imgsrc/srv/help.svg b/imgsrc/srv/help.svg new file mode 100644 index 000000000000..a8617809b6df --- /dev/null +++ b/imgsrc/srv/help.svg @@ -0,0 +1 @@ + diff --git a/src/calibre/gui2/viewer/web_view.py b/src/calibre/gui2/viewer/web_view.py index 719514882b2f..e987f058d9b9 100644 --- a/src/calibre/gui2/viewer/web_view.py +++ b/src/calibre/gui2/viewer/web_view.py @@ -36,6 +36,7 @@ secure_webengine, to_js ) from calibre.srv.code import get_translations_data +from calibre.utils.localization import localize_user_manual_link from calibre.utils.serialize import json_loads from calibre.utils.shared_file import share_open from polyglot.builtins import as_bytes, iteritems @@ -275,6 +276,7 @@ class ViewerBridge(Bridge): tts = from_js(object, object) edit_book = from_js(object, object, object) show_book_folder = from_js() + show_help = from_js(object) create_view = to_js() start_book_load = to_js() @@ -538,6 +540,7 @@ def __init__(self, parent=None): self.bridge.highlights_changed.connect(self.highlights_changed) self.bridge.edit_book.connect(self.edit_book) self.bridge.show_book_folder.connect(self.show_book_folder) + self.bridge.show_help.connect(self.show_help) self.bridge.open_url.connect(safe_open_url) self.bridge.speak_simple_text.connect(self.tts.speak_simple_text) self.bridge.tts.connect(self.tts.action) @@ -744,5 +747,9 @@ def show_book_folder(self): path = os.path.dirname(os.path.abspath(set_book_path.pathtoebook)) safe_open_url(QUrl.fromLocalFile(path)) + def show_help(self, which): + if which == 'viewer': + safe_open_url(localize_user_manual_link('https://manual.calibre-ebook.com/viewer.html')) + def repair_after_fullscreen_switch(self): self.execute_when_ready('repair_after_fullscreen_switch') diff --git a/src/calibre/srv/code.py b/src/calibre/srv/code.py index 58ec95b50526..bf8e8066c986 100644 --- a/src/calibre/srv/code.py +++ b/src/calibre/srv/code.py @@ -27,7 +27,7 @@ from calibre.utils.config import prefs, tweaks from calibre.utils.icu import numeric_sort_key, sort_key from calibre.utils.localization import ( - get_lang, lang_map_for_ui, localize_website_link + get_lang, lang_map_for_ui, localize_website_link, lang_code_for_user_manual ) from calibre.utils.search_query_parser import ParseException from calibre.utils.serialize import json_dumps @@ -156,7 +156,8 @@ def basic_interface_data(ctx, rd): 'search_the_net_urls': getattr(ctx, 'search_the_net_urls', None) or [], 'num_per_page': rd.opts.num_per_page, 'default_book_list_mode': rd.opts.book_list_mode, - 'donate_link': localize_website_link('https://calibre-ebook.com/donate') + 'donate_link': localize_website_link('https://calibre-ebook.com/donate'), + 'lang_code_for_user_manual': lang_code_for_user_manual(), } ans['library_map'], ans['default_library_id'] = ctx.library_info(rd) return ans diff --git a/src/calibre/utils/localization.py b/src/calibre/utils/localization.py index e005c45eb7a4..1d89ac49f193 100644 --- a/src/calibre/utils/localization.py +++ b/src/calibre/utils/localization.py @@ -528,12 +528,19 @@ def user_manual_stats(): return stats -def localize_user_manual_link(url): +def lang_code_for_user_manual(): lc = lang_as_iso639_1(get_lang()) if lc == 'en': - return url + return '' stats = user_manual_stats() if stats.get(lc, 0) < 0.3: + return '' + return lc + + +def localize_user_manual_link(url): + lc = lang_code_for_user_manual() + if not lc: return url from polyglot.urllib import urlparse, urlunparse parts = urlparse(url) diff --git a/src/pyj/read_book/overlay.pyj b/src/pyj/read_book/overlay.pyj index cb7bf5bdac09..ee768a44a9fa 100644 --- a/src/pyj/read_book/overlay.pyj +++ b/src/pyj/read_book/overlay.pyj @@ -431,9 +431,17 @@ class MainOverlay: # {{{ style='position: fixed; width: 100%; bottom: 0; display: flex; justify-content: space-between; align-items: center;' 'user-select: none; background-color: {}'.format(get_color('window-background')), E.div( - style='display: flex; align-items: center; cursor: pointer; padding: 0.5ex 1rem', class_='main-overlay-button', - title=_('Close the viewer controls'), - svgicon('close', icon_size, icon_size), '\xa0', _('Close') + style='display: flex; justify-content: space-between; align-items: center;', + E.div( + style='display: flex; align-items: center; cursor: pointer; padding: 0.5ex 1rem', class_='main-overlay-button', + title=_('Close the viewer controls'), + svgicon('close', icon_size, icon_size), '\xa0', _('Close') + ), + E.div( + style='display: flex; align-items: center; cursor: pointer; padding: 0.5ex 1rem', class_='main-overlay-button', + svgicon('help', icon_size, icon_size), '\xa0', _('Help'), onclick=def(ev): + ui_operations.show_help('viewer') + ) ), E.div(style='padding: 0.5ex 1rem', '\xa0'), E.div(style='padding: 0.5ex 1rem', '\xa0'), ), diff --git a/src/pyj/read_book/ui.pyj b/src/pyj/read_book/ui.pyj index a8689824ccd7..c070816f51d2 100644 --- a/src/pyj/read_book/ui.pyj +++ b/src/pyj/read_book/ui.pyj @@ -18,6 +18,7 @@ from read_book.db import get_db from read_book.globals import ui_operations from read_book.tts import Client from read_book.view import View +from session import get_interface_data from utils import debounce, full_screen_element, human_readable, request_full_screen from widgets import create_button @@ -92,6 +93,16 @@ class ReadUI: ui_operations.find_next = self.view.search_overlay.find_next ui_operations.open_url = def(url): window.open(url, '_blank') + ui_operations.show_help = def(which): + if which is 'viewer': + path = '/viewer.html' + else: + return + if get_interface_data().lang_code_for_user_manual: + path = f'/{get_interface_data().lang_code_for_user_manual}{path}' + url = 'https://manual.calibre-ebook.com' + path + window.open(url, '_blank') + ui_operations.copy_selection = def(text, html): # try using document.execCommand which on chrome allows the # copy on non-secure origin if this is close to a user diff --git a/src/pyj/session.pyj b/src/pyj/session.pyj index 8df290c63bc4..4249060164f5 100644 --- a/src/pyj/session.pyj +++ b/src/pyj/session.pyj @@ -241,6 +241,7 @@ default_interface_data = { 'icon_path': '', 'custom_list_template': None, 'num_per_page': 50, + 'lang_code_for_user_manual': '', } def get_interface_data(): diff --git a/src/pyj/viewer-main.pyj b/src/pyj/viewer-main.pyj index a4bf81ae3e4a..a3f4600088ce 100644 --- a/src/pyj/viewer-main.pyj +++ b/src/pyj/viewer-main.pyj @@ -429,6 +429,8 @@ if window is window.top: to_python.edit_book(spine_name, frac, selected_text or '') ui_operations.show_book_folder = def(): to_python.show_book_folder() + ui_operations.show_help = def(which): + to_python.show_help(which) document.body.appendChild(E.div(id='view')) window.onerror = onerror