mirror of
https://github.com/kovidgoyal/calibre.git
synced 2026-01-10 06:00:21 -05:00
187 lines
7.0 KiB
Plaintext
187 lines
7.0 KiB
Plaintext
# vim:fileencoding=utf-8
|
|
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
from __python__ import hash_literals, bound_methods
|
|
|
|
from dom import ensure_id, unique_id, clear
|
|
from elementmaker import E
|
|
from session import local_storage
|
|
from popups import CompletionPopup
|
|
from utils import uniq
|
|
|
|
class EditWithComplete:
|
|
|
|
def __init__(self, name, placeholder=None, tooltip=None, parent=None, input_type='text', onenterkey=None):
|
|
inpt = E.input(type=input_type, name=name, title=tooltip or '', placeholder=placeholder or '', autocomplete='off')
|
|
self.input_id = ensure_id(inpt)
|
|
self.onenterkey = onenterkey
|
|
self.completion_popup = CompletionPopup(parent=parent, onselect=self.apply_completion)
|
|
inpt.addEventListener('keydown', self.onkeydown)
|
|
inpt.addEventListener('input', self.oninput)
|
|
self.completion_popup.add_associated_widget(inpt)
|
|
if parent:
|
|
parent.appendChild(inpt)
|
|
|
|
@property
|
|
def text_input(self):
|
|
return document.getElementById(self.input_id)
|
|
|
|
def apply_completion(self, text):
|
|
if text:
|
|
ti = self.text_input
|
|
ti.value = text
|
|
ti.focus()
|
|
return True
|
|
|
|
def onkeydown(self, event):
|
|
if self.completion_popup.is_visible and self.completion_popup.handle_keydown(event):
|
|
event.preventDefault(), event.stopPropagation()
|
|
return
|
|
if event.key is 'Enter':
|
|
if self.completion_popup.is_visible:
|
|
if self.apply_completion(self.completion_popup.current_text):
|
|
self.completion_popup.hide()
|
|
event.preventDefault(), event.stopPropagation()
|
|
return
|
|
if self.onenterkey:
|
|
event.preventDefault(), event.stopPropagation()
|
|
self.onenterkey()
|
|
elif event.key is 'Tab':
|
|
if self.completion_popup.is_visible:
|
|
if self.apply_completion(self.completion_popup.current_text):
|
|
self.completion_popup.hide()
|
|
else:
|
|
self.completion_popup.move_highlight()
|
|
event.preventDefault(), event.stopPropagation()
|
|
elif event.key is 'ArrowDown':
|
|
ti = self.text_input
|
|
if not ti.value:
|
|
self.completion_popup.set_query('')
|
|
self.completion_popup.popup(ti)
|
|
event.preventDefault(), event.stopPropagation()
|
|
|
|
def oninput(self, event):
|
|
ti = self.text_input
|
|
self.completion_popup.set_query(ti.value or '')
|
|
self.completion_popup.popup(ti)
|
|
|
|
def hide_completion_popup(self):
|
|
self.completion_popup.hide()
|
|
|
|
def add_associated_widget(self, widget_or_id):
|
|
self.completion_popup.add_associated_widget(widget_or_id)
|
|
|
|
def set_all_items(self, items):
|
|
self.completion_popup.set_all_items(items)
|
|
|
|
|
|
def create_search_bar(action, name, tooltip=None, placeholder=None, button=None, history_size=100, associated_widgets=None):
|
|
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(text)
|
|
if text and text.strip():
|
|
items = local_storage().get(history_name) or v'[]'
|
|
idx = items.indexOf(text)
|
|
if idx > -1:
|
|
items.splice(idx, 1)
|
|
items.unshift(text)
|
|
local_storage().set(history_name, uniq(items[:history_size]))
|
|
update_completion_items()
|
|
ewc.onenterkey = trigger
|
|
parent.querySelector('input').addEventListener('search', trigger)
|
|
|
|
if button:
|
|
ewc.add_associated_widget(button)
|
|
button.addEventListener('click', trigger)
|
|
if associated_widgets is not None:
|
|
for w in associated_widgets:
|
|
ewc.add_associated_widget(w)
|
|
return parent
|
|
|
|
|
|
def create_simple_input_with_history_native(name, tooltip=None, placeholder=None, history_size=100, input_type='text'):
|
|
# cannot use in standalone viewer because of: https://bugreports.qt.io/browse/QTBUG-54433
|
|
# fixed in Qt 6.4.0
|
|
dl_id = unique_id()
|
|
dl = document.createElement('datalist')
|
|
dl.id = dl_id
|
|
history_name = f'simple_input_history_{name}'
|
|
|
|
def update_completion_items(x):
|
|
items = local_storage().get(history_name)
|
|
dl = x or document.getElementById(dl_id)
|
|
if dl:
|
|
clear(dl)
|
|
if items?.length:
|
|
for item in items:
|
|
dl.appendChild(E.option(value=item))
|
|
|
|
def save_completion_items():
|
|
text = document.getElementById(dl_id).nextSibling.value
|
|
if text and text.strip():
|
|
items = local_storage().get(history_name) or v'[]'
|
|
idx = items.indexOf(text)
|
|
if idx > -1:
|
|
items.splice(idx, 1)
|
|
items.unshift(text)
|
|
local_storage().set(history_name, uniq(items[:history_size]))
|
|
update_completion_items()
|
|
|
|
update_completion_items(dl)
|
|
ans = E.span(
|
|
data_calibre_history_input='1',
|
|
dl,
|
|
E.input(type=input_type, name=name, list=dl_id, title=tooltip or '', placeholder=placeholder or ''),
|
|
)
|
|
ans.addEventListener('save_history', save_completion_items)
|
|
return ans
|
|
|
|
|
|
def create_simple_input_with_history(name, tooltip=None, placeholder=None, history_size=100, input_type='text'):
|
|
# to use simply add the returned element to the DOM and when you want to
|
|
# save a new completion item, use dispatchEvent to send a 'save_history'
|
|
# event to it.
|
|
parent = E.span(data_calibre_history_input='1')
|
|
ewc = EditWithComplete(name, parent=parent, tooltip=tooltip, placeholder=placeholder, input_type=input_type)
|
|
history_name = f'simple_input_history_{name}'
|
|
|
|
def update_completion_items():
|
|
items = local_storage().get(history_name)
|
|
if items?.length:
|
|
ewc.set_all_items(items)
|
|
update_completion_items()
|
|
|
|
def save_completion_items():
|
|
text = ewc.text_input.value
|
|
if text and text.strip():
|
|
items = local_storage().get(history_name) or v'[]'
|
|
idx = items.indexOf(text)
|
|
if idx > -1:
|
|
items.splice(idx, 1)
|
|
items.unshift(text)
|
|
local_storage().set(history_name, uniq(items[:history_size]))
|
|
update_completion_items()
|
|
|
|
parent.addEventListener('save_history', save_completion_items)
|
|
return parent
|
|
# }}}
|
|
|
|
|
|
def main(container):
|
|
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()
|