author | Tero Marttila <terom@fixme.fi> |
Thu, 20 Jan 2011 23:14:07 +0200 | |
changeset 58 | 4f4150296cd3 |
parent 50 | c3ae4c448248 |
child 60 | b364279347d9 |
permissions | -rw-r--r-- |
0
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
1 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
2 |
Generating XHTML output from nested python objects |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
3 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
4 |
XXX: use a 'real' XML builder? |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
5 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
6 |
To use: |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
7 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
8 |
>>> from html import tags |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
9 |
>>> str(tags.a(href="http://www.google.com")("Google <this>!")) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
10 |
'<a href="http://www.google.com">\\n\\tGoogle <this>!\\n</a>\\n' |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
11 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
12 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
13 |
from cgi import escape |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
14 |
import itertools as _itertools, types as _types |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
15 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
16 |
class IRenderable (object) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
17 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
18 |
Something that's renderable as the contents of a HTML tag. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
19 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
20 |
This is just used by Container for rendering Tags as actual HTML, vs just plain strs as escaped data. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
21 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
22 |
Additionally, some str vs unicode vs file stuff.. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
23 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
24 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
25 |
def render_raw_lines (self, indent=u'\t') : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
26 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
27 |
Render the indented lines for tag and contents, without newlines |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
28 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
29 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
30 |
abstract |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
31 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
32 |
def render_lines (self, indent=u'\t', newline=u'\n') : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
33 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
34 |
Render full output lines with given newlines |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
35 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
36 |
>>> list(Tag('xx', 'yy').render_lines()) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
37 |
[u'<xx>\\n', u'\\tyy\\n', u'</xx>\\n'] |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
38 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
39 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
40 |
for line in self.render_raw_lines(indent=indent) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
41 |
yield line + newline |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
42 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
43 |
def render_unicode (self, **render_opts) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
44 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
45 |
Render full tag as a single unicode string |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
46 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
47 |
>>> Tag('xx', 'yy').render_unicode() |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
48 |
u'<xx>\\n\\tyy\\n</xx>\\n' |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
49 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
50 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
51 |
return "".join(self.render_lines(**render_opts)) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
52 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
53 |
def render_str (self, encoding='ascii', **render_opts) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
54 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
55 |
Render full tag as an encoded string |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
56 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
57 |
>>> Tag('xx', 'yy').render_str() |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
58 |
'<xx>\\n\\tyy\\n</xx>\\n' |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
59 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
60 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
61 |
return self.render_unicode(**render_opts).encode(encoding) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
62 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
63 |
def render_out (self, stream, encoding=None, **render_opts) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
64 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
65 |
Render output into the given stream, encoding using the given encoding if given. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
66 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
67 |
>>> from StringIO import StringIO; buf = StringIO(); Tag('xx', 'yy').render_out(buf, 'ascii'); buf.getvalue() |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
68 |
'<xx>\\n\\tyy\\n</xx>\\n' |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
69 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
70 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
71 |
for line in self.render_lines(**render_opts) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
72 |
if encoding : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
73 |
line = line.encode(encoding) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
74 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
75 |
stream.write(line) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
76 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
77 |
def render_file (self, file, encoding=None, **render_opts) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
78 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
79 |
Render output to given file, overwriteing anything already there |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
80 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
81 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
82 |
self.render_out(file.open_write(encoding), **render_opts) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
83 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
84 |
# default output |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
85 |
__str__ = render_str |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
86 |
__unicode__ = render_unicode |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
87 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
88 |
# default .render method |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
89 |
render = render_unicode |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
90 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
91 |
class Container (IRenderable) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
92 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
93 |
A container holds a sequence of other renderable items. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
94 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
95 |
This is just used as the superclass for Tag, and just serves to gives us useful handling for e.g. generators as |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
96 |
tag contents (iterate through them instead of repr'ing them). |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
97 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
98 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
99 |
@classmethod |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
100 |
def process_contents (cls, contents) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
101 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
102 |
Postprocess contents iterable to return new list. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
103 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
104 |
Items that are None will be omitted from the return value. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
105 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
106 |
Certain core sequence types will be recognized and flattened for output: tuples, lists, and generators. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
107 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
108 |
>>> list(Container.process_contents([])) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
109 |
[] |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
110 |
>>> list(Container.process_contents([None])) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
111 |
[] |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
112 |
>>> list(Container.process_contents([u'foo'])) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
113 |
[u'foo'] |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
114 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
115 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
116 |
for content in contents : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
117 |
if content is None : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
118 |
continue |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
119 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
120 |
# Hardcoded list of special-case nested contents |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
121 |
elif isinstance(content, (_types.TupleType, _types.ListType, _types.GeneratorType)) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
122 |
for subcontent in cls.process_contents(content) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
123 |
yield subcontent |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
124 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
125 |
else : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
126 |
# normal, handle as IRenderable/unicode data |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
127 |
yield content |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
128 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
129 |
def __init__ (self, *contents) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
130 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
131 |
Construct this container with the given sub-items |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
132 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
133 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
134 |
# store postprocessed |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
135 |
self.contents = list(self.process_contents(contents)) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
136 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
137 |
def render_raw_lines (self, **render_opts) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
138 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
139 |
Render our contents as a series of non-indented lines, with the contents handling indentation themselves. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
140 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
141 |
>>> list(Container(5).render_raw_lines()) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
142 |
[u'5'] |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
143 |
>>> list(Container('line1', 'line2').render_raw_lines()) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
144 |
[u'line1', u'line2'] |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
145 |
>>> list(Container('a', Tag('b', 'bb'), 'c').render_raw_lines()) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
146 |
[u'a', u'<b>', u'\\tbb', u'</b>', u'c'] |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
147 |
>>> list(Container(Tag('hr'), Tag('foo')('bar')).render_raw_lines()) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
148 |
[u'<hr />', u'<foo>', u'\\tbar', u'</foo>'] |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
149 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
150 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
151 |
for content in self.contents : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
152 |
if isinstance(content, IRenderable) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
153 |
# sub-items |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
154 |
for line in content.render_raw_lines(**render_opts) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
155 |
yield line |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
156 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
157 |
else : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
158 |
# escape raw values |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
159 |
yield escape(unicode(content)) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
160 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
161 |
def __repr__ (self) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
162 |
return 'Container(%s)' % ', '.join(repr(c) for c in self.contents) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
163 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
164 |
class Tag (Container) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
165 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
166 |
A HTML tag, with attributes and contents, which can a mixture of data and other renderables(tags). |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
167 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
168 |
This is the core object, and the ~only one you really need to pay attention to. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
169 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
170 |
Provides various kinds of rendering output via IRenderable. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
171 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
172 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
173 |
@staticmethod |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
174 |
def process_attrs (attrs) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
175 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
176 |
Postprocess attributes. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
177 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
178 |
Key-value pairs where the value is None will be ommitted, and any trailing underscores in the key omitted. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
179 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
180 |
TODO: only remove one underscore |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
181 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
182 |
>>> dict(Tag.process_attrs(dict())) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
183 |
{} |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
184 |
>>> dict(Tag.process_attrs(dict(foo='bar'))) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
185 |
{'foo': 'bar'} |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
186 |
>>> dict(Tag.process_attrs(dict(class_='bar', frob=None))) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
187 |
{'class': 'bar'} |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
188 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
189 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
190 |
return ((k.rstrip('_'), v) for k, v in attrs.iteritems() if v is not None) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
191 |
|
5 | 192 |
def __init__ (self, _name, *contents, **attrs) : |
0
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
193 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
194 |
Construct tag with given name/attributes or contents. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
195 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
196 |
The filtering rules desribed in process_contents/process_attrs apply. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
197 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
198 |
>>> Tag('foo') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
199 |
Tag('foo') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
200 |
>>> Tag('foo', 'quux') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
201 |
Tag('foo', 'quux') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
202 |
>>> Tag('foo', 'quux', bar=5) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
203 |
Tag('foo', 'quux', bar=5) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
204 |
>>> Tag('foo', class_='ten') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
205 |
Tag('foo', class='ten') |
5 | 206 |
>>> Tag('bar', name='foo') |
207 |
Tag('bar', name='foo') |
|
0
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
208 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
209 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
210 |
# store contents as container |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
211 |
super(Tag, self).__init__(*contents) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
212 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
213 |
# store postprocessed stuff |
5 | 214 |
self.name = _name |
0
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
215 |
self.attrs = dict(self.process_attrs(attrs)) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
216 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
217 |
def __call__ (self, *contents, **attrs) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
218 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
219 |
Return a new Tag with this tag's attributes and contents, as well as the given attributes/contents. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
220 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
221 |
The filtering rules desribed in process_contents/process_attrs apply. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
222 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
223 |
>>> Tag('foo')('bar') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
224 |
Tag('foo', 'bar') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
225 |
>>> Tag('a', href='index.html')("Home") |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
226 |
Tag('a', 'Home', href='index.html') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
227 |
>>> Tag('bar', None)(5, foo=None, class_='bar') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
228 |
Tag('bar', 5, class='bar') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
229 |
>>> Tag('a')('b')('c')(asdf=5) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
230 |
Tag('a', 'b', 'c', asdf=5) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
231 |
>>> t1 = Tag('a'); t2 = t1('b'); t1 |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
232 |
Tag('a') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
233 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
234 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
235 |
# merge attrs/contents |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
236 |
# XXX: new_attrs is not an iterator... |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
237 |
new_attrs = dict(_itertools.chain(self.attrs.iteritems(), attrs.iteritems())) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
238 |
new_contents = _itertools.chain(self.contents, contents) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
239 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
240 |
# build new tag |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
241 |
return Tag(self.name, *new_contents, **new_attrs) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
242 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
243 |
@staticmethod |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
244 |
def format_attr (name, value) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
245 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
246 |
Format a single HTML tag attribute |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
247 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
248 |
>>> Tag.format_attr('name', 'value') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
249 |
u'name="value"' |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
250 |
>>> Tag.format_attr('this', '<a"b>') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
251 |
u'this="<a"b>"' |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
252 |
>>> Tag.format_attr('xx', 1337) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
253 |
u'xx="1337"' |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
254 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
255 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
256 |
return u'%s="%s"' % (name, escape(unicode(value), True)) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
257 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
258 |
def render_attrs (self) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
259 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
260 |
Return the HTML attributes string |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
261 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
262 |
>>> Tag('x', foo=5, bar='<').render_attrs() |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
263 |
u'foo="5" bar="<"' |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
264 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
265 |
|
8
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
266 |
return " ".join(self.format_attr(n, v) for n, v in self.attrs.iteritems() if not n.startswith('_')) |
0
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
267 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
268 |
def render_raw_lines (self, indent=u'\t') : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
269 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
270 |
Render the tag and indented content |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
271 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
272 |
>>> list(Tag('xx', 'yy', zz='foo').render_raw_lines(indent=' ')) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
273 |
[u'<xx zz="foo">', u' yy', u'</xx>'] |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
274 |
""" |
8
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
275 |
|
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
276 |
# opts |
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
277 |
selfclosing = self.attrs.get('_selfclosing') |
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
278 |
whitespace_sensitive = self.attrs.get('_whitespace_sensitive') |
0
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
279 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
280 |
# render attr string, including preceding space |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
281 |
attrs_stuff = (" " + self.render_attrs()) if self.attrs else "" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
282 |
|
8
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
283 |
if self.contents or selfclosing is False: |
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
284 |
|
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
285 |
if not whitespace_sensitive : |
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
286 |
# wrapping tags |
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
287 |
yield u"<%s%s>" % (self.name, attrs_stuff) |
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
288 |
|
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
289 |
# subcontents |
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
290 |
for line in super(Tag, self).render_raw_lines(indent=indent) : |
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
291 |
yield indent + line |
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
292 |
|
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
293 |
yield u"</%s>" % (self.name, ) |
0
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
294 |
|
8
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
295 |
else : |
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
296 |
# whole tag |
27e37082625e
html: Implement selfclosing and whitespace_sensitive options (for <textarea>s)
Tero Marttila <terom@fixme.fi>
parents:
5
diff
changeset
|
297 |
yield u"<%s%s>%s</%s>" % (self.name, attrs_stuff, ''.join(super(Tag, self).render_raw_lines(indent=indent)), self.name) |
0
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
298 |
else : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
299 |
# singleton tag |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
300 |
yield u"<%s%s />" % (self.name, attrs_stuff) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
301 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
302 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
303 |
def __repr__ (self) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
304 |
return 'Tag(%s)' % ', '.join( |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
305 |
[ |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
306 |
repr(self.name) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
307 |
] + [ |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
308 |
repr(c) for c in self.contents |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
309 |
] + [ |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
310 |
'%s=%r' % (name, value) for name, value in self.attrs.iteritems() |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
311 |
] |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
312 |
) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
313 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
314 |
class Text (IRenderable) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
315 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
316 |
Raw HTML text |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
317 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
318 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
319 |
def __init__ (self, line) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
320 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
321 |
Initialize to render as the given lines |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
322 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
323 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
324 |
self.lines = [line] |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
325 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
326 |
def render_raw_lines (self, indent=u'\t') : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
327 |
return self.lines |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
328 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
329 |
class Document (IRenderable) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
330 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
331 |
A full XHTML document with XML header, doctype, head and body. |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
332 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
333 |
XXX: current rendering is a bit of a kludge |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
334 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
335 |
<?xml version="..." encoding="..." ?> |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
336 |
<!DOCTYPE ...> |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
337 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
338 |
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
339 |
<head> |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
340 |
... |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
341 |
</head> |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
342 |
<body> |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
343 |
... |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
344 |
</body> |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
345 |
</html> |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
346 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
347 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
348 |
def __init__ (self, |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
349 |
head, body, |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
350 |
xml_version='1.0', xml_encoding='utf-8', |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
351 |
doctype='html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"', |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
352 |
html_xmlns='http://www.w3.org/1999/xhtml', html_lang='en' |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
353 |
) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
354 |
# store |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
355 |
self.xml_version = xml_version |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
356 |
self.xml_encoding = xml_encoding |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
357 |
self.doctype = doctype |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
358 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
359 |
# build the document |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
360 |
self.document = Tag('html', **{'xmlns': html_xmlns, 'xml:lang': html_lang})( |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
361 |
Tag('head', head), |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
362 |
Tag('body', body), |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
363 |
) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
364 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
365 |
def render_raw_lines (self, **render_opts) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
366 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
367 |
Render the two header lines, and then the document |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
368 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
369 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
370 |
yield '<?xml version="%s" encoding="%s" ?>' % (self.xml_version, self.xml_encoding) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
371 |
yield '<!DOCTYPE %s>' % (self.doctype) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
372 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
373 |
for line in self.document.render_raw_lines(**render_opts) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
374 |
yield line |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
375 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
376 |
def _check_encoding (self, encoding) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
377 |
if encoding and encoding != self.xml_encoding : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
378 |
raise ValueError("encoding mismatch: %r should be %r" % (encoding, self.xml_encoding)) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
379 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
380 |
def render_str (self, encoding=None, **render_opts) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
381 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
382 |
Wrap render_str to verify that the right encoding is used |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
383 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
384 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
385 |
self._check_encoding(encoding) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
386 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
387 |
return super(XHTMLDocument, self).render_str(self.xml_encoding, **render_opts) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
388 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
389 |
def render_out (self, stream, encoding=None, **render_opts) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
390 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
391 |
Wrap render_out to verify that the right encoding is used |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
392 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
393 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
394 |
self._check_encoding(encoding) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
395 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
396 |
return super(XHTMLDocument, self).render_out(stream, self.xml_encoding, **render_opts) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
397 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
398 |
class TagFactory (object) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
399 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
400 |
Build Tags with names give as attribute names |
50
c3ae4c448248
html: add tags.raw pseudo-tag for raw HTML processing
Tero Marttila <terom@fixme.fi>
parents:
8
diff
changeset
|
401 |
|
c3ae4c448248
html: add tags.raw pseudo-tag for raw HTML processing
Tero Marttila <terom@fixme.fi>
parents:
8
diff
changeset
|
402 |
>>> str(TagFactory().raw("><") |
c3ae4c448248
html: add tags.raw pseudo-tag for raw HTML processing
Tero Marttila <terom@fixme.fi>
parents:
8
diff
changeset
|
403 |
'><' |
0
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
404 |
""" |
58
4f4150296cd3
controllers: tidy up PageHandler a little
Tero Marttila <terom@fixme.fi>
parents:
50
diff
changeset
|
405 |
|
4f4150296cd3
controllers: tidy up PageHandler a little
Tero Marttila <terom@fixme.fi>
parents:
50
diff
changeset
|
406 |
# full XHTML document |
4f4150296cd3
controllers: tidy up PageHandler a little
Tero Marttila <terom@fixme.fi>
parents:
50
diff
changeset
|
407 |
document = Document |
50
c3ae4c448248
html: add tags.raw pseudo-tag for raw HTML processing
Tero Marttila <terom@fixme.fi>
parents:
8
diff
changeset
|
408 |
|
c3ae4c448248
html: add tags.raw pseudo-tag for raw HTML processing
Tero Marttila <terom@fixme.fi>
parents:
8
diff
changeset
|
409 |
# raw HTML |
c3ae4c448248
html: add tags.raw pseudo-tag for raw HTML processing
Tero Marttila <terom@fixme.fi>
parents:
8
diff
changeset
|
410 |
raw = Text |
0
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
411 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
412 |
def __getattr__ (self, name) : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
413 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
414 |
Get a Tag object with the given name, but no contents |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
415 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
416 |
>>> TagFactory().a(href='bar')('quux') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
417 |
Tag('a', 'quux', href='bar') |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
418 |
""" |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
419 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
420 |
return Tag(name) |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
421 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
422 |
# pretty names |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
423 |
container = Container |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
424 |
tag = Tag |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
425 |
tags = TagFactory() |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
426 |
raw = Text |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
427 |
document = Document |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
428 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
429 |
# testing |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
430 |
if __name__ == '__main__' : |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
431 |
import doctest |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
432 |
|
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
433 |
doctest.testmod() |
b28a1681e79b
Initial layout, with hello-world
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
434 |