mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Work on refactoring the books view
This commit is contained in:
parent
8cb4545b96
commit
ab332d0b99
@ -113,6 +113,52 @@ def update_interface_data(ctx, rd):
|
|||||||
return basic_interface_data(ctx, rd)
|
return basic_interface_data(ctx, rd)
|
||||||
|
|
||||||
|
|
||||||
|
def get_library_init_data(ctx, rd, db, num, sorts, orders):
|
||||||
|
ans = {}
|
||||||
|
with db.safe_read_lock:
|
||||||
|
try:
|
||||||
|
ans['search_result'] = search_result(ctx, rd, db, rd.query.get('search', ''), num, 0, ','.join(sorts), ','.join(orders))
|
||||||
|
except ParseException:
|
||||||
|
ans['search_result'] = search_result(ctx, rd, db, '', num, 0, ','.join(sorts), ','.join(orders))
|
||||||
|
sf = db.field_metadata.ui_sortable_field_keys()
|
||||||
|
sf.pop('ondevice', None)
|
||||||
|
ans['sortable_fields'] = sorted(((
|
||||||
|
sanitize_sort_field_name(db.field_metadata, k), v) for k, v in sf.iteritems()),
|
||||||
|
key=lambda (field, name):sort_key(name))
|
||||||
|
ans['field_metadata'] = db.field_metadata.all_metadata()
|
||||||
|
mdata = ans['metadata'] = {}
|
||||||
|
try:
|
||||||
|
extra_books = set(int(x) for x in rd.query.get('extra_books', '').split(','))
|
||||||
|
except Exception:
|
||||||
|
extra_books = ()
|
||||||
|
for coll in (ans['search_result']['book_ids'], extra_books):
|
||||||
|
for book_id in coll:
|
||||||
|
if book_id not in mdata:
|
||||||
|
data = book_as_json(db, book_id)
|
||||||
|
if data is not None:
|
||||||
|
mdata[book_id] = data
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint('/interface-data/books-init', postprocess=json)
|
||||||
|
def books(ctx, rd):
|
||||||
|
'''
|
||||||
|
Get data to create list of books
|
||||||
|
|
||||||
|
Optional: ?num=50&sort=timestamp.desc&library_id=<default library>
|
||||||
|
&search=''&extra_books=''
|
||||||
|
'''
|
||||||
|
ans = {}
|
||||||
|
try:
|
||||||
|
num = int(rd.query.get('num', DEFAULT_NUMBER_OF_BOOKS))
|
||||||
|
except Exception:
|
||||||
|
raise HTTPNotFound('Invalid number of books: %r' % rd.query.get('num'))
|
||||||
|
library_id, db, sorts, orders = get_basic_query_data(ctx, rd)
|
||||||
|
ans = get_library_init_data(ctx, rd, db, num, sorts, orders)
|
||||||
|
ans['library_id'] = library_id
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
@endpoint('/interface-data/init', postprocess=json)
|
@endpoint('/interface-data/init', postprocess=json)
|
||||||
def interface_data(ctx, rd):
|
def interface_data(ctx, rd):
|
||||||
'''
|
'''
|
||||||
@ -139,29 +185,7 @@ def interface_data(ctx, rd):
|
|||||||
num = int(rd.query.get('num', DEFAULT_NUMBER_OF_BOOKS))
|
num = int(rd.query.get('num', DEFAULT_NUMBER_OF_BOOKS))
|
||||||
except Exception:
|
except Exception:
|
||||||
raise HTTPNotFound('Invalid number of books: %r' % rd.query.get('num'))
|
raise HTTPNotFound('Invalid number of books: %r' % rd.query.get('num'))
|
||||||
with db.safe_read_lock:
|
ans.update(get_library_init_data(ctx, rd, db, num, sorts, orders))
|
||||||
try:
|
|
||||||
ans['search_result'] = search_result(ctx, rd, db, rd.query.get('search', ''), num, 0, ','.join(sorts), ','.join(orders))
|
|
||||||
except ParseException:
|
|
||||||
ans['search_result'] = search_result(ctx, rd, db, '', num, 0, ','.join(sorts), ','.join(orders))
|
|
||||||
sf = db.field_metadata.ui_sortable_field_keys()
|
|
||||||
sf.pop('ondevice', None)
|
|
||||||
ans['sortable_fields'] = sorted(((
|
|
||||||
sanitize_sort_field_name(db.field_metadata, k), v) for k, v in sf.iteritems()),
|
|
||||||
key=lambda (field, name):sort_key(name))
|
|
||||||
ans['field_metadata'] = db.field_metadata.all_metadata()
|
|
||||||
mdata = ans['metadata'] = {}
|
|
||||||
try:
|
|
||||||
extra_books = set(int(x) for x in rd.query.get('extra_books', '').split(','))
|
|
||||||
except Exception:
|
|
||||||
extra_books = ()
|
|
||||||
for coll in (ans['search_result']['book_ids'], extra_books):
|
|
||||||
for book_id in coll:
|
|
||||||
if book_id not in mdata:
|
|
||||||
data = book_as_json(db, book_id)
|
|
||||||
if data is not None:
|
|
||||||
mdata[book_id] = data
|
|
||||||
|
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ THUMBNAIL_MAX_HEIGHT = 400
|
|||||||
BORDER_RADIUS = 10
|
BORDER_RADIUS = 10
|
||||||
|
|
||||||
def cover_grid_css():
|
def cover_grid_css():
|
||||||
sel = '#' + this
|
sel = '.' + this
|
||||||
ans = build_rule(sel, display='flex', flex_wrap='wrap', justify_content='space-around', align_items='flex-end', align_content='flex-start', user_select='none', overflow='hidden')
|
ans = build_rule(sel, display='flex', flex_wrap='wrap', justify_content='space-around', align_items='flex-end', align_content='flex-start', user_select='none', overflow='hidden')
|
||||||
|
|
||||||
# Container for an individual cover
|
# Container for an individual cover
|
||||||
@ -65,4 +65,3 @@ def create_item(book_id, interface_data, onclick):
|
|||||||
def append_item(container, item):
|
def append_item(container, item):
|
||||||
first_filler = container.lastChild.querySelector('.cover-grid-filler')
|
first_filler = container.lastChild.querySelector('.cover-grid-filler')
|
||||||
container.lastChild.insertBefore(item, first_filler)
|
container.lastChild.insertBefore(item, first_filler)
|
||||||
|
|
||||||
|
@ -4,10 +4,12 @@ from __python__ import hash_literals, bound_methods
|
|||||||
|
|
||||||
from dom import ensure_id
|
from dom import ensure_id
|
||||||
from elementmaker import E
|
from elementmaker import E
|
||||||
|
from session import get_interface_data
|
||||||
|
from gettext import gettext as _
|
||||||
|
|
||||||
from book_list.globals import get_db
|
from book_list.globals import get_db
|
||||||
from book_list.top_bar import create_top_bar
|
from book_list.top_bar import create_top_bar
|
||||||
from book_list.ui import set_default_panel_handler
|
from book_list.ui import set_default_panel_handler, show_panel
|
||||||
|
|
||||||
|
|
||||||
def show_recent():
|
def show_recent():
|
||||||
@ -23,9 +25,27 @@ def show_recent():
|
|||||||
def init(container_id):
|
def init(container_id):
|
||||||
create_top_bar(container_id, run_animation=True)
|
create_top_bar(container_id, run_animation=True)
|
||||||
container = document.getElementById(container_id)
|
container = document.getElementById(container_id)
|
||||||
|
interface_data = get_interface_data()
|
||||||
|
|
||||||
|
# Recent books
|
||||||
recent = E.div(style='display:none')
|
recent = E.div(style='display:none')
|
||||||
recent_container_id = ensure_id(recent)
|
recent_container_id = ensure_id(recent)
|
||||||
container.appendChild(recent)
|
container.appendChild(recent)
|
||||||
window.setTimeout(show_recent.bind(recent_container_id), 5)
|
window.setTimeout(show_recent.bind(recent_container_id), 5)
|
||||||
|
|
||||||
|
# Choose library
|
||||||
|
cl = E.div(
|
||||||
|
E.h2(_('Choose the calibre library to browse...'))
|
||||||
|
)
|
||||||
|
container.appendChild(cl)
|
||||||
|
lids = sorted(interface_data.library_map, key=def(x): return interface_data.library_map[x];)
|
||||||
|
for library_id in lids:
|
||||||
|
library_name = interface_data.library_map[library_id]
|
||||||
|
if library_name:
|
||||||
|
cl.appendChild(E.div(E.a(library_name, href='javascript: void(0)', title=library_name, data_lid=library_id, onclick=def(ev):
|
||||||
|
lib_id = ev.currentTarget.dataSet.lid
|
||||||
|
show_panel('book_list', {'library_id': lib_id})
|
||||||
|
)))
|
||||||
|
|
||||||
|
|
||||||
set_default_panel_handler(init)
|
set_default_panel_handler(init)
|
||||||
|
46
src/pyj/book_list/library_data.pyj
Normal file
46
src/pyj/book_list/library_data.pyj
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
from __python__ import hash_literals, bound_methods
|
||||||
|
|
||||||
|
from ajax import ajax
|
||||||
|
from session import get_interface_data
|
||||||
|
from utils import parse_url_params
|
||||||
|
|
||||||
|
|
||||||
|
load_status = {'loading':True, 'ok':False, 'error_html':None, 'current_fetch': None}
|
||||||
|
library_data = {}
|
||||||
|
current_fetch = None
|
||||||
|
|
||||||
|
|
||||||
|
def current_library_id():
|
||||||
|
return parse_url_params().library_id or get_interface_data().library_id
|
||||||
|
|
||||||
|
|
||||||
|
def update_library_data(data):
|
||||||
|
load_status.loading = False
|
||||||
|
load_status.ok = True
|
||||||
|
load_status.error_html = None
|
||||||
|
for key in 'search_result sortable_fields field_metadata metadata'.split(' '):
|
||||||
|
library_data[key] = data[key]
|
||||||
|
|
||||||
|
|
||||||
|
def on_data_loaded(end_type, xhr, ev):
|
||||||
|
load_status.current_fetch = None
|
||||||
|
if end_type is 'load':
|
||||||
|
data = JSON.parse(xhr.responseText)
|
||||||
|
update_library_data(data)
|
||||||
|
else:
|
||||||
|
load_status.ok = False
|
||||||
|
load_status.loading = False
|
||||||
|
load_status.error_html = xhr.error_html
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_init_data():
|
||||||
|
if load_status.current_fetch:
|
||||||
|
load_status.current_fetch.abort()
|
||||||
|
query = {'library_id': current_library_id()}
|
||||||
|
url_query = parse_url_params()
|
||||||
|
for key in url_query:
|
||||||
|
query[key] = url_query[key]
|
||||||
|
load_status.current_fetch = ajax('interface-data/books-init', on_data_loaded, query=query)
|
||||||
|
load_status.current_fetch.send()
|
@ -13,14 +13,16 @@ from popups import install_event_filters
|
|||||||
from utils import parse_url_params
|
from utils import parse_url_params
|
||||||
|
|
||||||
from book_list.constants import book_list_container_id, read_book_container_id
|
from book_list.constants import book_list_container_id, read_book_container_id
|
||||||
|
from book_list.library_data import fetch_init_data
|
||||||
from book_list.theme import get_color
|
from book_list.theme import get_color
|
||||||
from book_list.router import update_window_title, set_default_mode_handler, apply_url, set_mode_handler
|
from book_list.router import update_window_title, set_default_mode_handler, apply_url, set_mode_handler, on_pop_state
|
||||||
from book_list.globals import get_db, set_session_data
|
from book_list.globals import get_db, set_session_data
|
||||||
from book_list.ui import apply_url_state as book_list_mode_handler
|
from book_list.ui import apply_url_state as book_list_mode_handler
|
||||||
from read_book.ui import ReadUI
|
from read_book.ui import ReadUI
|
||||||
|
|
||||||
# Register the various panels
|
# Register the various panels
|
||||||
import book_list.home # noqa: unused-import
|
import book_list.home # noqa: unused-import
|
||||||
|
import book_list.views # noqa: unused-import
|
||||||
|
|
||||||
|
|
||||||
def remove_initial_progress_bar():
|
def remove_initial_progress_bar():
|
||||||
@ -48,6 +50,10 @@ def init_ui():
|
|||||||
install_event_filters()
|
install_event_filters()
|
||||||
set_default_mode_handler(book_list_mode_handler)
|
set_default_mode_handler(book_list_mode_handler)
|
||||||
window.onerror = onerror
|
window.onerror = onerror
|
||||||
|
setTimeout(def():
|
||||||
|
window.onpopstate = on_pop_state
|
||||||
|
, 0) # We do this after event loop ticks over to avoid catching popstate events that some browsers send on page load
|
||||||
|
|
||||||
translations = get_translations()
|
translations = get_translations()
|
||||||
if translations:
|
if translations:
|
||||||
install(translations)
|
install(translations)
|
||||||
@ -65,6 +71,7 @@ def init_ui():
|
|||||||
set_mode_handler('read_book', read_ui.apply_url_state.bind(read_ui))
|
set_mode_handler('read_book', read_ui.apply_url_state.bind(read_ui))
|
||||||
apply_url()
|
apply_url()
|
||||||
|
|
||||||
|
|
||||||
def on_data_loaded(end_type, xhr, ev):
|
def on_data_loaded(end_type, xhr, ev):
|
||||||
remove_initial_progress_bar()
|
remove_initial_progress_bar()
|
||||||
if end_type is 'load':
|
if end_type is 'load':
|
||||||
@ -84,11 +91,13 @@ def on_data_loaded(end_type, xhr, ev):
|
|||||||
p.innerHTML = xhr.error_html
|
p.innerHTML = xhr.error_html
|
||||||
document.body.appendChild(p)
|
document.body.appendChild(p)
|
||||||
|
|
||||||
|
|
||||||
def on_data_load_progress(loaded, total):
|
def on_data_load_progress(loaded, total):
|
||||||
p = document.querySelector('#page_load_progress > progress')
|
p = document.querySelector('#page_load_progress > progress')
|
||||||
p.max = total
|
p.max = total
|
||||||
p.value = loaded
|
p.value = loaded
|
||||||
|
|
||||||
|
|
||||||
def load_interface_data():
|
def load_interface_data():
|
||||||
temp = UserSessionData(None, {}) # So that settings for anonymous users are preserved
|
temp = UserSessionData(None, {}) # So that settings for anonymous users are preserved
|
||||||
query = {}
|
query = {}
|
||||||
@ -102,7 +111,7 @@ def load_interface_data():
|
|||||||
ajax('interface-data/init', on_data_loaded, on_data_load_progress, query=query).send()
|
ajax('interface-data/init', on_data_loaded, on_data_load_progress, query=query).send()
|
||||||
|
|
||||||
|
|
||||||
def on_update_interface_data():
|
def do_update_interface_data():
|
||||||
ajax('interface-data/update', def (end_type, xhr, ev):
|
ajax('interface-data/update', def (end_type, xhr, ev):
|
||||||
if end_type is 'load':
|
if end_type is 'load':
|
||||||
data = JSON.parse(xhr.responseText)
|
data = JSON.parse(xhr.responseText)
|
||||||
@ -117,5 +126,6 @@ def main():
|
|||||||
else:
|
else:
|
||||||
sd = UserSessionData(interface_data.username, interface_data.user_session_data)
|
sd = UserSessionData(interface_data.username, interface_data.user_session_data)
|
||||||
set_session_data(sd)
|
set_session_data(sd)
|
||||||
on_update_interface_data()
|
do_update_interface_data()
|
||||||
|
fetch_init_data()
|
||||||
init_ui()
|
init_ui()
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
from __python__ import hash_literals, bound_methods
|
from __python__ import hash_literals, bound_methods
|
||||||
|
|
||||||
|
from ajax import encode_query
|
||||||
|
|
||||||
from book_list.constants import read_book_container_id, book_list_container_id
|
from book_list.constants import read_book_container_id, book_list_container_id
|
||||||
from book_list.globals import get_current_query
|
from book_list.globals import get_current_query
|
||||||
from utils import parse_url_params
|
from utils import parse_url_params
|
||||||
@ -26,7 +28,7 @@ def update_window_title(subtitle, title='calibre', sep=' :: '):
|
|||||||
|
|
||||||
|
|
||||||
def is_reading_book():
|
def is_reading_book():
|
||||||
cq = get_current_query
|
cq = get_current_query()
|
||||||
return cq and cq.mode is read_book_mode
|
return cq and cq.mode is read_book_mode
|
||||||
|
|
||||||
|
|
||||||
@ -36,17 +38,42 @@ def apply_mode(mode):
|
|||||||
div.style.display = 'block' if div.id is divid else 'none'
|
div.style.display = 'block' if div.id is divid else 'none'
|
||||||
|
|
||||||
|
|
||||||
def apply_url():
|
def apply_url(ignore_handler):
|
||||||
data = parse_url_params()
|
data = parse_url_params()
|
||||||
data.mode = data.mode or 'book_list'
|
data.mode = data.mode or 'book_list'
|
||||||
get_current_query(data)
|
get_current_query(data)
|
||||||
apply_mode()
|
apply_mode()
|
||||||
handler = mode_handlers[data.mode] or default_mode_handler
|
if not ignore_handler:
|
||||||
handler(data)
|
handler = mode_handlers[data.mode] or default_mode_handler
|
||||||
|
handler(data)
|
||||||
|
|
||||||
|
|
||||||
def push_state(query, replace=False, mode='book_list'):
|
history_count = 0
|
||||||
|
|
||||||
|
|
||||||
|
def push_state(query, replace=False, mode='book_list', call_handler=True):
|
||||||
|
nonlocal history_count
|
||||||
query = {k:query[k] for k in query}
|
query = {k:query[k] for k in query}
|
||||||
if mode is not 'book_list':
|
if mode is not 'book_list':
|
||||||
query.mode = mode
|
query.mode = mode
|
||||||
# TODO: Implement this (see push_state in boos.pyj)
|
query = encode_query(query) or '?'
|
||||||
|
if replace:
|
||||||
|
window.history.replaceState(None, '', query)
|
||||||
|
else:
|
||||||
|
window.history.pushState(None, '', query)
|
||||||
|
history_count += 1
|
||||||
|
apply_url(not call_handler)
|
||||||
|
|
||||||
|
|
||||||
|
def on_pop_state(ev):
|
||||||
|
nonlocal history_count
|
||||||
|
history_count = max(0, history_count - 1)
|
||||||
|
apply_url()
|
||||||
|
|
||||||
|
|
||||||
|
def back():
|
||||||
|
nonlocal history_count
|
||||||
|
if history_count > 0:
|
||||||
|
window.back()
|
||||||
|
else:
|
||||||
|
push_state({}, replace=True)
|
||||||
|
@ -7,6 +7,8 @@ from elementmaker import E
|
|||||||
|
|
||||||
from book_list.constants import book_list_container_id
|
from book_list.constants import book_list_container_id
|
||||||
from book_list.globals import get_current_query
|
from book_list.globals import get_current_query
|
||||||
|
from book_list.router import push_state, back as router_back
|
||||||
|
from book_list.library_data import current_library_id
|
||||||
|
|
||||||
|
|
||||||
panel_handlers = {}
|
panel_handlers = {}
|
||||||
@ -38,13 +40,51 @@ def develop_panel(container):
|
|||||||
set_panel_handler('develop-widgets', develop_panel)
|
set_panel_handler('develop-widgets', develop_panel)
|
||||||
|
|
||||||
|
|
||||||
|
def currently_showing_panel():
|
||||||
|
c = document.getElementById(book_list_container_id)
|
||||||
|
return c.dataset.panel
|
||||||
|
|
||||||
|
def number_of_subpanels():
|
||||||
|
c = document.getElementById(book_list_container_id)
|
||||||
|
return c.lastChild.childNodes.length
|
||||||
|
|
||||||
|
|
||||||
|
def show_panel(panel, query_data, replace=False):
|
||||||
|
if currently_showing_panel() is panel:
|
||||||
|
return
|
||||||
|
query = {k:query_data[k] for k in query}
|
||||||
|
if panel is not 'home':
|
||||||
|
lid = current_library_id()
|
||||||
|
if lid:
|
||||||
|
query.library_id = lid
|
||||||
|
push_state(query, replace=replace)
|
||||||
|
|
||||||
|
|
||||||
|
def close_subpanel():
|
||||||
|
c = document.getElementById(book_list_container_id).lastChild
|
||||||
|
panel_to_remove = c.lastChild
|
||||||
|
if panel_to_remove:
|
||||||
|
c.remove(panel_to_remove)
|
||||||
|
if c.lastChild:
|
||||||
|
c.lastChild.style.display = 'block'
|
||||||
|
else:
|
||||||
|
c.style.display = 'none'
|
||||||
|
|
||||||
|
|
||||||
|
def back():
|
||||||
|
if number_of_subpanels() > 0:
|
||||||
|
return close_subpanel()
|
||||||
|
router_back()
|
||||||
|
|
||||||
|
|
||||||
def apply_url_state(state):
|
def apply_url_state(state):
|
||||||
panel = state.panel or 'home'
|
panel = state.panel or 'home'
|
||||||
c = document.getElementById(book_list_container_id)
|
if currently_showing_panel() is panel:
|
||||||
if c.dataset.panel is panel:
|
|
||||||
return
|
return
|
||||||
|
c = document.getElementById(book_list_container_id)
|
||||||
clear(c)
|
clear(c)
|
||||||
c.appendChild(E.div()), c.appendChild(E.div(style='display:none'))
|
c.appendChild(E.div())
|
||||||
|
c.appendChild(E.div(style='display:none'))
|
||||||
c.dataset.panel = panel
|
c.dataset.panel = panel
|
||||||
handler = panel_handlers[panel] or default_panel_handler
|
handler = panel_handlers[panel] or default_panel_handler
|
||||||
handler(ensure_id(c.firstChild, 'panel'))
|
handler(ensure_id(c.firstChild, 'panel'))
|
||||||
|
@ -4,25 +4,31 @@ from __python__ import hash_literals
|
|||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
from ajax import ajax_send
|
from ajax import ajax_send
|
||||||
from dom import set_css, add_extra_css, unique_id
|
from dom import set_css, add_extra_css
|
||||||
from elementmaker import E
|
from elementmaker import E
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from modals import error_dialog, ajax_progress_dialog
|
from modals import error_dialog, ajax_progress_dialog
|
||||||
|
|
||||||
from book_list.globals import get_session_data, get_boss
|
from book_list.globals import get_session_data
|
||||||
from book_list.cover_grid import cover_grid_css, create_item as create_cover_grid_item, init as init_cover_grid, append_item as cover_grid_append_item
|
from book_list.cover_grid import cover_grid_css, create_item as create_cover_grid_item, init as init_cover_grid, append_item as cover_grid_append_item
|
||||||
|
from book_list.top_bar import create_top_bar
|
||||||
|
from book_list.ui import back, set_panel_handler
|
||||||
from widgets import create_button, create_spinner
|
from widgets import create_button, create_spinner
|
||||||
|
|
||||||
bv_counter = 0
|
COVER_GRID_CLASS = 'book-list-cover-grid'
|
||||||
|
|
||||||
CLASS_NAME = 'books-main-list'
|
|
||||||
COVER_GRID = unique_id('cover-grid')
|
|
||||||
|
|
||||||
add_extra_css(def():
|
add_extra_css(def():
|
||||||
ans = cover_grid_css.call(COVER_GRID)
|
ans = cover_grid_css.call(COVER_GRID_CLASS)
|
||||||
return ans
|
return ans
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def init(container_id):
|
||||||
|
create_top_bar(container_id, title=_('Books'), action=back, icon='close')
|
||||||
|
|
||||||
|
|
||||||
|
set_panel_handler('book_list', init)
|
||||||
|
|
||||||
|
|
||||||
class BooksView:
|
class BooksView:
|
||||||
|
|
||||||
def __init__(self, interface_data, book_list_container):
|
def __init__(self, interface_data, book_list_container):
|
||||||
|
@ -25,13 +25,18 @@ def debounce(func, wait, immediate=False):
|
|||||||
func.apply(context, args)
|
func.apply(context, args)
|
||||||
|
|
||||||
def parse_url_params(url=None, allow_multiple=False):
|
def parse_url_params(url=None, allow_multiple=False):
|
||||||
|
cache = parse_url_params.cache
|
||||||
url = url or window.location.href
|
url = url or window.location.href
|
||||||
|
if cache[url]:
|
||||||
|
return parse_url_params.cache[url]
|
||||||
qs = url.indexOf('?')
|
qs = url.indexOf('?')
|
||||||
ans = {}
|
ans = {}
|
||||||
if qs < 0:
|
if qs < 0:
|
||||||
|
cache[url] = ans
|
||||||
return ans
|
return ans
|
||||||
q = url.slice(qs + 1, ((url.indexOf('#') + 1) or (url.length + 1)))
|
q = url.slice(qs + 1, ((url.indexOf('#') + 1) or (url.length + 1)))
|
||||||
if not q:
|
if not q:
|
||||||
|
cache[url] = ans
|
||||||
return ans
|
return ans
|
||||||
pairs = q.replace(/\+/g, " ").split("&")
|
pairs = q.replace(/\+/g, " ").split("&")
|
||||||
for pair in pairs:
|
for pair in pairs:
|
||||||
@ -43,7 +48,9 @@ def parse_url_params(url=None, allow_multiple=False):
|
|||||||
ans[key].append(val)
|
ans[key].append(val)
|
||||||
else:
|
else:
|
||||||
ans[key] = val
|
ans[key] = val
|
||||||
|
cache[url] = ans
|
||||||
return ans
|
return ans
|
||||||
|
parse_url_params.cache = {}
|
||||||
|
|
||||||
_roman = list(zip(
|
_roman = list(zip(
|
||||||
[1000,900,500,400,100,90,50,40,10,9,5,4,1],
|
[1000,900,500,400,100,90,50,40,10,9,5,4,1],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user