1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
from __future__ import unicode_literals
from .writers.html import HtmlWriter
class HtmlGenerator(object):
def __init__(self):
self._stack = []
self._writer = HtmlWriter()
def text(self, text):
if text:
self._write_all()
self._writer.text(text)
def start(self, name, attributes=None, always_write=False):
self._stack.append(_Element(name, attributes))
if always_write:
self._write_all()
def end(self):
element = self._stack.pop()
if element.written:
self._writer.end(element.name)
def end_all(self):
while self._stack:
self.end()
def self_closing(self, name, attributes=None):
self._writer.self_closing(name, attributes)
def _write_all(self):
for element in self._stack:
if not element.written:
element.written = True
self._write_element(element)
def _write_element(self, element):
self._writer.start(element.name, element.attributes)
def append(self, other):
other_string = other.as_string()
if other_string:
self._write_all()
self._writer.append(other_string)
def as_string(self):
return self._writer.as_string()
class _Element(object):
def __init__(self, name, attributes):
if attributes is None:
attributes = {}
self.name = name
self.attributes = attributes
self.written = False
def satisfy_html_path(generator, path):
first_unsatisfied_index = _find_first_unsatisfied_index(generator, path)
while len(generator._stack) > first_unsatisfied_index:
generator.end()
for element in path.elements[first_unsatisfied_index:]:
attributes = {}
if element.class_names:
attributes["class"] = _generate_class_attribute(element)
generator.start(element.names[0], attributes=attributes)
def _find_first_unsatisfied_index(generator, path):
for index, (generated_element, path_element) in enumerate(zip(generator._stack, path.elements)):
if not _is_element_match(generated_element, path_element):
return index
return len(generator._stack)
def _is_element_match(generated_element, path_element):
return (
not path_element.fresh and
generated_element.name in path_element.names and
generated_element.attributes.get("class", "") == _generate_class_attribute(path_element)
)
def _generate_class_attribute(path_element):
return " ".join(path_element.class_names)
|