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 ajax import ajax
|
||||
from complete import create_search_bar
|
||||
from dom import clear, set_css, build_rule, svgicon, add_extra_css
|
||||
from elementmaker import E
|
||||
from gettext import gettext as _
|
||||
@ -56,15 +57,10 @@ class SearchPanel:
|
||||
|
||||
# Build search input
|
||||
search_container = div.firstChild
|
||||
search_button = create_button(_('Search'), icon='search', action=self.execute_search.bind(self), tooltip=_('Do the search'))
|
||||
search_container.appendChild(E.div(style="display: flex; width: 100%;",
|
||||
E.input(
|
||||
type='search', name='search-books',
|
||||
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_button = create_button(_('Search'), icon='search', tooltip=_('Do the search'))
|
||||
search_bar = create_search_bar(self.execute_search.bind(self), 'search-books', tooltip=_('Search for books'), placeholder=_('Enter the search query'), button=search_button)
|
||||
set_css(search_bar, flex_grow='10', margin_right='0.5em')
|
||||
search_container.appendChild(E.div(style="display: flex; width: 100%;", search_bar, search_button))
|
||||
search_container.appendChild(E.ul(class_='search-items'))
|
||||
|
||||
# Build loading panel
|
||||
@ -80,12 +76,6 @@ class SearchPanel:
|
||||
self.node_id_map = {}
|
||||
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):
|
||||
tb = self.search_control
|
||||
# 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 elementmaker import E
|
||||
from keycodes import get_key
|
||||
from session import local_storage
|
||||
from popups import CompletionPopup
|
||||
from utils import uniq
|
||||
|
||||
class EditWithComplete:
|
||||
|
||||
@ -63,14 +65,30 @@ class EditWithComplete:
|
||||
self.completion_popup.set_all_items(items)
|
||||
|
||||
|
||||
def create_search_bar(action, name, tooltip=None, placeholder=None, button=None):
|
||||
|
||||
parent = E.div()
|
||||
def create_search_bar(action, name, tooltip=None, placeholder=None, button=None, history_size=100):
|
||||
parent = E.div(style="display:flex")
|
||||
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():
|
||||
text = ewc.text_input.value
|
||||
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
|
||||
|
||||
if button:
|
||||
@ -81,6 +99,8 @@ def create_search_bar(action, name, tooltip=None, placeholder=None, button=None)
|
||||
# }}}
|
||||
|
||||
def main(container):
|
||||
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()
|
||||
container.appendChild(create_search_bar(print, 'test-search-bar', placeholder='Testing search bar'))
|
||||
container.firstChild.lastChild.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))
|
||||
parent = parent or document.body
|
||||
parent.appendChild(div)
|
||||
return pid
|
||||
return div
|
||||
|
||||
def show_popup(popup_id, associated_widget_ids=None):
|
||||
elem = document.getElementById(popup_id)
|
||||
@ -68,12 +68,12 @@ class CompletionPopup:
|
||||
|
||||
def __init__(self, parent=None, max_items=25, onselect=None):
|
||||
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.items = []
|
||||
self.matches = []
|
||||
c = self.container
|
||||
set_css(c, user_select='none')
|
||||
c.appendChild(E.div(class_=self.CLASS))
|
||||
self.associated_widget_ids = set()
|
||||
self.current_query, self.is_upwards = '', False
|
||||
@ -88,7 +88,7 @@ class CompletionPopup:
|
||||
return self.container.style.display is not 'none'
|
||||
|
||||
def set_all_items(self, items):
|
||||
self.items = items
|
||||
self.items = list(items)
|
||||
self.matches = []
|
||||
self.applied_query = ''
|
||||
|
||||
@ -210,7 +210,7 @@ class CompletionPopup:
|
||||
|
||||
add_extra_css(def():
|
||||
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'
|
||||
style += build_rule(sel, cursor='pointer', padding='1ex 1rem', white_space='nowrap', text_overflow='ellipsis', overflow='hidden')
|
||||
sel += '.' + CompletionPopup.CURRENT_ITEM_CLASS
|
||||
|
@ -72,9 +72,8 @@ def get_session_storage():
|
||||
|
||||
class SessionData:
|
||||
|
||||
global_prefix = 'calibre-'
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, global_prefix=None):
|
||||
self.global_prefix = global_prefix or 'calibre-session-'
|
||||
self.storage = get_session_storage()
|
||||
self.overflow_storage = {}
|
||||
self.has_overflow = False
|
||||
@ -115,6 +114,13 @@ class SessionData:
|
||||
self.overflow_storage = {}
|
||||
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):
|
||||
|
||||
def __init__(self, username, saved_data):
|
||||
|
@ -131,6 +131,16 @@ def viewport_to_document(x, y, doc):
|
||||
def username_key(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__':
|
||||
print(fmt_sidx(10), fmt_sidx(1.2))
|
||||
print(list(map(human_readable, [1, 1024.0, 1025, 1024*1024*2.3])))
|
||||
|
Loading…
x
Reference in New Issue
Block a user