mirror of
https://github.com/wassname/baukit.git
synced 2026-07-04 21:53:24 +08:00
Rename emit_tag to emit, and add callable style values.
This commit is contained in:
+20
-20
@@ -217,7 +217,7 @@ class Widget(Model):
|
||||
Override to define the initial HTML view of the widget. Should
|
||||
define an element with id given by view_id().
|
||||
'''
|
||||
with show.enter_tag() as t:
|
||||
with show.enter() as t:
|
||||
return t.begin() + t.end()
|
||||
|
||||
def view_id(self):
|
||||
@@ -558,7 +558,7 @@ class Button(Widget):
|
||||
''')
|
||||
|
||||
def widget_html(self):
|
||||
return show.emit_tag('input', self.std_attrs(),
|
||||
return show.emit('input', self.std_attrs(),
|
||||
type='button', value=self.label)
|
||||
|
||||
class Label(Widget):
|
||||
@@ -579,7 +579,7 @@ class Label(Widget):
|
||||
|
||||
def widget_html(self):
|
||||
out = []
|
||||
with show.enter_tag('label', self.std_attrs(), out=out):
|
||||
with show.enter('label', self.std_attrs(), out=out):
|
||||
out.append(html.escape(str(self.value)))
|
||||
return ''.join(out)
|
||||
|
||||
@@ -615,7 +615,7 @@ class Textbox(Widget):
|
||||
''')
|
||||
|
||||
def widget_html(self):
|
||||
return show.emit_tag('input', self.std_attrs(),
|
||||
return show.emit('input', self.std_attrs(),
|
||||
type='text', value=self.value, size=self.size)
|
||||
|
||||
|
||||
@@ -650,7 +650,7 @@ class Numberbox(Widget):
|
||||
''')
|
||||
|
||||
def widget_html(self):
|
||||
return show.emit_tag('input', self.std_attrs(),
|
||||
return show.emit('input', self.std_attrs(),
|
||||
type='numeric', value=self.value, size=self.size)
|
||||
|
||||
class Textarea(Widget):
|
||||
@@ -680,7 +680,7 @@ class Textarea(Widget):
|
||||
|
||||
def widget_html(self):
|
||||
out = []
|
||||
with show.enter_tag('textarea', self.std_attrs(), out=out):
|
||||
with show.enter('textarea', self.std_attrs(), out=out):
|
||||
out.append(html.escape(self.value))
|
||||
return ''.join(out)
|
||||
|
||||
@@ -711,7 +711,7 @@ class Range(Widget):
|
||||
''')
|
||||
|
||||
def widget_html(self):
|
||||
return show.emit_tag('input', self.std_attrs(),
|
||||
return show.emit('input', self.std_attrs(),
|
||||
type='range', value=self.value,
|
||||
min=self.min, max=self.max, step=self.step)
|
||||
|
||||
@@ -738,7 +738,7 @@ class ColorPicker(Widget):
|
||||
''')
|
||||
|
||||
def widget_html(self):
|
||||
return show.emit_tag('input', self.std_attrs(),
|
||||
return show.emit('input', self.std_attrs(),
|
||||
type='color', value=self.value)
|
||||
|
||||
|
||||
@@ -783,10 +783,10 @@ class Choice(Widget):
|
||||
|
||||
def widget_html(self):
|
||||
out = []
|
||||
with show.enter_tag('form', self.std_attrs(), out=out):
|
||||
with show.enter('form', self.std_attrs(), out=out):
|
||||
for value in self.choices:
|
||||
with show.enter_tag('label', out=out):
|
||||
show.emit_tag('input',
|
||||
with show.enter('label', out=out):
|
||||
show.emit('input',
|
||||
(show.attrs(checked=None) if value == self.selection else None),
|
||||
name='choice', type='radio', value=value, out=out)
|
||||
return ''.join(out)
|
||||
@@ -830,10 +830,10 @@ class Menu(Widget):
|
||||
|
||||
def widget_html(self):
|
||||
out = []
|
||||
with show.enter_tag('form', self.std_attrs(), out=out):
|
||||
with show.enter_tag(show.Tag('select', name='menu'), out=out):
|
||||
with show.enter('form', self.std_attrs(), out=out):
|
||||
with show.enter(show.Tag('select', name='menu'), out=out):
|
||||
for value in self.choices:
|
||||
with show.enter_tag(show.Tag('option',
|
||||
with show.enter(show.Tag('option',
|
||||
(show.attr(selected=None) if value == self.selection else None),
|
||||
value=value), out=out):
|
||||
out.append(html.escape(str(value)))
|
||||
@@ -898,13 +898,13 @@ class Datalist(Widget):
|
||||
|
||||
def widget_html(self):
|
||||
out = []
|
||||
with show.enter_tag('form', self.std_attrs(),
|
||||
with show.enter('form', self.std_attrs(),
|
||||
onsubmit='return false;', out=out):
|
||||
show.emit_tag('input', name='inp', list=self.datalist_id(),
|
||||
show.emit('input', name='inp', list=self.datalist_id(),
|
||||
autocomplete='off', out=out)
|
||||
with show.enter_tag(show.Tag('datalist'), id=self.datalist_id()):
|
||||
with show.enter(show.Tag('datalist'), id=self.datalist_id()):
|
||||
for value in self.choices:
|
||||
show.emit_tag('option', value=str(value))
|
||||
show.emit('option', value=str(value))
|
||||
|
||||
|
||||
class Div(Widget):
|
||||
@@ -953,7 +953,7 @@ class Div(Widget):
|
||||
|
||||
def widget_html(self):
|
||||
out = []
|
||||
with emit.enter_tag(self.std_attrs(), out=out):
|
||||
with show.enter(self.std_attrs(), out=out):
|
||||
out.append(self.innerHTML);
|
||||
return ''.join(out)
|
||||
|
||||
@@ -1022,7 +1022,7 @@ class Image(Widget):
|
||||
''')
|
||||
|
||||
def widget_html(self):
|
||||
return show.emit_tag('img', self.std_attrs(), show.style(margin=0),
|
||||
return show.emit('img', self.std_attrs(), show.style(margin=0),
|
||||
src=self.src)
|
||||
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class PaintWidget(Widget):
|
||||
opacity: 0; transition: opacity .1s ease-in-out; }}
|
||||
#{v} .paintmask.vanishing:hover {{ opacity: { self.opacity }; }}
|
||||
</style>''')]
|
||||
show.emit_tag(self.std_attrs(), out=out)
|
||||
show.emit(self.std_attrs(), out=out)
|
||||
return ''.join(out)
|
||||
|
||||
|
||||
|
||||
+40
-26
@@ -53,7 +53,7 @@ def raw_html(*args):
|
||||
return HtmlRepr(''.join(str(x) for x in args))
|
||||
|
||||
@contextmanager
|
||||
def enter_tag(*args, out=None, **kwargs):
|
||||
def enter(*args, out=None, **kwargs):
|
||||
'''
|
||||
Context manager for creating and emitting a tag and its matching
|
||||
end-tag. When the tag is created, any current defaults and options
|
||||
@@ -63,7 +63,7 @@ def enter_tag(*args, out=None, **kwargs):
|
||||
|
||||
```
|
||||
out = []
|
||||
with show.enter_tag('div', id='d38', style(topMargin='8px'), out=out):
|
||||
with show.enter('div', id='d38', style(topMargin='8px'), out=out):
|
||||
out.append('inside the div')
|
||||
```
|
||||
|
||||
@@ -95,15 +95,15 @@ def enter_tag(*args, out=None, **kwargs):
|
||||
tag_modifications.clear()
|
||||
tag_stack.pop()
|
||||
|
||||
def emit_tag(*args, out=None, **kwargs):
|
||||
def emit(*args, out=None, **kwargs):
|
||||
'''
|
||||
Emits the specified tag, applying any current defaults and options
|
||||
to the styles and attributes. Options are handled as with enter_tag.
|
||||
to the styles and attributes. Options are handled as with enter.
|
||||
|
||||
If no `out` array is provided, returns the tag as a string.
|
||||
'''
|
||||
emit_out = [] if out is None else out
|
||||
with enter_tag(*args, out=emit_out, **kwargs):
|
||||
with enter(*args, out=emit_out, **kwargs):
|
||||
if out is None:
|
||||
return ''.join(emit_out)
|
||||
|
||||
@@ -118,7 +118,7 @@ CSS_UNITS = dict([(k, unit) for keys, unit in [
|
||||
('border border-left border-right border-top border-bottom '
|
||||
'border-width border-left-width border-right-width '
|
||||
'border-top-width border-bottom-width', 'px'),
|
||||
('border-spacing letter-spacing word-spacing', 'px')
|
||||
('border-spacing letter-spacing word-spacing', 'px'),
|
||||
('margin margin-left margin-right margin-top margin-bottom', 'px'),
|
||||
('padding padding-left padding-right padding-top padding-bottom', 'px'),
|
||||
] for k in keys.split(' ')])
|
||||
@@ -127,6 +127,8 @@ def hyphenateCamelKeys(d):
|
||||
return {re.sub('([A-Z]+)', r'-\1', k).lower() : v for k, v in d.items()}
|
||||
|
||||
def styleValue(v, k):
|
||||
if callable(v):
|
||||
v = v()
|
||||
if isinstance(v, (int, float)) and k in CSS_UNITS:
|
||||
return f'{v}{CSS_UNITS[k]}'
|
||||
return str(v)
|
||||
@@ -208,16 +210,27 @@ class Tag:
|
||||
def tag(*args, **kwargs):
|
||||
return Tag(*args, **kwargs)
|
||||
|
||||
def inherit_value(top, inner='inherit'):
|
||||
'''
|
||||
A callable style value that resolves to one default at the top level
|
||||
and a different value when nested inside tags.
|
||||
'''
|
||||
def resolve():
|
||||
return top if len(tag_stack) <= 2 else inner
|
||||
return resolve
|
||||
|
||||
|
||||
# This is the default loop for nesting children: horizontal layout by default,
|
||||
# and then vertical layout for nested arrays; then horizontal within those, etc.
|
||||
H = Tag(
|
||||
style(display='flex', flex='1', flexFlow='row wrap', gap='3px',
|
||||
alignItems='center'))
|
||||
V = Tag(
|
||||
style(display='flex', flex='1', flexFlow='column', gap='3px'),
|
||||
ChildTag(H))
|
||||
H.update(ChildTag(V))
|
||||
style(display='flex', flex='1', flexFlow='column',
|
||||
gap=inherit_value(3)))
|
||||
|
||||
H = Tag(
|
||||
style(display='flex', flex='1', flexFlow='row wrap',
|
||||
gap=inherit_value(3)),
|
||||
ChildTag(V))
|
||||
V.update(ChildTag(H))
|
||||
|
||||
# Tables
|
||||
TD = Tag('td', ChildTag(H))
|
||||
@@ -230,13 +243,14 @@ PLAIN = Tag()
|
||||
# The TIGHT style allows the content to provide the size, instead of
|
||||
# expanding to fill the available space.
|
||||
TIGHT = Tag(
|
||||
style(display='inline-flex', flex=None, flexFlow='column', gap='3px'),
|
||||
style(display='inline-flex', flex=None, flexFlow='column',
|
||||
gap=inherit_value(3)),
|
||||
ChildTag(H))
|
||||
|
||||
# WRAP provides wrapping lines of TIGHT boxes, akin to layout of text
|
||||
WRAP = Tag(
|
||||
style(display='flex', flex='1', flexFlow='row wrap', gap='3px',
|
||||
alignItems='start'),
|
||||
style(display='flex', flex='1', flexFlow='row wrap',
|
||||
gap=inherit_value(3), alignItems='start'),
|
||||
ChildTag(TIGHT))
|
||||
|
||||
|
||||
@@ -268,7 +282,7 @@ def render_str(obj, out):
|
||||
if '\n' in s:
|
||||
render_pre(s, out)
|
||||
return
|
||||
with enter_tag(out=out):
|
||||
with enter(out=out):
|
||||
out.append(escape(s))
|
||||
|
||||
def render_html(obj, out):
|
||||
@@ -299,7 +313,7 @@ def render_list(obj, out):
|
||||
'''
|
||||
Lists are divs containin divs, alternating row-inline and column flex layout.
|
||||
'''
|
||||
with enter_tag(out=out):
|
||||
with enter(out=out):
|
||||
for v in obj:
|
||||
render(v, out)
|
||||
|
||||
@@ -307,12 +321,12 @@ def render_dict(obj, out):
|
||||
'''
|
||||
Dicts become tables.
|
||||
'''
|
||||
with enter_tag(TABLE, out=out):
|
||||
with enter(TABLE, out=out):
|
||||
for k, v in obj.items():
|
||||
with enter_tag(out=out):
|
||||
with enter_tag(out=out):
|
||||
with enter(out=out):
|
||||
with enter(out=out):
|
||||
out.append(escape(str(k)))
|
||||
with enter_tag(out=out):
|
||||
with enter(out=out):
|
||||
render(v, out)
|
||||
|
||||
def render_image(obj, out):
|
||||
@@ -332,14 +346,14 @@ def render_image(obj, out):
|
||||
buf.close()
|
||||
except:
|
||||
return False
|
||||
emit_tag('img', attr(src=src), style(flex='0'), out=out)
|
||||
emit('img', attr(src=src), style(flex='0'), out=out)
|
||||
|
||||
def render_pre(obj, out):
|
||||
'''
|
||||
Long multiline text data types are rendered in <pre> tags.
|
||||
'''
|
||||
s = str(obj)
|
||||
with enter_tag('pre', out=out):
|
||||
with enter('pre', out=out):
|
||||
out.append(escape(s))
|
||||
|
||||
def render_modifications(obj, out):
|
||||
@@ -353,7 +367,7 @@ def render_pandas(obj, out):
|
||||
'''
|
||||
Allows control of Pandas outer-level table CSS and HTML attributes.
|
||||
'''
|
||||
with enter_tag(TABLE, style(display=None, flexFlow=None, gap=None, alignItems=None)) as t:
|
||||
with enter(TABLE, style(display=None, flexFlow=None, gap=None, alignItems=None)) as t:
|
||||
styler = obj.style
|
||||
css = str(t.style)
|
||||
if css:
|
||||
@@ -382,7 +396,7 @@ RENDERING_RULES = [
|
||||
((Style, Attr, Tag, ChildTag), render_modifications),
|
||||
# Pandas dataframes even though they have a _repr_html_
|
||||
(subclass_of('pandas.core.frame.DataFrame'), render_pandas),
|
||||
# Objects with an html repr
|
||||
# Objects with an mimebundle repr, like altair charts
|
||||
((lambda x: hasattr(x, '_repr_mimebundle_')), render_mimebundle),
|
||||
# Objects with an html repr
|
||||
((lambda x: hasattr(x, '_repr_html_')), render_html),
|
||||
@@ -394,7 +408,7 @@ RENDERING_RULES = [
|
||||
(subclass_of('PIL.Image.Image'), render_image),
|
||||
# Matplotlib figures
|
||||
(subclass_of('matplotlib.figure.Figure'), render_image),
|
||||
# Numpy, pytorch arrays
|
||||
# Numpy, pytorch arrays are often too big to render every item
|
||||
(lambda x: hasattr(x, 'shape') and hasattr(x, 'dtype'), render_pre),
|
||||
# Generators and lists: recurse
|
||||
((lambda x: hasattr(x, '__iter__')), render_list),
|
||||
|
||||
Reference in New Issue
Block a user