Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP - blueprints after generic_input_renderer #31

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ History
2.2.1 (unreleased)
------------------

- Add ``readonly`` as possible attribute of input elements.
[thet]

- Use predefined lists of managed attributes for documentation where common or
full generic input renderer are used.
[thet]

- When creating a blueprint chain with a factory, allow blueprints defined
after blueprints based in ``generic_input_renderer``.
[thet]

- Introduce ``hybrid_renderer`` and ``leaf`` widget property which gets
considered in ``hybrid_renderer`` and ``hybrid_extractor``. Use
``hybrid_renderer`` in ``div`` blueprint.
Expand All @@ -13,7 +24,7 @@ History
- Consider data attributes in div renderer.
[rnix]

- Fix rendering of empty div renderer.
- Fix rendering of empty in div ``div_renderer``.
[rnix]

- Explicitely check for ``None`` and ``UNSET`` before rendering empty value in
Expand Down
70 changes: 48 additions & 22 deletions src/yafowil/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@
Disables input.
"""

factory.defaults['readonly'] = None
factory.doc['props']['readonly'] = """\
Readonly input.
"""

factory.defaults['required_class_default'] = 'required'
factory.doc['props']['required_class_default'] = """\
CSS-class to apply if required condition was not met - if no specific class
Expand Down Expand Up @@ -160,6 +165,23 @@
input.
"""

managed_props__input_common = css_managed_props + [
'autofocus',
'data',
'disabled',
'maxlength',
'placeholder',
'readonly',
'required',
'size',
'title'
]


managed_props__input_full = managed_props__input_common + [
'autocomplete'
]


###############################################################################
# generic
Expand Down Expand Up @@ -276,11 +298,14 @@ def input_attributes_common(widget, data, excludes=list(), value=None):
autofocus = attr_value('autofocus', widget, data) and 'autofocus' or None
disabled = attr_value('disabled', widget, data)
disabled = bool(disabled) and 'disabled' or None
readonly = attr_value('readonly', widget, data)
readonly = bool(readonly) and 'readonly' or None
required = attr_value('required', widget, data) and 'required' or None
input_attrs = {
'autofocus': autofocus,
'class_': cssclasses(widget, data),
'disabled': disabled,
'readonly': readonly,
'id': cssid(widget, 'input'),
'name_': widget.dottedpath,
'placeholder': attr_value('placeholder', widget, data),
Expand Down Expand Up @@ -308,13 +333,18 @@ def input_attributes_full(widget, data, value=None):
return input_attrs


@managedprops(*css_managed_props)
def input_generic_renderer(widget, data, custom_attrs={}):
@managedprops(*managed_props__input_full)
def input_generic_renderer(widget, data, pos='before', custom_attrs={}):
"""Generic HTML ``input`` tag render.
"""
input_attrs = input_attributes_full(widget, data)
input_attrs.update(custom_attrs)
return data.tag('input', **input_attrs)
rendered = data.tag('input', **input_attrs)
if pos == 'before':
rendered = rendered + (data.rendered or u'')
else:
rendered = (data.rendered or u'') + rendered
return rendered
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

input_generic_renderer is supposed only to render an input tag, no matter whether data already contains rendered markup, please revert



# multivalued is not documented, because its only valid for specific blueprints
Expand All @@ -333,7 +363,7 @@ def display_proxy_renderer(widget, data):
input_attrs = input_attributes_full(widget, data, value=val)
rendered += data.tag('input', **input_attrs)
else:
rendered += input_generic_renderer(widget, data)
rendered = input_generic_renderer(widget, data, pos='after')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above, if position really needs to be set here hardcoded (for what exactly?) it should be done here, otherwise revert please

if orgin_type:
widget.attrs['type'] = orgin_type
else:
Expand Down Expand Up @@ -389,10 +419,11 @@ def generic_positional_rendering_helper(tagname, message, attrs, rendered, pos,
pos
position how to place the newtag relative to the prior rendered:
'before'='<newtag>message</newtag>rendered',
'after' ='<newtag>message</newtag>'
'after' ='rendered<newtag>message</newtag>'
'inner-before'= <newtag>message rendered</newtag>
'inner-after'= <newtag>rendered message</newtag>
"""
rendered = rendered or u''
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it possible that rendered is something other than string here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, rendered can also be UNSET

if pos not in ['before', 'after', 'inner-before', 'inner-after']:
raise ValueError('Invalid value for position "{0}"'.format(pos))
if pos.startswith('inner'):
Expand Down Expand Up @@ -448,8 +479,7 @@ def tag_renderer(widget, data):
# text
###############################################################################

@managedprops('data', 'title', 'size', 'disabled', 'autofocus',
'placeholder', 'autocomplete', *css_managed_props)
@managedprops(*managed_props__input_full)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be double checked

def text_edit_renderer(widget, data):
return input_generic_renderer(widget, data)

Expand Down Expand Up @@ -484,9 +514,6 @@ def text_edit_renderer(widget, data):
factory.defaults['text.class'] = 'text'

