mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Start work on completion popups
This commit is contained in:
parent
f3b17074e9
commit
bdaa808886
@ -12,6 +12,7 @@ from book_list.prefs import PrefsPanel
|
|||||||
from book_list.book_details import BookDetailsPanel
|
from book_list.book_details import BookDetailsPanel
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from modals import error_dialog, ajax_progress_dialog
|
from modals import error_dialog, ajax_progress_dialog
|
||||||
|
from popups import install_event_filters
|
||||||
|
|
||||||
class BarState:
|
class BarState:
|
||||||
|
|
||||||
@ -88,6 +89,7 @@ class UI:
|
|||||||
ROOT_PANEL = 'books'
|
ROOT_PANEL = 'books'
|
||||||
|
|
||||||
def __init__(self, interface_data, book_list_container):
|
def __init__(self, interface_data, book_list_container):
|
||||||
|
install_event_filters()
|
||||||
self.top_bar = TopBar(book_list_container)
|
self.top_bar = TopBar(book_list_container)
|
||||||
self.books_view = BooksView(interface_data, book_list_container)
|
self.books_view = BooksView(interface_data, book_list_container)
|
||||||
self.items_view = ItemsView(interface_data, book_list_container)
|
self.items_view = ItemsView(interface_data, book_list_container)
|
||||||
|
@ -91,3 +91,14 @@ def element(elem_id, child_selector):
|
|||||||
if child_selector:
|
if child_selector:
|
||||||
ans = ans.querySelector(child_selector)
|
ans = ans.querySelector(child_selector)
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
auto_id_count = 0
|
||||||
|
|
||||||
|
def ensure_id(w):
|
||||||
|
nonlocal auto_id_count
|
||||||
|
ans = w.getAttribute('id')
|
||||||
|
if not ans:
|
||||||
|
auto_id_count += 1
|
||||||
|
ans = 'auto-id-' + auto_id_count
|
||||||
|
w.setAttribute('id', ans)
|
||||||
|
return ans
|
||||||
|
@ -7,6 +7,7 @@ from elementmaker import E
|
|||||||
from dom import set_css, clear, build_rule, svgicon
|
from dom import set_css, clear, build_rule, svgicon
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from book_list.theme import get_color, get_font_size
|
from book_list.theme import get_color, get_font_size
|
||||||
|
from popups import MODAL_Z_INDEX
|
||||||
|
|
||||||
modal_container = None
|
modal_container = None
|
||||||
modal_count = 0
|
modal_count = 0
|
||||||
@ -43,7 +44,7 @@ class ModalContainer:
|
|||||||
# Container style
|
# Container style
|
||||||
set_css(div,
|
set_css(div,
|
||||||
position='fixed', top='0', right='0', bottom='0', left='0', # Stretch over entire window
|
position='fixed', top='0', right='0', bottom='0', left='0', # Stretch over entire window
|
||||||
background_color='rgba(0,0,0,0.8)', z_index='1000',
|
background_color='rgba(0,0,0,0.8)', z_index=MODAL_Z_INDEX + '',
|
||||||
display='none', text_align='center', user_select='none'
|
display='none', text_align='center', user_select='none'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
109
src/pyj/popups.pyj
Normal file
109
src/pyj/popups.pyj
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# 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 set_css, ensure_id
|
||||||
|
from elementmaker import E
|
||||||
|
|
||||||
|
MODAL_Z_INDEX = 1000
|
||||||
|
POPUP_Z_INDEX = MODAL_Z_INDEX + 1
|
||||||
|
popup_count = 0
|
||||||
|
|
||||||
|
shown_popups = set()
|
||||||
|
associated_widgets = {}
|
||||||
|
|
||||||
|
def element_contains_click_event(element, event):
|
||||||
|
r = element.getBoundingClientRect()
|
||||||
|
return r.left <= event.clientX <= r.right and r.top <= event.clientY <= r.bottom
|
||||||
|
|
||||||
|
def check_for_open_popups(event):
|
||||||
|
if not shown_popups.length:
|
||||||
|
return False
|
||||||
|
for popup_id in shown_popups:
|
||||||
|
popup = document.getElementById(popup_id)
|
||||||
|
if element_contains_click_event(popup, event):
|
||||||
|
return False
|
||||||
|
w = associated_widgets[popup_id]
|
||||||
|
if w and w.length:
|
||||||
|
for wid in w:
|
||||||
|
widget = document.getElementById(wid)
|
||||||
|
if element_contains_click_event(widget, event):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def filter_clicks(event):
|
||||||
|
if check_for_open_popups(event):
|
||||||
|
event.stopPropagation(), event.preventDefault()
|
||||||
|
for popup in list(shown_popups):
|
||||||
|
hide_popup(popup.getAttribute('id'))
|
||||||
|
|
||||||
|
def install_event_filters():
|
||||||
|
window.addEventListener('click', filter_clicks, True)
|
||||||
|
|
||||||
|
def create_popup(parent, idprefix):
|
||||||
|
nonlocal popup_count
|
||||||
|
popup_count += 1
|
||||||
|
pid = (idprefix or 'popup') + '-' + popup_count
|
||||||
|
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
|
||||||
|
|
||||||
|
def show_popup(popup_id, *associated_widget_ids):
|
||||||
|
elem = document.getElementById(popup_id)
|
||||||
|
elem.style.display = 'block'
|
||||||
|
shown_popups.add(popup_id)
|
||||||
|
associated_widgets[popup_id] = set()
|
||||||
|
for aid in associated_widget_ids:
|
||||||
|
associated_widgets[popup_id].add(aid)
|
||||||
|
|
||||||
|
def hide_popup(popup_id):
|
||||||
|
elem = document.getElementById(popup_id)
|
||||||
|
elem.style.display = 'none'
|
||||||
|
shown_popups.discard(popup_id)
|
||||||
|
v'delete associated_widgets[popup_id]'
|
||||||
|
|
||||||
|
class CompletionPopup:
|
||||||
|
|
||||||
|
def __init__(self, parent=None, max_items=25):
|
||||||
|
self.max_items = max_items
|
||||||
|
self.container_id = create_popup(parent)
|
||||||
|
self.items = []
|
||||||
|
c = self.container
|
||||||
|
set_css(c, user_select='none')
|
||||||
|
self.associated_widget_ids = set()
|
||||||
|
self.current_query, self.is_upwards = '', False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def container(self):
|
||||||
|
return document.getElementById(self.container_id)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_visible(self):
|
||||||
|
return self.container.style.display is not 'none'
|
||||||
|
|
||||||
|
def set_all_items(self, items):
|
||||||
|
self.items = items
|
||||||
|
|
||||||
|
def add_associated_widget(self, widget_or_id):
|
||||||
|
if type(widget_or_id) is not 'string':
|
||||||
|
widget_or_id = ensure_id(widget_or_id)
|
||||||
|
self.associated_widget_ids.add(widget_or_id)
|
||||||
|
|
||||||
|
def show_at_widget(self, w):
|
||||||
|
br = w.getBoundingClientRect()
|
||||||
|
if br.top > window.innerHeight - br.bottom:
|
||||||
|
y, upwards = br.top, True
|
||||||
|
else:
|
||||||
|
y, upwards = br.bottom, False
|
||||||
|
self.show_at(br.left, y, br.width, upwards)
|
||||||
|
|
||||||
|
def show_at(self, x, y, width, upwards):
|
||||||
|
self.is_upwards = upwards
|
||||||
|
c = self.container
|
||||||
|
cs = c.style
|
||||||
|
cs.left = x + 'px'
|
||||||
|
cs.top = 'auto' if upwards else y + 'px'
|
||||||
|
cs.bottom = y + 'px' if upwards else 'auto'
|
||||||
|
cs.width = width + 'px'
|
||||||
|
show_popup(self.container_id, *self.associated_widget_ids)
|
Loading…
x
Reference in New Issue
Block a user