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 session import get_interface_data
|
||||||
from utils import parse_url_params
|
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 = {}
|
library_data = {}
|
||||||
current_fetch = None
|
|
||||||
|
|
||||||
|
|
||||||
def current_library_id():
|
def url_books_query(sd):
|
||||||
return parse_url_params().library_id or get_interface_data().library_id
|
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):
|
def update_library_data(data):
|
||||||
@ -29,6 +55,11 @@ def on_data_loaded(end_type, xhr, ev):
|
|||||||
if end_type is 'load':
|
if end_type is 'load':
|
||||||
data = JSON.parse(xhr.responseText)
|
data = JSON.parse(xhr.responseText)
|
||||||
update_library_data(data)
|
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:
|
else:
|
||||||
load_status.ok = False
|
load_status.ok = False
|
||||||
load_status.loading = False
|
load_status.loading = False
|
||||||
@ -38,17 +69,16 @@ def on_data_loaded(end_type, xhr, ev):
|
|||||||
def fetch_init_data():
|
def fetch_init_data():
|
||||||
if load_status.current_fetch:
|
if load_status.current_fetch:
|
||||||
load_status.current_fetch.abort()
|
load_status.current_fetch.abort()
|
||||||
load_status.library_id = current_library_id()
|
query = url_books_query()
|
||||||
query = {'library_id': load_status.library_id}
|
load_status.loading = True
|
||||||
url_query = parse_url_params()
|
load_status.ok = False
|
||||||
for key in url_query:
|
load_status.error_html = None
|
||||||
query[key] = url_query[key]
|
|
||||||
load_status.current_fetch = ajax('interface-data/books-init', on_data_loaded, query=query)
|
load_status.current_fetch = ajax('interface-data/books-init', on_data_loaded, query=query)
|
||||||
load_status.current_fetch.send()
|
load_status.current_fetch.send()
|
||||||
|
|
||||||
|
|
||||||
def cover_url(book_id, width, height):
|
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):
|
def book_metadata(book_id):
|
||||||
@ -56,6 +86,12 @@ def book_metadata(book_id):
|
|||||||
|
|
||||||
|
|
||||||
def ensure_current_library_data():
|
def ensure_current_library_data():
|
||||||
# TODO: Handle search/sort parameters as well
|
q = url_books_query()
|
||||||
if load_status.library_id != current_library_id():
|
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()
|
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 session import get_interface_data, UserSessionData, update_interface_data, get_translations
|
||||||
from gettext import gettext as _, install
|
from gettext import gettext as _, install
|
||||||
from popups import install_event_filters
|
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.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.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.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
|
||||||
@ -77,6 +76,7 @@ def on_data_loaded(end_type, xhr, ev):
|
|||||||
if end_type is 'load':
|
if end_type is 'load':
|
||||||
data = JSON.parse(xhr.responseText)
|
data = JSON.parse(xhr.responseText)
|
||||||
update_interface_data(data)
|
update_interface_data(data)
|
||||||
|
update_library_data(data)
|
||||||
interface_data = get_interface_data()
|
interface_data = get_interface_data()
|
||||||
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)
|
||||||
@ -99,15 +99,11 @@ def on_data_load_progress(loaded, total):
|
|||||||
|
|
||||||
|
|
||||||
def load_interface_data():
|
def load_interface_data():
|
||||||
temp = UserSessionData(None, {}) # So that settings for anonymous users are preserved
|
idata = get_interface_data()
|
||||||
query = {}
|
query = {}
|
||||||
library_id = temp.get('library_id')
|
if not idata.is_default:
|
||||||
if library_id:
|
temp = UserSessionData(None, {}) # So that settings for anonymous users are preserved
|
||||||
query.library_id = library_id
|
query = url_books_query(temp)
|
||||||
query.sort = temp.get_library_option(library_id, 'sort')
|
|
||||||
url_query = parse_url_params()
|
|
||||||
for key in url_query:
|
|
||||||
query[key] = url_query[key]
|
|
||||||
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()
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ 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
|
from book_list.router import push_state
|
||||||
from book_list.library_data import current_library_id
|
|
||||||
|
|
||||||
|
|
||||||
panel_handlers = {}
|
panel_handlers = {}
|
||||||
@ -45,13 +44,13 @@ def currently_showing_panel():
|
|||||||
return c.dataset.panel
|
return c.dataset.panel
|
||||||
|
|
||||||
|
|
||||||
def show_panel(panel, query_data, replace=False):
|
def show_panel(panel, query=None, replace=False):
|
||||||
query = {k:query_data[k] for k in query_data}
|
if query is None:
|
||||||
|
query = {}
|
||||||
|
else:
|
||||||
|
query = {k:query[k] for k in query if k is not 'panel'}
|
||||||
if panel is not 'home':
|
if panel is not 'home':
|
||||||
query.panel = panel
|
query.panel = panel
|
||||||
lid = current_library_id()
|
|
||||||
if lid:
|
|
||||||
query.library_id = lid
|
|
||||||
push_state(query, replace=replace)
|
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.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.top_bar import create_top_bar, add_button
|
||||||
from book_list.router import back
|
from book_list.router import back
|
||||||
from book_list.ui import set_panel_handler
|
from book_list.ui import set_panel_handler, show_panel
|
||||||
from book_list.library_data import current_library_id, load_status, ensure_current_library_data, library_data
|
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'}
|
ALLOWED_MODES = {'cover_grid'}
|
||||||
DEFAULT_MODE = 'cover_grid'
|
DEFAULT_MODE = 'cover_grid'
|
||||||
@ -76,6 +77,8 @@ def apply_view_mode(mode=DEFAULT_MODE):
|
|||||||
render_ids()
|
render_ids()
|
||||||
|
|
||||||
|
|
||||||
|
# More button {{{
|
||||||
|
|
||||||
def update_fetching_status():
|
def update_fetching_status():
|
||||||
more = document.getElementById(book_list_data.container_id).lastChild
|
more = document.getElementById(book_list_data.container_id).lastChild
|
||||||
if book_list_data.fetching_more_books:
|
if book_list_data.fetching_more_books:
|
||||||
@ -123,7 +126,7 @@ def get_more_books():
|
|||||||
data[key] = library_data.search_result[key]
|
data[key] = library_data.search_result[key]
|
||||||
book_list_data.fetching_more_books = ajax_send(
|
book_list_data.fetching_more_books = ajax_send(
|
||||||
'interface-data/more-books', data, got_more_books,
|
'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()
|
update_fetching_status()
|
||||||
|
|
||||||
@ -142,6 +145,9 @@ def create_more_button(more):
|
|||||||
update_fetching_status()
|
update_fetching_status()
|
||||||
|
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
def create_books_list(container):
|
def create_books_list(container):
|
||||||
book_list_data.container_id = ensure_id(container)
|
book_list_data.container_id = ensure_id(container)
|
||||||
book_list_data.shown_book_ids = set()
|
book_list_data.shown_book_ids = set()
|
||||||
@ -151,6 +157,7 @@ def create_books_list(container):
|
|||||||
container.appendChild(E.div()), container.appendChild(E.div())
|
container.appendChild(E.div()), container.appendChild(E.div())
|
||||||
apply_view_mode(get_session_data().get('view_mode'))
|
apply_view_mode(get_session_data().get('view_mode'))
|
||||||
create_more_button(container.lastChild)
|
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():
|
def check_for_books_loaded():
|
||||||
@ -169,7 +176,7 @@ def check_for_books_loaded():
|
|||||||
err,
|
err,
|
||||||
E.div(
|
E.div(
|
||||||
style='margin-top: 1em; border-top: solid 1px currentColor; padding-top: 1ex;',
|
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
|
return
|
||||||
@ -180,7 +187,7 @@ def init(container_id):
|
|||||||
interface_data = get_interface_data()
|
interface_data = get_interface_data()
|
||||||
ensure_current_library_data()
|
ensure_current_library_data()
|
||||||
container = document.getElementById(container_id)
|
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]
|
title = interface_data.library_map[lid]
|
||||||
create_top_bar(container_id, title=title, action=back, icon='home')
|
create_top_bar(container_id, title=title, action=back, icon='home')
|
||||||
container.appendChild(E.div())
|
container.appendChild(E.div())
|
||||||
@ -188,4 +195,44 @@ def init(container_id):
|
|||||||
conditional_timeout(container_id, 5, check_for_books_loaded)
|
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', init)
|
||||||
|
set_panel_handler('book_list^sort', create_sort_panel)
|
||||||
|
@ -8,6 +8,7 @@ defaults = {
|
|||||||
# Book list settings
|
# Book list settings
|
||||||
'view_mode': 'cover_grid',
|
'view_mode': 'cover_grid',
|
||||||
'sort': 'timestamp.desc', # comma separated list of items of the form: field.order
|
'sort': 'timestamp.desc', # comma separated list of items of the form: field.order
|
||||||
|
'last_sort_order': {},
|
||||||
|
|
||||||
# Tag Browser settings
|
# Tag Browser settings
|
||||||
'partition_method': 'first letter', # other choices: 'disable', 'partition'
|
'partition_method': 'first letter', # other choices: 'disable', 'partition'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user