@@ -20,6 +20,8 @@ class Element:
2020 values must be (string | list of strings | dict of styles)
2121 content : (None | string | list of (strings and/or elements)
2222 elements must have a 'render' method that returns valid html.
23+ <style> tag gets special handling. You may pass the css as a dict of
24+ the form {'selector': {'property':'value', ...}, ...}
2325
2426 Instance methods:
2527 render()
@@ -49,13 +51,21 @@ class Element:
4951 >>> doc.render()
5052 '<html><head></head><body style="background-color:black;"><h1>Title</h1><br/></body></html>'
5153
54+ >>> style = E('style', None, {'p.myclass': {'margin': '4px', 'font-color': 'blue'}})
55+ >>> style.render()
56+ '<style>p.myclass { margin:4px; font-color:blue; }</style>'
5257 """
5358 def __init__ (self , tagname , attrs , content ):
5459 ## Validate arguments
5560 assert isinstance (tagname , str )
61+ if tagname == '!--' :
62+ raise ValueError ("Sorry, can't handle html comments yet." )
5663 assert isinstance (attrs , (dict , type (None )))
57- assert isinstance (content , (list , str , type (None ))) ## None means an 'empty' element with no closing tag
58- self .T = tagname
64+ if tagname .lower () == 'style' :
65+ assert isinstance (content , (str , dict ))
66+ else :
67+ assert isinstance (content , (list , str , type (None ))) ## None means an 'empty' element with no closing tag
68+ self .T = tagname .lower ()
5969 self .A = attrs
6070 self .C = content
6171
@@ -69,11 +79,13 @@ def render(self):
6979 a = a .replace ('_' , '-' ) ## replace underscores with hyphens
7080 if isinstance (v , str ):
7181 rlist .append (' {}="{}"' .format (a ,v ))
82+ elif v is None :
83+ rlist .append (' {}' .format (a )) # bare attribute, e.g. 'disabled'
7284 elif isinstance (v ,list ):
7385 _ = ' ' .join (v ) ## must be list of strings
7486 rlist .append (' {}="{}"' .format (a , _ ))
7587 elif isinstance (v ,dict ) and a == 'style' :
76- rlist .append (' {}="{}"' .format (a ,renderstyle (v )))
88+ rlist .append (' {}="{}"' .format (a ,renderInlineStyle (v )))
7789 else :
7890 msg = "Don't know what to with {}={}" .format (a ,v )
7991 raise ValueError (msg )
@@ -90,6 +102,8 @@ def render(self):
90102 ## render the content
91103 if isinstance (self .C , str ):
92104 rlist .append (self .C )
105+ elif self .T == "style" :
106+ rlist .append (renderCss (self .C ))
93107 else :
94108 for c in self .C :
95109 if isinstance (c , str ):
@@ -107,22 +121,40 @@ def render(self):
107121
108122 return '' .join (rlist )
109123
110- def renderstyle (d ):
124+ def renderInlineStyle (d ):
111125 """If d is a dict of styles, return a proper style string """
112126 if isinstance (d , dict ):
113127 style = []
114128 for k ,v in d .items ():
115129 ## for convenience, convert underscores in keys to hyphens
116130 kh = k .replace ('_' , '-' )
117131 style .append ("{}:{};" .format (kh , v ))
118- result = ' ' .join (style )
132+ separator = ' '
133+ result = separator .join (style )
119134 elif isinstance (d , str ):
120135 result = d
121136 else :
122137 msg = "Cannot convert {} to style string" .format (d )
123138 raise TypeError (msg )
124139 return result
125140
141+ def renderCss (d , newlines = True ):
142+ """ If d is a dict of rulesets, render a string of CSS rulesets """
143+ if not isinstance (d , dict ):
144+ msg = "Expected dictionary of CSS rulesets, got {}." .format (d )
145+ raise TypeError (msg )
146+ else :
147+ rulesetlist = []
148+ for selector , declaration in d .items ():
149+ #print("In renderCss with selector = {}".format(selector))
150+ if not isinstance (selector , str ):
151+ msg = "Expected selector string, got {}" .format (selector )
152+ raise TypeError (msg )
153+
154+ ruleset = [selector , '{' , renderInlineStyle (declaration ), '}' ]
155+ rulesetlist .append (" " .join (ruleset ))
156+ separator = '\n ' if newlines else ' '
157+ return separator .join (rulesetlist )
126158
127159## The 'skip' pragma tells the Transcrypt Python to JS transpiler to
128160## ignore a section of code. It's needed here because the 'run as script'
0 commit comments