diff --git a/src/pyj/book_list/library_data.pyj b/src/pyj/book_list/library_data.pyj index 2ccf63f4db..330670dc75 100644 --- a/src/pyj/book_list/library_data.pyj +++ b/src/pyj/book_list/library_data.pyj @@ -6,14 +6,40 @@ from ajax import ajax from session import get_interface_data from utils import parse_url_params +from book_list.globals import get_session_data -load_status = {'loading':True, 'ok':False, 'error_html':None, 'current_fetch': None, 'library_id': None} +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 url_books_query(sd): + q = parse_url_params() + sd = sd or get_session_data() + lid = q.library_id or get_interface_data().default_library_id + return { + 'library_id': lid, + 'sort': q.sort or sd.get_library_option(lid, 'sort'), + } + + +def loaded_books_query(): + sr = library_data.search_result + sort = None + if sr: + sort = [s + '.' + o for s, o in zip(sr.sort.split(','), sr.sort_order.split(','))].join(',') + return { + 'library_id': sr.library_id if sr else None, + 'sort': sort, + } + + +def current_sorted_field(): + if library_data.search_result: + return library_data.search_result.sort, library_data.search_result.sort_order + sort = url_books_query().sort.partition(',')[0] + csf = sort.partition('.')[0] + csfo = sort.partition('.')[2] or 'asc' + return csf, csfo def update_library_data(data): @@ -29,6 +55,11 @@ def on_data_loaded(end_type, xhr, ev): if end_type is 'load': data = JSON.parse(xhr.responseText) update_library_data(data) + sd = get_session_data() + q = loaded_books_query() + sd.set_library_option(q.library_id, 'sort', q.sort) + elif end_type is 'abort': + pass else: load_status.ok = False load_status.loading = False @@ -38,17 +69,16 @@ def on_data_loaded(end_type, xhr, ev): def fetch_init_data(): if load_status.current_fetch: load_status.current_fetch.abort() - load_status.library_id = current_library_id() - query = {'library_id': load_status.library_id} - url_query = parse_url_params() - for key in url_query: - query[key] = url_query[key] + query = url_books_query() + load_status.loading = True + load_status.ok = False + load_status.error_html = None load_status.current_fetch = ajax('interface-data/books-init', on_data_loaded, query=query) load_status.current_fetch.send() def cover_url(book_id, width, height): - return 'get/thumb/{}/{}?sz={}x{}'.format(book_id, current_library_id, Math.ceil(width * window.devicePixelRatio), Math.ceil(height * window.devicePixelRatio)) + return 'get/thumb/{}/{}?sz={}x{}'.format(book_id, loaded_books_query().library_id, Math.ceil(width * window.devicePixelRatio), Math.ceil(height * window.devicePixelRatio)) def book_metadata(book_id): @@ -56,6 +86,12 @@ def book_metadata(book_id): def ensure_current_library_data(): - # TODO: Handle search/sort parameters as well - if load_status.library_id != current_library_id(): + q = url_books_query() + loaded = loaded_books_query() + matches = True + for key in q: + if q[key] is not loaded[key]: + matches = False + break + if not matches: fetch_init_data() diff --git a/src/pyj/book_list/main.pyj b/src/pyj/book_list/main.pyj index 88937c6c8c..e070ba0214 100644 --- a/src/pyj/book_list/main.pyj +++ b/src/pyj/book_list/main.pyj @@ -10,10 +10,9 @@ from modals import create_modal_container, error_dialog from session import get_interface_data, UserSessionData, update_interface_data, get_translations from gettext import gettext as _, install from popups import install_event_filters -from utils import parse_url_params 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.library_data import fetch_init_data, update_library_data, url_books_query from book_list.theme import get_color 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 @@ -77,6 +76,7 @@ def on_data_loaded(end_type, xhr, ev): if end_type is 'load': data = JSON.parse(xhr.responseText) update_interface_data(data) + update_library_data(data) interface_data = get_interface_data() sd = UserSessionData(interface_data.username, interface_data.user_session_data) set_session_data(sd) @@ -99,15 +99,11 @@ def on_data_load_progress(loaded, total): def load_interface_data(): - temp = UserSessionData(None, {}) # So that settings for anonymous users are preserved + idata = get_interface_data() query = {} - library_id = temp.get('library_id') - if library_id: - query.library_id = library_id - query.sort = temp.get_library_option(library_id, 'sort') - url_query = parse_url_params() - for key in url_query: - query[key] = url_query[key] + if not idata.is_default: + temp = UserSessionData(None, {}) # So that settings for anonymous users are preserved + query = url_books_query(temp) ajax('interface-data/init', on_data_loaded, on_data_load_progress, query=query).send() diff --git a/src/pyj/book_list/ui.pyj b/src/pyj/book_list/ui.pyj index 81e501e815..6dae389ef0 100644 --- a/src/pyj/book_list/ui.pyj +++ b/src/pyj/book_list/ui.pyj @@ -8,7 +8,6 @@ from elementmaker import E from book_list.constants import book_list_container_id from book_list.globals import get_current_query from book_list.router import push_state -from book_list.library_data import current_library_id panel_handlers = {} @@ -45,13 +44,13 @@ def currently_showing_panel(): return c.dataset.panel -def show_panel(panel, query_data, replace=False): - query = {k:query_data[k] for k in query_data} +def show_panel(panel, query=None, replace=False): + if query is None: + query = {} + else: + query = {k:query[k] for k in query if k is not 'panel'} if panel is not 'home': query.panel = panel - lid = current_library_id() - if lid: - query.library_id = lid push_state(query, replace=replace) diff --git a/src/pyj/book_list/views.pyj b/src/pyj/book_list/views.pyj index a83780c142..41c8b902b9 100644 --- a/src/pyj/book_list/views.pyj +++ b/src/pyj/book_list/views.pyj @@ -15,10 +15,11 @@ from widgets import create_button, create_spinner 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.top_bar import create_top_bar +from book_list.top_bar import create_top_bar, add_button from book_list.router import back -from book_list.ui import set_panel_handler -from book_list.library_data import current_library_id, load_status, ensure_current_library_data, library_data +from book_list.ui import set_panel_handler, show_panel +from book_list.library_data import load_status, ensure_current_library_data, library_data, current_sorted_field, loaded_books_query, url_books_query +from book_list.item_list import create_item_list, create_item ALLOWED_MODES = {'cover_grid'} DEFAULT_MODE = 'cover_grid' @@ -76,6 +77,8 @@ def apply_view_mode(mode=DEFAULT_MODE): render_ids() +# More button {{{ + def update_fetching_status(): more = document.getElementById(book_list_data.container_id).lastChild if book_list_data.fetching_more_books: @@ -123,7 +126,7 @@ def get_more_books(): data[key] = library_data.search_result[key] book_list_data.fetching_more_books = ajax_send( 'interface-data/more-books', data, got_more_books, - query={'library_id':current_library_id()} + query={'library_id':loaded_books_query().library_id} ) update_fetching_status() @@ -142,6 +145,9 @@ def create_more_button(more): update_fetching_status() +# }}} + + def create_books_list(container): book_list_data.container_id = ensure_id(container) book_list_data.shown_book_ids = set() @@ -151,6 +157,7 @@ def create_books_list(container): container.appendChild(E.div()), container.appendChild(E.div()) apply_view_mode(get_session_data().get('view_mode')) create_more_button(container.lastChild) + add_button(container.parentNode.id, icon='sort-amount-desc', action=show_panel.bind(None, 'book_list^sort'), tooltip=_('Sort Books')) def check_for_books_loaded(): @@ -169,7 +176,7 @@ def check_for_books_loaded(): err, E.div( style='margin-top: 1em; border-top: solid 1px currentColor; padding-top: 1ex;', - E.a(onclick=back, href='javascript: void(0)', style='color: blue', _('Go back to the home page'))) + E.a(onclick=back, href='javascript: void(0)', style='color: blue', _('Go back to the home page'))) ), ) return @@ -180,7 +187,7 @@ def init(container_id): interface_data = get_interface_data() ensure_current_library_data() container = document.getElementById(container_id) - lid = container.dataset.library_id = current_library_id() + lid = container.dataset.library_id = url_books_query().library_id title = interface_data.library_map[lid] create_top_bar(container_id, title=title, action=back, icon='home') container.appendChild(E.div()) @@ -188,4 +195,44 @@ def init(container_id): conditional_timeout(container_id, 5, check_for_books_loaded) +# Sorting {{{ + +def change_sort(field, order): + abort_get_more_books() + sd = get_session_data() + so = sd.get('last_sort_order') + order = order or so[field] or 'asc' + order = 'asc' if order is 'asc' else 'desc' + q = loaded_books_query() + q.sort = field + '.' + order + so[field] = order + sd.set('last_sort_order', so) + sd.set_library_option(q.library_id, 'sort', q.sort) + show_panel('book_list', query=q, replace=True) + + +def create_sort_panel(container_id): + if not library_data.sortable_fields: + show_panel('book_list', replace=True) + return + create_top_bar(container_id, title=_('Sort books by…'), action=back, icon='close') + items = [] + csf, csf_order = current_sorted_field() + new_sort_order = 'desc' if csf_order is 'asc' else 'asc' + if csf is 'date': + csf = 'timestamp' + for field, name in library_data.sortable_fields: + subtitle = icon_name = None + if field is csf: + subtitle = _('Reverse current sort order') + icon_name = 'sort-amount-asc' if csf_order is 'asc' else 'sort-amount-desc' + action = change_sort.bind(None, field, new_sort_order) + else: + action = change_sort.bind(None, field, None) + items.push(create_item(name, subtitle=subtitle, icon=icon_name, action=action)) + create_item_list(document.getElementById(container_id), items, _('Change how the list of books is sorted')) +# }}} + + set_panel_handler('book_list', init) +set_panel_handler('book_list^sort', create_sort_panel) diff --git a/src/pyj/session.pyj b/src/pyj/session.pyj index 191c23a9d8..f6fa95d72a 100644 --- a/src/pyj/session.pyj +++ b/src/pyj/session.pyj @@ -8,6 +8,7 @@ defaults = { # Book list settings 'view_mode': 'cover_grid', 'sort': 'timestamp.desc', # comma separated list of items of the form: field.order + 'last_sort_order': {}, # Tag Browser settings 'partition_method': 'first letter', # other choices: 'disable', 'partition'