Start work on completion popups

This commit is contained in:
Kovid Goyal 2016-06-14 09:08:54 +05:30
parent f3b17074e9
commit bdaa808886
4 changed files with 124 additions and 1 deletions

View File

@ -12,6 +12,7 @@ from book_list.prefs import PrefsPanel
from book_list.book_details import BookDetailsPanel
from gettext import gettext as _
from modals import error_dialog, ajax_progress_dialog
from popups import install_event_filters
class BarState:
@ -88,6 +89,7 @@ class UI:
ROOT_PANEL = 'books'
def __init__(self, interface_data, book_list_container):
install_event_filters()
self.top_bar = TopBar(book_list_container)
self.books_view = BooksView(interface_data, book_list_container)
self.items_view = ItemsView(interface_data, book_list_container)

View File

@ -91,3 +91,14 @@ def element(elem_id, child_selector):
if child_selector:
ans = ans.querySelector(child_selector)
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

View File

@ -7,6 +7,7 @@ from elementmaker import E
from dom import set_css, clear, build_rule, svgicon
from gettext import gettext as _
from book_list.theme import get_color, get_font_size
from popups import MODAL_Z_INDEX
modal_container = None
modal_count = 0
@ -43,7 +44,7 @@ class ModalContainer:
# Container style
set_css(div,
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'
)

109
src/pyj/popups.pyj Normal file
View 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)