factory.defaults['text.disabled'] = False
factory.doc['props']['text.disabled'] = """\
Flag input field is disabled.
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please readd


factory.defaults['text.persist'] = True

Expand Down Expand Up @@ -856,8 +883,7 @@ def _pwd_value(widget, data):
return attr_value('default', widget, data)


@managedprops('data', 'title', 'size', 'disabled', 'autofocus',
'placeholder', 'autocomplete', *css_managed_props)
@managedprops(*managed_props__input_common)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be double checked

def password_edit_renderer(widget, data):
"""Render password widget.
"""
Expand Down Expand Up @@ -958,8 +984,7 @@ def checkbox_extractor(widget, data):
)


@managedprops('data', 'title', 'size', 'disabled', 'autofocus',
'format', 'disabled', 'checked', *css_managed_props)
@managedprops('format', *managed_props__input_common)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be double checked

def checkbox_edit_renderer(widget, data):
tag = data.tag
input_attrs = input_attributes_common(widget, data)
Expand Down Expand Up @@ -1051,9 +1076,6 @@ def checkbox_display_renderer(widget, data):
factory.defaults['checkbox.class'] = 'checkbox'

factory.defaults['checkbox.disabled'] = False
factory.doc['props']['checkbox.disabled'] = """\
Flag whether checkbox is disabled.
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please readd


factory.defaults['checkbox.checked'] = None
factory.doc['props']['checkbox.checked'] = """\
Expand Down Expand Up @@ -1435,8 +1457,7 @@ def file_extractor(widget, data):
return value


@managedprops('accept', 'placeholder', 'autofocus',
'required', *css_managed_props)
@managedprops('accept', *managed_props__input_common)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be double checked

def input_file_edit_renderer(widget, data):
tag = data.tag
input_attrs = input_attributes_common(widget, data, excludes=['value'])
Expand Down Expand Up @@ -1553,8 +1574,8 @@ def file_options_renderer(widget, data):
# submit
###############################################################################

@managedprops('label', 'class', 'action', 'handler',
'next', 'skip', 'expression')
@managedprops('label', 'action', 'handler', 'next', 'skip', 'expression',
*managed_props__input_common)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be double checked

def submit_renderer(widget, data):
expression = attr_value('expression', widget, data)
if not expression:
Expand Down Expand Up @@ -1783,6 +1804,11 @@ def number_extractor(widget, data):
return val


@managedprops('min', 'max', 'step', *managed_props__input_full)
def number_edit_renderer(widget, data):
return input_generic_renderer(widget, data)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for dedicated number_edit_renderer. min max and step managed props are defined for number_extractor, and managed props gets aggregated


factory.register(
'number',
extractors=[
Expand All @@ -1792,7 +1818,7 @@ def number_extractor(widget, data):
generic_datatype_extractor,
number_extractor,
],
edit_renderers=[input_generic_renderer],
edit_renderers=[number_edit_renderer],
display_renderers=[
generic_display_renderer,
display_proxy_renderer
Expand Down
44 changes: 41 additions & 3 deletions src/yafowil/common.rst
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,29 @@ Render with title attribute::
u'<input class="text" id="input-MYTEXT" name="MYTEXT"
title="My awesome title" type="text" value="ja ha!" />'

Generic HTML5 Data::
Render disabled::

>>> widget = factory(
... 'text',
... name='MYTEXT',
... props={
... 'disabled': True
... })
>>> widget()
u'<input class="text" disabled="disabled" id="input-MYTEXT" name="MYTEXT" type="text" value="" />'

Render readonly::

>>> widget = factory(
... 'text',
... name='MYTEXT',
... props={
... 'readonly': True
... })
>>> widget()
u'<input class="text" id="input-MYTEXT" name="MYTEXT" readonly="readonly" type="text" value="" />'

Generic HTML5 Data::

>>> widget = factory(
... 'text',
Expand Down Expand Up @@ -449,8 +471,7 @@ hidden field::
>>> wrapped_pxml(widget())
<div>
<div class="display-text" id="display-DISPLAY">lorem ipsum</div>
<input class="text" id="input-DISPLAY" name="DISPLAY" type="hidden"
value="lorem ipsum"/>
<input class="text" id="input-DISPLAY" name="DISPLAY" type="hidden" value="lorem ipsum"/>
</div>
<BLANKLINE>

Expand All @@ -470,6 +491,23 @@ Skip mode renders empty string.::
>>> widget()
u''

Multiple blueprints::

>>> widget = factory(
... 'label:text:help',
... name="textinput",
... props={
... 'label': 'label before input',
... 'help': 'help after input',
... }
... )
>>> wrapped_pxml(widget())
<div>
<label for="input-textinput">label before input</label>
<input class="text" id="input-textinput" name="textinput" type="text" value=""/>
<div class="help">help after input</div>
</div>
<BLANKLINE>

Datatype extraction
-------------------
Expand Down