mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add history to the search bar widget
This commit is contained in:
parent
4815820f9b
commit
7852aa3eac
@ -3,6 +3,7 @@
|
|||||||
from __python__ import hash_literals
|
from __python__ import hash_literals
|
||||||
|
|
||||||
from ajax import ajax
|
from ajax import ajax
|
||||||
|
from complete import create_search_bar
|
||||||
from dom import clear, set_css, build_rule, svgicon, add_extra_css
|
from dom import clear, set_css, build_rule, svgicon, add_extra_css
|
||||||
from elementmaker import E
|
from elementmaker import E
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
@ -56,15 +57,10 @@ class SearchPanel:
|
|||||||
|
|
||||||
# Build search input
|
# Build search input
|
||||||
search_container = div.firstChild
|
search_container = div.firstChild
|
||||||
search_button = create_button(_('Search'), icon='search', action=self.execute_search.bind(self), tooltip=_('Do the search'))
|
search_button = create_button(_('Search'), icon='search', tooltip=_('Do the search'))
|
||||||
search_container.appendChild(E.div(style="display: flex; width: 100%;",
|
search_bar = create_search_bar(self.execute_search.bind(self), 'search-books', tooltip=_('Search for books'), placeholder=_('Enter the search query'), button=search_button)
|
||||||
E.input(
|
set_css(search_bar, flex_grow='10', margin_right='0.5em')
|
||||||
type='search', name='search-books',
|
search_container.appendChild(E.div(style="display: flex; width: 100%;", search_bar, search_button))
|
||||||
title=_('Search for books'), placeholder=_('Enter the search query'),
|
|
||||||
style="flex-grow: 10; margin-right: 0.5em", onkeydown=self.on_input_keydown.bind(self),
|
|
||||||
),
|
|
||||||
search_button
|
|
||||||
))
|
|
||||||
search_container.appendChild(E.ul(class_='search-items'))
|
search_container.appendChild(E.ul(class_='search-items'))
|
||||||
|
|
||||||
# Build loading panel
|
# Build loading panel
|
||||||
@ -80,12 +76,6 @@ class SearchPanel:
|
|||||||
self.node_id_map = {}
|
self.node_id_map = {}
|
||||||
self.active_nodes = {}
|
self.active_nodes = {}
|
||||||
|
|
||||||
def on_input_keydown(self, event):
|
|
||||||
if event.keyCode is 13: # Enter
|
|
||||||
event.preventDefault(), event.stopPropagation()
|
|
||||||
event.target.nextSibling.focus()
|
|
||||||
self.execute_search()
|
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
tb = self.search_control
|
tb = self.search_control
|
||||||
# We dont focus the search box because on mobile that will cause the
|
# We dont focus the search box because on mobile that will cause the
|
||||||
|
@ -5,7 +5,9 @@ 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 keycodes import get_key
|
from keycodes import get_key
|
||||||
|
from session import local_storage
|
||||||
from popups import CompletionPopup
|
from popups import CompletionPopup
|
||||||
|
from utils import uniq
|
||||||
|
|
||||||
class EditWithComplete:
|
class EditWithComplete:
|
||||||
|
|
||||||
@ -63,14 +65,30 @@ class EditWithComplete:
|
|||||||
self.completion_popup.set_all_items(items)
|
self.completion_popup.set_all_items(items)
|
||||||
|
|
||||||
|
|
||||||
def create_search_bar(action, name, tooltip=None, placeholder=None, button=None):
|
def create_search_bar(action, name, tooltip=None, placeholder=None, button=None, history_size=100):
|
||||||
|
parent = E.div(style="display:flex")
|
||||||
parent = E.div()
|
|
||||||
ewc = EditWithComplete(name, parent=parent, tooltip=tooltip, placeholder=placeholder, input_type='search')
|
ewc = EditWithComplete(name, parent=parent, tooltip=tooltip, placeholder=placeholder, input_type='search')
|
||||||
|
parent.lastChild.style.width = '100%'
|
||||||
|
history_name = 'search-bar-history-' + name
|
||||||
|
|
||||||
|
def update_completion_items():
|
||||||
|
items = local_storage().get(history_name)
|
||||||
|
if items?.length:
|
||||||
|
ewc.set_all_items(items)
|
||||||
|
update_completion_items()
|
||||||
|
|
||||||
def trigger():
|
def trigger():
|
||||||
|
text = ewc.text_input.value
|
||||||
ewc.hide_completion_popup()
|
ewc.hide_completion_popup()
|
||||||
action()
|
action(text)
|
||||||
|
if text and text.strip():
|
||||||
|
items = local_storage().get(history_name) or v'[]'
|
||||||
|
idx = items.indexOf(text)
|
||||||
|
if idx > -1:
|
||||||
|
items = items.splice(idx, 1)
|
||||||
|
items.unshift(text)
|
||||||
|
local_storage().set(history_name, uniq(items[:history_size]))
|
||||||
|
update_completion_items()
|
||||||
ewc.onenterkey = trigger
|
ewc.onenterkey = trigger
|
||||||
|
|
||||||
if button:
|
if button:
|
||||||
@ -81,6 +99,8 @@ def create_search_bar(action, name, tooltip=None, placeholder=None, button=None)
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
def main(container):
|
def main(container):
|
||||||
ewc = EditWithComplete(parent=container, placeholder='Testing edit with complete')
|
container.appendChild(create_search_bar(print, 'test-search-bar', placeholder='Testing search bar'))
|
||||||
ewc.set_all_items('a a1 a11 a12 a13 b b1 b2 b3'.split(' '))
|
container.firstChild.lastChild.focus()
|
||||||
ewc.text_input.focus()
|
# ewc = EditWithComplete(parent=container, placeholder='Testing edit with complete')
|
||||||
|
# ewc.set_all_items('a a1 a11 a12 a13 b b1 b2 b3'.split(' '))
|
||||||
|
# ewc.text_input.focus()
|
||||||
|
@ -48,7 +48,7 @@ def create_popup(parent, idprefix):
|
|||||||
div = E.div(id=pid, style='display: none; position: absolute; z-index: {}'.format(POPUP_Z_INDEX))
|
div = E.div(id=pid, style='display: none; position: absolute; z-index: {}'.format(POPUP_Z_INDEX))
|
||||||
parent = parent or document.body
|
parent = parent or document.body
|
||||||
parent.appendChild(div)
|
parent.appendChild(div)
|
||||||
return pid
|
return div
|
||||||
|
|
||||||
def show_popup(popup_id, associated_widget_ids=None):
|
def show_popup(popup_id, associated_widget_ids=None):
|
||||||
elem = document.getElementById(popup_id)
|
elem = document.getElementById(popup_id)
|
||||||
@ -68,12 +68,12 @@ class CompletionPopup:
|
|||||||
|
|
||||||
def __init__(self, parent=None, max_items=25, onselect=None):
|
def __init__(self, parent=None, max_items=25, onselect=None):
|
||||||
self.max_items = max_items
|
self.max_items = max_items
|
||||||
self.container_id = create_popup(parent)
|
c = create_popup(parent)
|
||||||
|
set_css(c, user_select='none')
|
||||||
|
self.container_id = c.getAttribute('id')
|
||||||
self.onselect = onselect
|
self.onselect = onselect
|
||||||
self.items = []
|
self.items = []
|
||||||
self.matches = []
|
self.matches = []
|
||||||
c = self.container
|
|
||||||
set_css(c, user_select='none')
|
|
||||||
c.appendChild(E.div(class_=self.CLASS))
|
c.appendChild(E.div(class_=self.CLASS))
|
||||||
self.associated_widget_ids = set()
|
self.associated_widget_ids = set()
|
||||||
self.current_query, self.is_upwards = '', False
|
self.current_query, self.is_upwards = '', False
|
||||||
@ -88,7 +88,7 @@ class CompletionPopup:
|
|||||||
return self.container.style.display is not 'none'
|
return self.container.style.display is not 'none'
|
||||||
|
|
||||||
def set_all_items(self, items):
|
def set_all_items(self, items):
|
||||||
self.items = items
|
self.items = list(items)
|
||||||
self.matches = []
|
self.matches = []
|
||||||
self.applied_query = ''
|
self.applied_query = ''
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ class CompletionPopup:
|
|||||||
|
|
||||||
add_extra_css(def():
|
add_extra_css(def():
|
||||||
sel = 'div.' + CompletionPopup.CLASS
|
sel = 'div.' + CompletionPopup.CLASS
|
||||||
style = build_rule(sel, overflow='hidden', background_color=get_color('window-background'), border='solid 1px ' + get_color('window-foreground'))
|
style = build_rule(sel, overflow='hidden', text_align='left', background_color=get_color('window-background'), border='solid 1px ' + get_color('window-foreground'))
|
||||||
sel += ' > div'
|
sel += ' > div'
|
||||||
style += build_rule(sel, cursor='pointer', padding='1ex 1rem', white_space='nowrap', text_overflow='ellipsis', overflow='hidden')
|
style += build_rule(sel, cursor='pointer', padding='1ex 1rem', white_space='nowrap', text_overflow='ellipsis', overflow='hidden')
|
||||||
sel += '.' + CompletionPopup.CURRENT_ITEM_CLASS
|
sel += '.' + CompletionPopup.CURRENT_ITEM_CLASS
|
||||||
|
@ -72,9 +72,8 @@ def get_session_storage():
|
|||||||
|
|
||||||
class SessionData:
|
class SessionData:
|
||||||
|
|
||||||
global_prefix = 'calibre-'
|
def __init__(self, global_prefix=None):
|
||||||
|
self.global_prefix = global_prefix or 'calibre-session-'
|
||||||
def __init__(self):
|
|
||||||
self.storage = get_session_storage()
|
self.storage = get_session_storage()
|
||||||
self.overflow_storage = {}
|
self.overflow_storage = {}
|
||||||
self.has_overflow = False
|
self.has_overflow = False
|
||||||
@ -115,6 +114,13 @@ class SessionData:
|
|||||||
self.overflow_storage = {}
|
self.overflow_storage = {}
|
||||||
self.has_overflow = False
|
self.has_overflow = False
|
||||||
|
|
||||||
|
_local_storage = None
|
||||||
|
def local_storage():
|
||||||
|
nonlocal _local_storage
|
||||||
|
if not _local_storage:
|
||||||
|
_local_storage = SessionData('calibre-local-')
|
||||||
|
return _local_storage
|
||||||
|
|
||||||
class UserSessionData(SessionData):
|
class UserSessionData(SessionData):
|
||||||
|
|
||||||
def __init__(self, username, saved_data):
|
def __init__(self, username, saved_data):
|
||||||
|
@ -131,6 +131,16 @@ def viewport_to_document(x, y, doc):
|
|||||||
def username_key(username):
|
def username_key(username):
|
||||||
return ('u' if username else 'n') + username
|
return ('u' if username else 'n') + username
|
||||||
|
|
||||||
|
def uniq(vals):
|
||||||
|
# Remove all duplicates from vals, while preserving order
|
||||||
|
ans = v'[]'
|
||||||
|
seen = {}
|
||||||
|
for x in vals:
|
||||||
|
if not seen[x]:
|
||||||
|
seen[x] = True
|
||||||
|
ans.push(x)
|
||||||
|
return ans
|
||||||
|
|
||||||
if __name__ is '__main__':
|
if __name__ is '__main__':
|
||||||
print(fmt_sidx(10), fmt_sidx(1.2))
|
print(fmt_sidx(10), fmt_sidx(1.2))
|
||||||
print(list(map(human_readable, [1, 1024.0, 1025, 1024*1024*2.3])))
|
print(list(map(human_readable, [1, 1024.0, 1025, 1024*1024*2.3])))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user