mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Re-implement sorting of the books list
Now the sort is made part of the URL
This commit is contained in:
parent
12f93be515
commit
6e6cadf996
@ -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()
|
||||
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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'
|
||||
|
Loading…
x
Reference in New Issue
Block a user