More useful error page when reading book fails

This commit is contained in:
Kovid Goyal 2017-05-18 00:48:15 +05:30
parent 07696cddb2
commit ecb9266eca
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 94 additions and 55 deletions

View File

@ -14,7 +14,7 @@ from book_list.library_data import (
from book_list.router import back, home, open_book from book_list.router import back, home, open_book
from book_list.theme import get_color, get_font_size 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.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 book_list.views import search_query_for
from date import format_date from date import format_date
from dom import add_extra_css, build_rule, clear, svgicon from dom import add_extra_css, build_rule, clear, svgicon
@ -479,7 +479,15 @@ def check_for_books_loaded():
def init(container_id): def init(container_id):
container = document.getElementById(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 window.scrollTo(0, 0) # Ensure we are at the top of the window
container.appendChild(E.div(class_=CLASS_NAME)) container.appendChild(E.div(class_=CLASS_NAME))
container.lastChild.appendChild(E.div(_('Loading books from the calibre library, please wait...'), style='margin: 1ex 1em')) container.lastChild.appendChild(E.div(_('Loading books from the calibre library, please wait...'), style='margin: 1ex 1em'))

View File

@ -320,7 +320,10 @@ def create_sort_panel(container_id):
show_panel('book_list', replace=True) show_panel('book_list', replace=True)
return return
container = document.getElementById(container_id) 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 = [] items = []
csf, csf_order = current_sorted_field() csf, csf_order = current_sorted_field()
new_sort_order = 'desc' if csf_order is 'asc' else 'asc' new_sort_order = 'desc' if csf_order is 'asc' else 'asc'

View File

@ -136,40 +136,46 @@ class ModalContainer:
self.close_current_modal() self.close_current_modal()
def create_simple_dialog(title, msg, details, icon, prefix): def create_simple_dialog_markup(title, msg, details, icon, prefix, parent):
details = details or '' show_details = E.a(class_='dialog-simple-link', style='cursor:pointer; color: blue; padding-top:1em; display:inline-block; margin-left: auto', _('Show details'))
def create_func(parent): show_details.addEventListener('click', def():
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.style.display = 'none'
show_details.addEventListener('click', def(): show_details.nextSibling.style.display = 'block'
show_details.style.display = 'none' )
show_details.nextSibling.style.display = 'block' is_html_msg = /<[a-zA-Z]/.test(msg)
) html_container = E.div()
is_html_msg = /<[a-zA-Z]/.test(msg) if is_html_msg:
html_container = E.div() safe_set_inner_html(html_container, msg)
if is_html_msg: details_container = E.span()
safe_set_inner_html(html_container, msg) if /<[a-zA-Z]/.test(details):
details_container = E.span() safe_set_inner_html(details_container, details)
if /<[a-zA-Z]/.test(details): else:
safe_set_inner_html(details_container, details) details_container.textContent = details
else: if prefix:
details_container.textContent = details prefix = E.span(' ' + prefix + ' ', style='white-space:pre; font-variant: small-caps')
parent.appendChild( else:
E.div( prefix = '\xa0'
style='max-width:60em; text-align: left', parent.appendChild(
E.h2( E.div(
E.span(svgicon(icon), style='color:red'), E.span('\xa0' + prefix + '\xa0', style='font-variant:small-caps'), title, style='max-width:40em; text-align: left',
style='font-weight: bold; font-size: ' + get_font_size('title') E.h2(
), E.span(svgicon(icon), style='color:red'), prefix, title,
E.div((html_container if is_html_msg else msg), style='padding-top: 1em; margin-top: 1em; border-top: 1px solid currentColor'), style='font-weight: bold; font-size: ' + get_font_size('title')
E.div(style='display: ' + ('block' if details else 'none'), ),
show_details, E.div((html_container if is_html_msg else msg), style='padding-top: 1em; margin-top: 1em; border-top: 1px solid currentColor'),
E.div(details_container, E.div(style='display: ' + ('block' if details else 'none'),
style='display:none; white-space:pre-wrap; font-size: smaller; margin-top: 1em; border-top: solid 1px currentColor; padding-top: 1em' 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): def create_custom_dialog(title, content_generator_func):

View File

@ -4,17 +4,22 @@
from __python__ import hash_literals from __python__ import hash_literals
import traceback import traceback
from ajax import ajax
from elementmaker import E from elementmaker import E
from gettext import gettext as _ 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.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 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 read_book.view import View
from utils import debounce, human_readable
from widgets import create_button
RENDER_VERSION = __RENDER_VERSION__ RENDER_VERSION = __RENDER_VERSION__
MATHJAX_VERSION = "__MATHJAX_VERSION__" MATHJAX_VERSION = "__MATHJAX_VERSION__"
@ -42,9 +47,7 @@ class ReadUI:
)) ))
container.appendChild(E.div( container.appendChild(E.div(
id=self.error_id, style='display:none; text-align: center', id=self.error_id, style='display:none;',
E.h2(_('Could not open book'), style='margin: 1ex; margin-top: 30vh;'),
E.div(style='margin: 1ex', E.a()),
)) ))
container.appendChild(E.div( container.appendChild(E.div(
@ -70,20 +73,38 @@ class ReadUI:
def show_error(self, title, msg, details): def show_error(self, title, msg, details):
div = self.show_stack(self.error_id) div = self.show_stack(self.error_id)
error_dialog(title, msg, details) clear(div)
a = div.lastChild.firstChild if self.current_metadata:
if self.current_book_id: book = self.current_metadata.title
a.setAttribute('href', encode_query_with_path({ elif self.current_book_id:
'library_id':current_library_id(), book = _('Book id #{}').format(self.current_book_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)
else: else:
a.textContent = '' book = _('book')
a.setAttribute('href', '')
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): def init_ui(self):
div = self.show_stack(self.progress_id) div = self.show_stack(self.progress_id)

View File

@ -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): def safe_set_inner_html(elem, html):
elem.innerHTML = simple_markup(html) elem.innerHTML = simple_markup(html)
return elem
def sandboxed_html(html, style, sandbox): def sandboxed_html(html, style, sandbox):