From ecb9266ecae984bebeb566f2d9aad7b763341e9d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 18 May 2017 00:48:15 +0530 Subject: [PATCH] More useful error page when reading book fails --- src/pyj/book_list/book_details.pyj | 12 +++++- src/pyj/book_list/views.pyj | 5 ++- src/pyj/modals.pyj | 68 ++++++++++++++++-------------- src/pyj/read_book/ui.pyj | 63 ++++++++++++++++++--------- src/pyj/utils.pyj | 1 + 5 files changed, 94 insertions(+), 55 deletions(-) diff --git a/src/pyj/book_list/book_details.pyj b/src/pyj/book_list/book_details.pyj index 249e618f80..81a015d62b 100644 --- a/src/pyj/book_list/book_details.pyj +++ b/src/pyj/book_list/book_details.pyj @@ -14,7 +14,7 @@ from book_list.library_data import ( from book_list.router import back, home, open_book from book_list.theme import get_color, get_font_size from book_list.top_bar import add_button, create_top_bar, set_title -from book_list.ui import query_as_href, set_panel_handler +from book_list.ui import query_as_href, set_panel_handler, show_panel from book_list.views import search_query_for from date import format_date from dom import add_extra_css, build_rule, clear, svgicon @@ -479,7 +479,15 @@ def check_for_books_loaded(): def init(container_id): container = document.getElementById(container_id) - create_top_bar(container, title=_('Book details'), action=back, icon='close') + close_action, close_icon = back, 'close' + q = parse_url_params() + ca = q.close_action + if ca is 'home': + close_action, close_icon = def(): home();, 'home' + elif ca is 'book_list': + close_action = def(): + show_panel('book_list', {'book_id':q.book_id}) + create_top_bar(container, title=_('Book details'), action=close_action, icon=close_icon) window.scrollTo(0, 0) # Ensure we are at the top of the window container.appendChild(E.div(class_=CLASS_NAME)) container.lastChild.appendChild(E.div(_('Loading books from the calibre library, please wait...'), style='margin: 1ex 1em')) diff --git a/src/pyj/book_list/views.pyj b/src/pyj/book_list/views.pyj index 79d88a7cf3..43b0333f37 100644 --- a/src/pyj/book_list/views.pyj +++ b/src/pyj/book_list/views.pyj @@ -320,7 +320,10 @@ def create_sort_panel(container_id): show_panel('book_list', replace=True) return container = document.getElementById(container_id) - create_top_bar(container, title=_('Sort books by…'), action=back, icon='close') + close_action, close_icon = back, 'close' + if parse_url_params().close_action is 'home': + close_action, close_icon = def(): home();, 'home' + create_top_bar(container, title=_('Sort books by…'), action=close_action, icon=close_icon) items = [] csf, csf_order = current_sorted_field() new_sort_order = 'desc' if csf_order is 'asc' else 'asc' diff --git a/src/pyj/modals.pyj b/src/pyj/modals.pyj index 58bd675840..56d3947082 100644 --- a/src/pyj/modals.pyj +++ b/src/pyj/modals.pyj @@ -136,40 +136,46 @@ class ModalContainer: self.close_current_modal() -def create_simple_dialog(title, msg, details, icon, prefix): - details = details or '' - def create_func(parent): - show_details = E.a(class_='dialog-simple-link', style='cursor:pointer; color: blue; padding-top:1em; display:inline-block; margin-left: auto', _('Show details')) - show_details.addEventListener('click', def(): - show_details.style.display = 'none' - show_details.nextSibling.style.display = 'block' - ) - is_html_msg = /<[a-zA-Z]/.test(msg) - html_container = E.div() - if is_html_msg: - safe_set_inner_html(html_container, msg) - details_container = E.span() - if /<[a-zA-Z]/.test(details): - safe_set_inner_html(details_container, details) - else: - details_container.textContent = details - parent.appendChild( - E.div( - style='max-width:60em; text-align: left', - E.h2( - E.span(svgicon(icon), style='color:red'), E.span('\xa0' + prefix + '\xa0', style='font-variant:small-caps'), title, - style='font-weight: bold; font-size: ' + get_font_size('title') - ), - E.div((html_container if is_html_msg else msg), style='padding-top: 1em; margin-top: 1em; border-top: 1px solid currentColor'), - E.div(style='display: ' + ('block' if details else 'none'), - show_details, - E.div(details_container, - style='display:none; white-space:pre-wrap; font-size: smaller; margin-top: 1em; border-top: solid 1px currentColor; padding-top: 1em' - ) +def create_simple_dialog_markup(title, msg, details, icon, prefix, parent): + show_details = E.a(class_='dialog-simple-link', style='cursor:pointer; color: blue; padding-top:1em; display:inline-block; margin-left: auto', _('Show details')) + show_details.addEventListener('click', def(): + show_details.style.display = 'none' + show_details.nextSibling.style.display = 'block' + ) + is_html_msg = /<[a-zA-Z]/.test(msg) + html_container = E.div() + if is_html_msg: + safe_set_inner_html(html_container, msg) + details_container = E.span() + if /<[a-zA-Z]/.test(details): + safe_set_inner_html(details_container, details) + else: + details_container.textContent = details + if prefix: + prefix = E.span(' ' + prefix + ' ', style='white-space:pre; font-variant: small-caps') + else: + prefix = '\xa0' + parent.appendChild( + E.div( + style='max-width:40em; text-align: left', + E.h2( + E.span(svgicon(icon), style='color:red'), prefix, title, + style='font-weight: bold; font-size: ' + get_font_size('title') + ), + E.div((html_container if is_html_msg else msg), style='padding-top: 1em; margin-top: 1em; border-top: 1px solid currentColor'), + E.div(style='display: ' + ('block' if details else 'none'), + show_details, + E.div(details_container, + style='display:none; white-space:pre-wrap; font-size: smaller; margin-top: 1em; border-top: solid 1px currentColor; padding-top: 1em' ) ) ) - show_modal(create_func) + ) + + +def create_simple_dialog(title, msg, details, icon, prefix): + details = details or '' + show_modal(create_simple_dialog_markup.bind(None, title, msg, details, icon, prefix)) def create_custom_dialog(title, content_generator_func): diff --git a/src/pyj/read_book/ui.pyj b/src/pyj/read_book/ui.pyj index 284c592e6c..c5e94ef444 100644 --- a/src/pyj/read_book/ui.pyj +++ b/src/pyj/read_book/ui.pyj @@ -4,17 +4,22 @@ from __python__ import hash_literals import traceback -from ajax import ajax from elementmaker import E from gettext import gettext as _ -from modals import error_dialog -from utils import human_readable, debounce, encode_query_with_path +from ajax import ajax from book_list.constants import read_book_container_id +from book_list.library_data import ( + current_library_id, library_data +) +from book_list.ui import show_panel +from book_list.router import update_window_title, home +from dom import clear +from modals import create_simple_dialog_markup from read_book.db import get_db -from book_list.router import update_window_title -from book_list.library_data import library_data, current_library_id, current_virtual_library from read_book.view import View +from utils import debounce, human_readable +from widgets import create_button RENDER_VERSION = __RENDER_VERSION__ MATHJAX_VERSION = "__MATHJAX_VERSION__" @@ -42,9 +47,7 @@ class ReadUI: )) container.appendChild(E.div( - id=self.error_id, style='display:none; text-align: center', - E.h2(_('Could not open book'), style='margin: 1ex; margin-top: 30vh;'), - E.div(style='margin: 1ex', E.a()), + id=self.error_id, style='display:none;', )) container.appendChild(E.div( @@ -70,20 +73,38 @@ class ReadUI: def show_error(self, title, msg, details): div = self.show_stack(self.error_id) - error_dialog(title, msg, details) - a = div.lastChild.firstChild - if self.current_book_id: - a.setAttribute('href', encode_query_with_path({ - 'library_id':current_library_id(), - 'vl': current_virtual_library(), - 'book_id': (self.current_book_id + ''), - 'panel':'book_details' - })) - a.textContent = _( - 'Click to go back to the details page for: {}').format(self.current_metadata.title) + clear(div) + if self.current_metadata: + book = self.current_metadata.title + elif self.current_book_id: + book = _('Book id #{}').format(self.current_book_id) else: - a.textContent = '' - a.setAttribute('href', '') + book = _('book') + + div.appendChild(E.div(style='padding: 2ex 2rem; display:table; margin: auto')) + div = div.lastChild + dp = E.div() + create_simple_dialog_markup(title, _('Could not open {}. {}').format(book, msg), details, 'bug', '', dp) + div.appendChild(dp) + div.appendChild(E.div( + style='margin-top: 1ex; padding-top: 1ex; border-top: solid 1px currentColor', + _('Go back to:'), E.br(), E.br(), + create_button(_('Home'), 'home', def(): home(True);), + )) + q = {} + if self.current_book_id: + q.book_id = self.current_book_id + '' + q.close_action = 'home' + div.lastChild.appendChild(E.span( + '\xa0', + create_button(_('Book list'), 'library', def(): show_panel('book_list', q, True);), + )) + if self.current_book_id: + q.close_action = 'book_list' + div.lastChild.appendChild(E.span( + '\xa0', + create_button(_('Book details'), 'book', def(): show_panel('book_details', q, True);), + )) def init_ui(self): div = self.show_stack(self.progress_id) diff --git a/src/pyj/utils.pyj b/src/pyj/utils.pyj index 3daab0960f..a131ed5f33 100644 --- a/src/pyj/utils.pyj +++ b/src/pyj/utils.pyj @@ -219,6 +219,7 @@ simple_markup.allowed_tags = v"'b|i|br|h1|h2|h3|h4|h5|h6|div|em|strong|span'.spl def safe_set_inner_html(elem, html): elem.innerHTML = simple_markup(html) + return elem def sandboxed_html(html, style, sandbox):