mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-11-25 07:45:01 -05:00
150 lines
6.1 KiB
Plaintext
150 lines
6.1 KiB
Plaintext
# vim:fileencoding=utf-8
|
|
# License: GPL v3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
|
|
|
|
from elementmaker import E
|
|
from dom import set_css, clear, build_rule
|
|
from gettext import gettext as _
|
|
from book_list.theme import get_color, get_font_size
|
|
|
|
modal_container = None
|
|
|
|
class ModalContainer:
|
|
|
|
def __init__(self):
|
|
div = E.div(id='modal-container',
|
|
E.div( # popup
|
|
E.div(), # content area
|
|
E.a(E.i(class_='fa fa-close', style='vertical-align:bottom;'), title=_('Close'))
|
|
),
|
|
E.style(
|
|
build_rule(
|
|
'#modal-container > div > a:hover',
|
|
color=get_color('dialog-foreground') + ' !important',
|
|
background_color=get_color('dialog-background') + ' !important'
|
|
) +
|
|
build_rule(
|
|
'#modal-container a.dialog-simple-link:hover', color='red !important'
|
|
)
|
|
)
|
|
)
|
|
document.body.appendChild(div)
|
|
|
|
# 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',
|
|
display='none', text_align='center', user_select='none'
|
|
)
|
|
|
|
# Popup style
|
|
set_css(div.firstChild,
|
|
position='relative', display='inline-block', top='50vh', transform='translateY(-50%)',
|
|
min_width='25vw', max_width='75vw',
|
|
border_radius='1em', padding='1em 2em', margin_right='1em', margin_left='1em',
|
|
background=get_color('dialog-background'), color=get_color('dialog-foreground'),
|
|
background_image=get_color('dialog-background-image'), get_color('dialog-background'), get_color('dialog-background2')
|
|
)
|
|
|
|
# Close button style
|
|
set_css(div.firstChild.lastChild,
|
|
font_size='1.5em', line_height='100%', cursor='pointer', position='absolute',
|
|
right='-0.5em', top='-0.5em', width='1em', height='1em',
|
|
background_color=get_color('window-foreground'), color=get_color('window-background'), display='inline-box',
|
|
border_radius='50%', padding='4px', text_align='center', box_shadow='1px 1px 3px black'
|
|
)
|
|
div.firstChild.lastChild.addEventListener('click', def(event): event.preventDefault(), self.close_modal(event);)
|
|
|
|
# Content container style
|
|
set_css(div.firstChild.firstChild, user_select='text', max_height='60vh', overflow='auto')
|
|
|
|
self.modals = v'[]'
|
|
self.current_modal = None
|
|
self.hide = self.close_modal.bind(self)
|
|
|
|
@property
|
|
def modal_container(self):
|
|
return document.getElementById('modal-container')
|
|
|
|
def show_modal(self, create_func, on_close=None):
|
|
self.modals.push(v'[create_func, on_close]')
|
|
self.update()
|
|
|
|
def update(self):
|
|
if self.current_modal is None and self.modals:
|
|
self.current_modal = self.modals.shift()
|
|
c = self.modal_container
|
|
try:
|
|
self.current_modal[0](c.firstChild.firstChild, self.hide)
|
|
except:
|
|
self.current_modal = None
|
|
raise
|
|
if c.style.display == 'none':
|
|
set_css(c, display='block')
|
|
|
|
def close_modal(self, event):
|
|
if self.current_modal is not None:
|
|
if self.current_modal[1] is not None and self.current_modal[1](event) is True:
|
|
return
|
|
self.current_modal = None
|
|
c = self.modal_container
|
|
clear(c.firstChild.firstChild)
|
|
if self.modals.length == 0:
|
|
set_css(c, display='none')
|
|
else:
|
|
self.update()
|
|
|
|
def create_simple_dialog(title, msg, details, icon_name, prefix):
|
|
details = details or ''
|
|
def create_func(parent):
|
|
show_details = E.a(class_='dialog-simple-link', style='cursor:pointer; color: blue; padding-top:1em; display:inline-block; margin-left: auto', _('Show details'))
|
|
show_details.addEventListener('click', def():
|
|
show_details.style.display = 'none'
|
|
show_details.nextSibling.style.display = 'block'
|
|
)
|
|
is_html_msg = /<[a-zA-Z]/.test(msg)
|
|
html_container = E.div()
|
|
if is_html_msg:
|
|
html_container.innerHTML = msg
|
|
parent.appendChild(
|
|
E.div(
|
|
style='max-width:60em; text-align: left',
|
|
E.h2(
|
|
E.i(class_='fa fa-lg fa-' + icon_name, style='color:red'), E.span('\xa0' + prefix + '\xa0', style='font-variant:small-caps'), title,
|
|
style='font-weight: bold; font-size: ' + get_font_size('title')
|
|
),
|
|
E.div((html_container if is_html_msg else msg), style='padding-top: 1em; margin-top: 1em; border-top: 1px solid currentColor'),
|
|
E.div(style='display: ' + ('block' if details else 'none'),
|
|
show_details,
|
|
E.div(details,
|
|
style='display:none; white-space:pre-wrap; font-size: smaller; margin-top: 1em; border-top: solid 1px currentColor; padding-top: 1em'
|
|
)
|
|
)
|
|
)
|
|
)
|
|
show_modal(create_func)
|
|
|
|
def error_dialog(title, msg, details=None):
|
|
create_simple_dialog(title, msg, details, 'bug', _('Error:'))
|
|
|
|
def warning_dialog(title, msg, details=None):
|
|
create_simple_dialog(title, msg, details, 'warning', _('Warning:'))
|
|
|
|
# def test_error():
|
|
# error_dialog(
|
|
# 'Hello, world!',
|
|
# 'Some long text to test rendering/line breaking in error dialogs that contain lots of text like this test error dialog from hell in a handbasket with fruits and muppets making a scene.',
|
|
# ['a word ' for i in range(10000)].join(' ')
|
|
# )
|
|
|
|
def create_modal_container():
|
|
nonlocal modal_container
|
|
if modal_container is None:
|
|
modal_container = ModalContainer()
|
|
# window.setTimeout(def():
|
|
# document.getElementById('books-view-1').addEventListener('click', test_error)
|
|
# , 10)
|
|
return modal_container
|
|
|
|
def show_modal(create_func, on_close=None):
|
|
modal_container.show_modal(create_func, on_close)
|