mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
Finish up EditWithComplete
This commit is contained in:
parent
7c0d90f7b4
commit
a585b65f3b
@ -13,8 +13,7 @@ class EditWithComplete:
|
|||||||
inpt = E.input(type=input_type, name=name, title=tooltip or '', placeholder=placeholder or '')
|
inpt = E.input(type=input_type, name=name, title=tooltip or '', placeholder=placeholder or '')
|
||||||
self.input_id = ensure_id(inpt)
|
self.input_id = ensure_id(inpt)
|
||||||
self.onenterkey = onenterkey
|
self.onenterkey = onenterkey
|
||||||
self.completion_popup = CompletionPopup(parent=parent)
|
self.completion_popup = CompletionPopup(parent=parent, onselect=self.apply_completion)
|
||||||
self.ignore_next_input = False
|
|
||||||
inpt.addEventListener('keydown', self.onkeydown)
|
inpt.addEventListener('keydown', self.onkeydown)
|
||||||
inpt.addEventListener('input', self.oninput)
|
inpt.addEventListener('input', self.oninput)
|
||||||
self.completion_popup.add_associated_widget(inpt)
|
self.completion_popup.add_associated_widget(inpt)
|
||||||
@ -25,10 +24,12 @@ class EditWithComplete:
|
|||||||
def text_input(self):
|
def text_input(self):
|
||||||
return document.getElementById(self.input_id)
|
return document.getElementById(self.input_id)
|
||||||
|
|
||||||
def apply_completion(self):
|
def apply_completion(self, text):
|
||||||
self.ignore_next_input = True
|
if text:
|
||||||
text = self.completion_popup.current_text
|
ti = self.text_input
|
||||||
self.text_input.value = text
|
ti.value = text
|
||||||
|
ti.focus()
|
||||||
|
return True
|
||||||
|
|
||||||
def onkeydown(self, event):
|
def onkeydown(self, event):
|
||||||
k = get_key(event)
|
k = get_key(event)
|
||||||
@ -38,19 +39,19 @@ class EditWithComplete:
|
|||||||
if k is 'enter':
|
if k is 'enter':
|
||||||
if self.onenterkey:
|
if self.onenterkey:
|
||||||
event.preventDefault(), event.stopPropagation()
|
event.preventDefault(), event.stopPropagation()
|
||||||
self.enter_pressed()
|
self.onenterkey()
|
||||||
elif k is 'tab':
|
elif k is 'tab':
|
||||||
if self.completion_popup.is_visible:
|
if self.completion_popup.is_visible:
|
||||||
self.apply_completion()
|
if self.apply_completion(self.completion_popup.current_text):
|
||||||
|
self.completion_popup.hide()
|
||||||
|
else:
|
||||||
|
self.completion_popup.move_highlight()
|
||||||
event.preventDefault(), event.stopPropagation()
|
event.preventDefault(), event.stopPropagation()
|
||||||
|
|
||||||
def oninput(self, event):
|
def oninput(self, event):
|
||||||
if self.ignore_next_input:
|
ti = self.text_input
|
||||||
self.ignore_next_input = False
|
self.completion_popup.set_query(ti.value or '')
|
||||||
else:
|
self.completion_popup.popup(ti)
|
||||||
ti = self.text_input
|
|
||||||
self.completion_popup.set_query(ti.value or '')
|
|
||||||
self.completion_popup.popup(ti)
|
|
||||||
|
|
||||||
def hide_completion_popup(self):
|
def hide_completion_popup(self):
|
||||||
self.completion_popup.hide()
|
self.completion_popup.hide()
|
||||||
@ -65,7 +66,7 @@ class EditWithComplete:
|
|||||||
def create_search_bar(action, name, tooltip=None, placeholder=None, button=None):
|
def create_search_bar(action, name, tooltip=None, placeholder=None, button=None):
|
||||||
|
|
||||||
parent = E.div()
|
parent = E.div()
|
||||||
ewc = EditWithComplete(name, parent=parent, tooltip=tooltip, placeholder=placeholder)
|
ewc = EditWithComplete(name, parent=parent, tooltip=tooltip, placeholder=placeholder, input_type='search')
|
||||||
|
|
||||||
def trigger():
|
def trigger():
|
||||||
ewc.hide_completion_popup()
|
ewc.hide_completion_popup()
|
||||||
|
@ -32,11 +32,11 @@ def click_in_popup(event):
|
|||||||
|
|
||||||
def filter_clicks(event):
|
def filter_clicks(event):
|
||||||
if shown_popups.length:
|
if shown_popups.length:
|
||||||
event.stopPropagation(), event.preventDefault()
|
|
||||||
if not click_in_popup(event):
|
if not click_in_popup(event):
|
||||||
for popup_id in shown_popups:
|
for popup_id in shown_popups:
|
||||||
hide_popup(popup_id)
|
hide_popup(popup_id)
|
||||||
shown_popups.clear()
|
shown_popups.clear()
|
||||||
|
event.stopPropagation(), event.preventDefault()
|
||||||
|
|
||||||
def install_event_filters():
|
def install_event_filters():
|
||||||
window.addEventListener('click', filter_clicks, True)
|
window.addEventListener('click', filter_clicks, True)
|
||||||
@ -66,14 +66,15 @@ class CompletionPopup:
|
|||||||
CLASS = 'popup-completion-items'
|
CLASS = 'popup-completion-items'
|
||||||
CURRENT_ITEM_CLASS = 'popup-completion-current-item'
|
CURRENT_ITEM_CLASS = 'popup-completion-current-item'
|
||||||
|
|
||||||
def __init__(self, parent=None, max_items=25):
|
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)
|
self.container_id = create_popup(parent)
|
||||||
|
self.onselect = onselect
|
||||||
self.items = []
|
self.items = []
|
||||||
self.matches = []
|
self.matches = []
|
||||||
c = self.container
|
c = self.container
|
||||||
set_css(c, user_select='none')
|
set_css(c, user_select='none')
|
||||||
c.appendChild(E.div(class_=self.CLASS, onclick=self._item_clicked))
|
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
|
||||||
self.applied_query = self.current_query
|
self.applied_query = self.current_query
|
||||||
@ -120,38 +121,41 @@ class CompletionPopup:
|
|||||||
|
|
||||||
def hide(self):
|
def hide(self):
|
||||||
self.container.style.display = 'none'
|
self.container.style.display = 'none'
|
||||||
|
c = self.current_item
|
||||||
def highlight_up(self):
|
if c:
|
||||||
self.move_highlight(True)
|
c.classList.remove(self.CURRENT_ITEM_CLASS)
|
||||||
|
|
||||||
def highlight_down(self):
|
|
||||||
self.move_highlight(False)
|
|
||||||
|
|
||||||
def handle_keydown(self, key):
|
def handle_keydown(self, key):
|
||||||
if key is 'escape':
|
if key is 'escape':
|
||||||
self.hide()
|
self.hide()
|
||||||
return True
|
return True
|
||||||
if key is 'up':
|
if key is 'up':
|
||||||
self.highlight_up()
|
self.move_highlight(True)
|
||||||
return True
|
return True
|
||||||
if key is 'down':
|
if key is 'down':
|
||||||
self.highlight_down()
|
self.move_highlight(False)
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_item(self):
|
def current_item(self):
|
||||||
c = self.container
|
c = self.container
|
||||||
return c.querySelector('{} > div.{}'.format(self.CLASS, self.CURRENT_ITEM_CLASS))
|
return c.querySelector('div.{} > div.{}'.format(self.CLASS, self.CURRENT_ITEM_CLASS))
|
||||||
|
|
||||||
def move_highlight(self, up=True):
|
@property
|
||||||
|
def current_text(self):
|
||||||
|
return self.current_item?.textContent
|
||||||
|
|
||||||
|
def move_highlight(self, up=None):
|
||||||
|
if up is None:
|
||||||
|
up = self.is_upwards
|
||||||
ans = None
|
ans = None
|
||||||
div = self.current_item
|
div = self.current_item
|
||||||
if div:
|
if div:
|
||||||
div.classList.remove(self.CURRENT_ITEM_CLASS)
|
div.classList.remove(self.CURRENT_ITEM_CLASS)
|
||||||
ans = div.previousSibling if up else div.nextSibling
|
ans = div.previousSibling if up else div.nextSibling
|
||||||
if not ans:
|
if not ans:
|
||||||
c = self.container
|
c = self.container.firstChild
|
||||||
ans = c.lastChild if up else c.firstChild
|
ans = c.lastChild if up else c.firstChild
|
||||||
if ans:
|
if ans:
|
||||||
ans.classList.add(self.CURRENT_ITEM_CLASS)
|
ans.classList.add(self.CURRENT_ITEM_CLASS)
|
||||||
@ -188,18 +192,28 @@ class CompletionPopup:
|
|||||||
if self.is_upwards:
|
if self.is_upwards:
|
||||||
items = reversed(items)
|
items = reversed(items)
|
||||||
for m in items:
|
for m in items:
|
||||||
c.firstChild.appendChild(E.div(m))
|
c.firstChild.appendChild(E.div(m, onmouseenter=self.onmouseenter, onclick=self.onclick))
|
||||||
|
|
||||||
def _item_clicked(self, ev):
|
def onmouseenter(self, event):
|
||||||
self.hide()
|
div = self.current_item
|
||||||
|
if div:
|
||||||
|
div.classList.remove(self.CURRENT_ITEM_CLASS)
|
||||||
|
event.currentTarget.classList.add(self.CURRENT_ITEM_CLASS)
|
||||||
|
|
||||||
|
def onclick(self, event):
|
||||||
|
self.onmouseenter(event)
|
||||||
|
try:
|
||||||
|
if self.onselect:
|
||||||
|
self.onselect(self.current_text)
|
||||||
|
finally:
|
||||||
|
self.hide()
|
||||||
|
|
||||||
add_extra_css(def():
|
add_extra_css(def():
|
||||||
sel = 'div.' + CompletionPopup.CLASS
|
sel = 'div.' + CompletionPopup.CLASS
|
||||||
style = build_rule(sel, background_color=get_color('window-background'),
|
style = build_rule(sel, overflow='hidden', background_color=get_color('window-background'), border='solid 1px ' + get_color('window-foreground'))
|
||||||
border='solid 1px ' + get_color('window-foreground'))
|
|
||||||
sel += ' > div'
|
sel += ' > div'
|
||||||
style += build_rule(sel, cursor='pointer', margin='1ex 1rem')
|
style += build_rule(sel, cursor='pointer', padding='1ex 1rem', white_space='nowrap', text_overflow='ellipsis', overflow='hidden')
|
||||||
sel += ' > div.' + CompletionPopup.CURRENT_ITEM_CLASS
|
sel += '.' + CompletionPopup.CURRENT_ITEM_CLASS
|
||||||
style += build_rule(sel, color=get_color('list-hover-foreground'), background_color=get_color('list-hover-background'))
|
style += build_rule(sel, color=get_color('list-hover-foreground'), background_color=get_color('list-hover-background'))
|
||||||
return style
|
return style
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user