1# vim:fileencoding=utf-8
2# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
3from __python__ import bound_methods, hash_literals
4
5from elementmaker import E
6from gettext import gettext as _
7
8from book_list.constants import book_list_container_id, read_book_container_id
9from book_list.globals import get_current_query, get_session_data
10from book_list.library_data import current_library_id
11from modals import close_all_modals
12from utils import (
13    encode_query_with_path, parse_url_params, request_full_screen,
14    safe_set_inner_html
15)
16
17mode_handlers = {}
18default_mode_handler = None
19read_book_mode = 'read_book'
20
21
22def set_mode_handler(mode, handler):
23    mode_handlers[mode] = handler
24
25
26def set_default_mode_handler(handler):
27    nonlocal default_mode_handler
28    default_mode_handler = handler
29
30
31def update_window_title(subtitle, title='calibre', sep=' :: '):
32    extra = (sep + subtitle) if subtitle else ''
33    document.title = title + extra
34
35
36def is_reading_book():
37    cq = get_current_query()
38    return cq and cq.mode is read_book_mode
39
40
41def apply_mode():
42    divid = read_book_container_id if is_reading_book() else book_list_container_id
43    for div in document.getElementById(divid).parentNode.childNodes:
44        div.style.display = 'block' if div.id is divid else 'none'
45
46
47def apply_url(ignore_handler):
48    close_all_modals()  # needed to close any error dialogs, etc when clicking back or forward in the browser or using push_state() to go to a new page
49    data = parse_url_params()
50    data.mode = data.mode or 'book_list'
51    get_current_query(data)
52    apply_mode()
53    if not ignore_handler:
54        handler = mode_handlers[data.mode] or default_mode_handler
55        handler(data)
56
57
58def open_book(book_id, fmt, library_id=None, replace=False):
59    opt = get_session_data().get('fullscreen_when_opening')
60    has_touch = v'"ontouchstart" in window'
61    at_left = window.screenLeft is 0
62    likely_wants_fullscreen = has_touch and at_left
63    if (opt is 'auto' and likely_wants_fullscreen) or opt is 'always':
64        # Note that full screen requests only succeed if they are in response to a
65        # user action like clicking/tapping a button
66        request_full_screen()
67    library_id = library_id or current_library_id()
68    push_state({'book_id':book_id, 'fmt':fmt, 'library_id':library_id}, replace=replace, mode=read_book_mode)
69
70
71
72def push_state(query, replace=False, mode='book_list', call_handler=True):
73    query = {k:query[k] for k in query if query[k]}
74    if mode is not 'book_list':
75        query.mode = mode
76    query = encode_query_with_path(query)
77    if replace:
78        window.history.replaceState(None, '', query)
79    else:
80        window.history.pushState(None, '', query)
81        push_state.history_count += 1
82    apply_url(not call_handler)
83
84push_state.history_count = 0
85
86def on_pop_state(ev):
87    push_state.history_count = max(0, push_state.history_count - 1)
88    apply_url()
89
90
91def back():
92    if push_state.history_count > 0:
93        window.history.back()
94    else:
95        cq = get_current_query()
96        handler = mode_handlers[cq.mode] or default_mode_handler
97        if handler.back_from_current:
98            q = handler.back_from_current(cq)
99        else:
100            q = {}
101        push_state(q, replace=True)
102
103
104def home(replace=False):
105    push_state({})
106
107
108def report_a_load_failure(container, msg, error_html):
109    err = E.div()
110    safe_set_inner_html(err, error_html)
111    container.appendChild(E.div(
112        style='margin: 1ex 1em',
113        E.div(msg),
114        err,
115        E.div(
116            style='margin-top: 1em; border-top: solid 1px currentColor; padding-top: 1ex;',
117            E.a(onclick=def(): home(replace=True);, href='javascript: void(0)', class_='blue-link', _('Go back to the home page')))
118        ),
119    )
120