mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
More work on the conversion setting UI for the server
This commit is contained in:
parent
d2de878849
commit
f85c5228c2
@ -151,7 +151,7 @@ OptionRecommendation(name='base_font_size',
|
||||
help=_('The base font size in pts. All font sizes in the produced book '
|
||||
'will be rescaled based on this size. By choosing a larger '
|
||||
'size you can make the fonts in the output bigger and vice '
|
||||
'versa. By default, the base font size is chosen based on '
|
||||
'versa. By default, when the value is zero, the base font size is chosen based on '
|
||||
'the output profile you chose.'
|
||||
)
|
||||
),
|
||||
@ -849,6 +849,16 @@ OptionRecommendation(name='search_replace',
|
||||
if help is not None:
|
||||
return help.replace('%default', str(rec.recommended_value))
|
||||
|
||||
def get_all_help(self):
|
||||
ans = {}
|
||||
for group in (self.input_options, self.pipeline_options,
|
||||
self.output_options, self.all_format_options):
|
||||
for rec in group:
|
||||
help = getattr(rec, 'help', None)
|
||||
if help is not None:
|
||||
ans[rec.option.name] = help
|
||||
return ans
|
||||
|
||||
def merge_plugin_recs(self, plugin):
|
||||
for name, val, level in plugin.recommendations:
|
||||
rec = self.get_option_by_name(name)
|
||||
|
@ -209,7 +209,7 @@ def get_conversion_options(input_fmt, output_fmt, book_id, db):
|
||||
from calibre.customize.conversion import OptionRecommendation
|
||||
plumber = create_dummy_plumber(input_fmt, output_fmt)
|
||||
specifics = load_specifics(db, book_id)
|
||||
ans = {'options': {}, 'disabled': set(), 'defaults': {}}
|
||||
ans = {'options': {}, 'disabled': set(), 'defaults': {}, 'help': {}}
|
||||
|
||||
def merge_group(group_name, option_names):
|
||||
if not group_name or group_name in ('debug', 'metadata'):
|
||||
@ -227,6 +227,7 @@ def get_conversion_options(input_fmt, output_fmt, book_id, db):
|
||||
ans['options'].update(defs['options'])
|
||||
ans['disabled'] |= set(defs['disabled'])
|
||||
ans['defaults'].update(defaults)
|
||||
ans['help'] = plumber.get_all_help()
|
||||
|
||||
for group_name, option_names in OPTIONS['pipe'].iteritems():
|
||||
merge_group(group_name, option_names)
|
||||
|
@ -2,6 +2,178 @@
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
from __python__ import bound_methods, hash_literals
|
||||
|
||||
from elementmaker import E
|
||||
from gettext import gettext as _
|
||||
|
||||
def create_option_group(group_name, container):
|
||||
pass
|
||||
from dom import ensure_id, add_extra_css, build_rule
|
||||
|
||||
CLASS_NAME = 'conversion-option-group'
|
||||
|
||||
add_extra_css(def():
|
||||
style = ''
|
||||
sel = '.' + CLASS_NAME + ' '
|
||||
style += build_rule(sel + ' [data-option-name]', margin_bottom='1ex')
|
||||
return style
|
||||
)
|
||||
|
||||
|
||||
# globals {{{
|
||||
container_id = None
|
||||
get_option_value = get_option_default_value = set_option_value = is_option_disabled = get_option_help = None
|
||||
entry_points = {}
|
||||
registry = {}
|
||||
listeners = {}
|
||||
|
||||
|
||||
def ep(func):
|
||||
entry_points[func.name] = func
|
||||
return func
|
||||
|
||||
|
||||
def add_listener(name, callback):
|
||||
if not listeners[name]:
|
||||
listeners[name] = v'[]'
|
||||
listeners[name].push(callback)
|
||||
|
||||
|
||||
def on_change(name):
|
||||
if listeners[name]:
|
||||
for callback in listeners[name]:
|
||||
callback(name)
|
||||
|
||||
|
||||
def sanitize_accelerator(text):
|
||||
return text.replace('&', '')
|
||||
# }}}
|
||||
|
||||
def create_simple_widget(name, text, tooltip, input_widget_, getter, setter, reverse): # {{{
|
||||
if not text.endswith(':'):
|
||||
text = text + ':'
|
||||
div = E.div(
|
||||
data_option_name=name,
|
||||
title=tooltip or get_option_help(name),
|
||||
(
|
||||
E.label(input_widget_, '\xa0' + sanitize_accelerator(text)) if reverse else
|
||||
E.label(sanitize_accelerator(text) + '\xa0', input_widget_)
|
||||
)
|
||||
)
|
||||
|
||||
def straight_input_widget(container):
|
||||
return container.firstChild.lastChild
|
||||
|
||||
def reverse_input_widget(container):
|
||||
return container.firstChild.firstChild
|
||||
|
||||
input_widget = reverse_input_widget if reverse else straight_input_widget
|
||||
input_widget(div).addEventListener('change', on_change.bind(None, name))
|
||||
|
||||
ops = {
|
||||
'get': def (container):
|
||||
return getter(input_widget(container))
|
||||
,
|
||||
'set': def (container, val):
|
||||
setter(input_widget(container), val)
|
||||
,
|
||||
'set_disabled': def (container, val):
|
||||
if val:
|
||||
container.classList.add('disabled')
|
||||
input_widget(container).setAttribute('disabled', 'disabled')
|
||||
else:
|
||||
container.classList.remove('disabled')
|
||||
input_widget(container).removeAttribute('disabled')
|
||||
}
|
||||
registry[name] = ops
|
||||
ops.set(div, get_option_value(name))
|
||||
ops.set(div, get_option_value(name))
|
||||
if is_option_disabled(name):
|
||||
ops.set_disabled(div, True)
|
||||
return div
|
||||
# }}}
|
||||
|
||||
def checkbox(name, text, tooltip): # {{{
|
||||
return create_simple_widget(name, text, tooltip, E.input(type='checkbox'),
|
||||
def getter(w): # noqa: unused-local
|
||||
return bool(w.checked)
|
||||
,
|
||||
def setter(w, val): # noqa: unused-local
|
||||
w.checked = bool(val)
|
||||
,
|
||||
True
|
||||
)
|
||||
# }}}
|
||||
|
||||
def lineedit(name, text, tooltip): # {{{
|
||||
return create_simple_widget(name, text, tooltip, E.input(type='text'),
|
||||
def getter(w): # noqa: unused-local
|
||||
ans = w.value
|
||||
if ans and ans.strip():
|
||||
return ans.strip()
|
||||
,
|
||||
def setter(w, val): # noqa: unused-local
|
||||
w.value = val or ''
|
||||
)
|
||||
# }}}
|
||||
|
||||
def float_spin(name, text, tooltip=None, step=0.1, min=0, max=100): # {{{
|
||||
f = E.input(type='number', step=str(step), min=str(min), max=str(max), required=True)
|
||||
defval = get_option_default_value(name)
|
||||
return create_simple_widget(name, text, tooltip, f,
|
||||
def getter(w): # noqa: unused-local
|
||||
try:
|
||||
return float(w.value)
|
||||
except:
|
||||
return defval
|
||||
,
|
||||
def setter(w, val): # noqa: unused-local
|
||||
w.value = str(float(val))
|
||||
)
|
||||
# }}}
|
||||
|
||||
def container_for_option(name):
|
||||
return document.getElementById(container_id).querySelector(f'[data-option-name="{name}"]')
|
||||
|
||||
|
||||
def get(name):
|
||||
return registry[name].get(container_for_option(name))
|
||||
|
||||
|
||||
def set(name, val):
|
||||
registry[name].set(container_for_option(name), val)
|
||||
|
||||
|
||||
def set_disabled(name, val):
|
||||
registry[name].set_disabled(container_for_option(name), val)
|
||||
|
||||
|
||||
# Look & feel {{{
|
||||
@ep
|
||||
def look_and_feel(container):
|
||||
def subhead(text):
|
||||
container.appendChild(E.div(
|
||||
style='border-bottom: solid 1px currentColor; margin-bottom: 1ex; max-width: 30em', E.b(sanitize_accelerator(text))))
|
||||
|
||||
subhead(_('&Fonts'))
|
||||
add_listener('disable_font_rescaling', def (name):
|
||||
disabled = get('disable_font_rescaling')
|
||||
for dname in 'font_size_mapping', 'base_font_size':
|
||||
set_disabled(dname, disabled)
|
||||
)
|
||||
container.appendChild(checkbox('disable_font_rescaling', _('&Disable font size rescaling')))
|
||||
container.appendChild(float_spin('base_font_size', _('Base font si&ze:'), step=0.1, min=0, max=50))
|
||||
container.appendChild(lineedit('font_size_mapping', _('Font size &key:')))
|
||||
# }}}
|
||||
|
||||
|
||||
def create_option_group(group_name, container, get_option_value_, get_option_default_value_, is_option_disabled_, get_option_help_):
|
||||
nonlocal get_option_value, get_option_default_value, set_option_value, is_option_disabled, container_id, registry, listeners, get_option_help
|
||||
get_option_value, get_option_default_value, is_option_disabled, get_option_help = get_option_value_, get_option_default_value_, is_option_disabled_, get_option_help_
|
||||
registry = {}
|
||||
listeners = {}
|
||||
container_id = ensure_id(container)
|
||||
container.classList.add(CLASS_NAME)
|
||||
entry_points[group_name](container)
|
||||
|
||||
|
||||
def commit_changes(set_option_value):
|
||||
for name in registry:
|
||||
set_option_value(name, get(name))
|
||||
|
@ -7,7 +7,7 @@ from gettext import gettext as _
|
||||
|
||||
from ajax import ajax, ajax_send
|
||||
from book_list.book_details import report_load_failure
|
||||
from book_list.conversion_widgets import create_option_group
|
||||
from book_list.conversion_widgets import create_option_group, entry_points, commit_changes
|
||||
from book_list.library_data import download_url, load_status, url_books_query
|
||||
from book_list.router import back, open_book, report_a_load_failure
|
||||
from book_list.top_bar import create_top_bar, set_title
|
||||
@ -240,6 +240,8 @@ def create_configuring_markup():
|
||||
ans = E.li(E.a(class_='simple-link', href='javascript: void(0)'))
|
||||
ans.dataset.group = name
|
||||
ans.firstChild.addEventListener('click', show_group)
|
||||
if not entry_points[name]:
|
||||
ans.style.display = 'none'
|
||||
return ans
|
||||
|
||||
GROUP_TITLES = {
|
||||
@ -290,6 +292,32 @@ def create_configuring_markup():
|
||||
return ans, initialize
|
||||
|
||||
|
||||
def get_option_value(name, defval):
|
||||
ans = conversion_data.conversion_options.options[name]
|
||||
if ans is undefined:
|
||||
ans = defval
|
||||
return ans
|
||||
|
||||
|
||||
def get_option_default_value(name, defval):
|
||||
ans = conversion_data.conversion_options.defaults[name]
|
||||
if ans is undefined:
|
||||
ans = defval
|
||||
return ans
|
||||
|
||||
|
||||
def set_option_value(name, val):
|
||||
conversion_data.conversion_options.options[name] = val
|
||||
|
||||
|
||||
def is_option_disabled(name):
|
||||
return conversion_data.disabled_map[name] is True
|
||||
|
||||
|
||||
def get_option_help(name):
|
||||
return conversion_data.conversion_options.help[name] or ''
|
||||
|
||||
|
||||
def create_configure_group_markup():
|
||||
ans = E.div()
|
||||
|
||||
@ -300,7 +328,7 @@ def create_configure_group_markup():
|
||||
_('Configuring {} settings').format(conversion_data.configuring_group_title)))
|
||||
panel = E.div()
|
||||
container.appendChild(panel)
|
||||
create_option_group(conversion_data.configuring_group, container)
|
||||
create_option_group(conversion_data.configuring_group, container, get_option_value, get_option_default_value, is_option_disabled, get_option_help)
|
||||
|
||||
return ans, init
|
||||
|
||||
@ -320,6 +348,9 @@ def on_data_loaded(end_type, xhr, ev):
|
||||
|
||||
if end_type is 'load':
|
||||
conversion_data = JSON.parse(xhr.responseText)
|
||||
conversion_data.disabled_map = {}
|
||||
for name in conversion_data.conversion_options.disabled:
|
||||
conversion_data.disabled_map[name] = True
|
||||
elif end_type is 'abort':
|
||||
pass
|
||||
else:
|
||||
@ -346,6 +377,7 @@ def fetch_conversion_data(book_id, input_fmt, output_fmt):
|
||||
def on_close(container_id):
|
||||
nonlocal current_state
|
||||
if current_state is 'configure-group':
|
||||
commit_changes(set_option_value)
|
||||
current_state = 'configuring'
|
||||
apply_state_to_markup()
|
||||
return
|
||||
|
Loading…
x
Reference in New Issue
Block a user