Skip to content
This repository has been archived by the owner on Jun 4, 2024. It is now read-only.

add basic HTML serializer for header and footer #29

Closed
wants to merge 3 commits into from
Closed
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
2 changes: 2 additions & 0 deletions dash_html_components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import dash as _dash
import sys as _sys
from .version import __version__
from ._to_html5 import _to_html5

_current_path = _os.path.dirname(_os.path.abspath(__file__))

Expand All @@ -24,3 +25,4 @@
for component in _components:
setattr(_this_module, component.__name__, component)
setattr(component, '_js_dist', _js_dist)
setattr(component, 'to_html5', _to_html5)
65 changes: 65 additions & 0 deletions dash_html_components/_to_html5.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import collections
from dash.development.base_component import Component
import re

_VOID_ELEMENTS = [
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen',
'link', 'meta', 'param', 'source', 'track', 'wbr'
]

_CAMELCASE_REGEX = re.compile('([a-z0-9])([A-Z])')


def _camel_case_to_css_case(name):
return _CAMELCASE_REGEX.sub(r'\1-\2', name).lower()


def _attribute(name, value):
if name == 'className':
return ('class', value,)
elif name == 'style':
# Dash CSS is camel-cased but CSS is hyphenated
# convert e.g. fontColor to font-color
inline_style = '; '.join([
'='.join([_camel_case_to_css_case(k), v])
for (k, v) in value.iteritems()

Choose a reason for hiding this comment

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

Seems as though the = should be an :

])
return (name, inline_style,)
else:
return (name, value,)


def _to_html5(self):
def __to_html5(component):
if not isinstance(component, Component):
return str(component)
component_type = component._type.lower()

children = ''
if component_type not in _VOID_ELEMENTS:
children = getattr(component, 'children', '')
if isinstance(children, Component):
children = __to_html5(children)
elif isinstance(children, collections.MutableSequence):
children = '\n'.join([__to_html5(child) for child in children])
else:
children = str(children)
if children != '':
children = '\n' + children

closing = ''
if component_type not in _VOID_ELEMENTS:
closing = '\n</{}>'.format(component_type)

return '<{type}{properties}>{children}{closing}'.format(
type=component_type,
properties=''.join([
' {}="{}"'.format(
_attribute(p, getattr(component, p)))
for p in component._prop_names
if (hasattr(component, p) and p is not 'children')
]),
children=children,
closing=closing)

return __to_html5(self)
74 changes: 74 additions & 0 deletions tests/test_dash_html_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,77 @@ def test_sample_items(self):
self.assertEqual(
layout._namespace, 'dash_html_components'
)

def test_to_html5(self):
test_cases = [
{
'name': 'None Children',
'input': html.Div(),
'output': '<div></div>'
},
{
'name': 'Text Children',
'input': html.Script('alert'),
'output': '<script>alert</script>'
},
{
'name': 'Numerical Children',
'input': html.Div(3),
'output': '<div>3</div>'
},
{
'name': 'Single Attribute',
'input': html.Script('alert', type='text/javascript'),
'output': '<script type="text/javascript">alert</script>'
},
{
'name': 'Multiple Attributes',
'input': html.A(href='codepen', target='_blank'),
'output': '<a href="codepen" target="_blank"></a>'
},
{
'name': 'Void Elements',
'input': html.Link(rel='stylesheet', type='text/css'),
'output': '<link rel="stylesheet" type="text/css">'
},
{
'name': 'Style',
'input': html.Div(style={'fontSize': '15px', 'color': 'blue'}),
'output': '<div style="font-size: 15px; color: blue"></div>'
},
{
'name': 'className',
'input': html.Div(className='container'),
'output': '<div class="container"></div>'
},
{
'name': 'Nested Children',
'input': html.Div([
3,
html.H1('header'),
html.Div(),
html.Div(
html.P([
html.Img(src='imgur', className='full-bleed')
])
)
], className='parent'),
'output': '\n'.join([
'<div class="parent">',
'3',
'<h1>header</h1>',
'<div></div>',
'<div>',
'<p>',
'<img src="imgur" class="full-bleed">'
'</p>',
'</div>',
'</div>'
])
}
]
for test_case in test_cases:
self.assertEqual(
test_case['input'].to_html5(),
test_case['output']
)