1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """render a tree in HTML.
19
20
21
22
23 """
24 __docformat__ = "restructuredtext en"
25
26
28 """
29 Generate a pure HTML representation of a tree given as an instance
30 of a logilab.common.tree.Node
31
32 selected_node is the currently selected node (if any) which will
33 have its surrounding <div> have id="selected" (which default
34 to a bold border libe with the default CSS).
35
36 render_node is a function that should take a Node content (Node.id)
37 as parameter and should return a string (what will be displayed
38 in the cell).
39
40 Warning: proper rendering of the generated html code depends on html_tree.css
41 """
42 tree_depth = tree.depth_down()
43 if render_node is None:
44 render_node = str
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 def build_matrix(path, matrix):
64 if path[-1].is_leaf():
65 matrix.append(path[:])
66 else:
67 for child in path[-1].children:
68 build_matrix(path[:] + [child], matrix)
69
70 matrix = []
71 build_matrix([tree], matrix)
72
73
74 for line in matrix:
75 line.extend([None]*(tree_depth-len(line)))
76 for i in range(len(matrix)-1, 0, -1):
77 prev_line, line = matrix[i-1:i+1]
78 for j in range(len(line)):
79 if line[j] == prev_line[j]:
80 line[j] = None
81
82
83
84 link_types = {(True, True, True ): 1,
85 (False, False, True ): 2,
86 (False, True, True ): 3,
87 (False, True, False): 4,
88 (True, True, False): 5,
89 }
90 links = []
91 for i, line in enumerate(matrix):
92 links.append([])
93 for j in range(tree_depth-1):
94 cell_11 = line[j] is not None
95 cell_12 = line[j+1] is not None
96 cell_21 = line[j+1] is not None and line[j+1].next_sibling() is not None
97 link_type = link_types.get((cell_11, cell_12, cell_21), 0)
98 if link_type == 0 and i > 0 and links[i-1][j] in (1, 2, 3):
99 link_type = 2
100 links[-1].append(link_type)
101
102
103
104 s = u'<table class="tree">\n'
105 if caption:
106 s += '<caption>%s</caption>\n' % caption
107
108 for i, link_line in enumerate(links):
109 line = matrix[i]
110
111 s += '<tr>'
112 for j, link_cell in enumerate(link_line):
113 cell = line[j]
114 if cell:
115 if cell.id == selected_node:
116 s += '<td class="tree_cell" rowspan="2"><div class="selected tree_cell">%s</div></td>' % (render_node(cell.id))
117 else:
118 s += '<td class="tree_cell" rowspan="2"><div class="tree_cell">%s</div></td>' % (render_node(cell.id))
119 else:
120 s += '<td rowspan="2"> </td>'
121 s += '<td class="tree_cell_%d_1"> </td>' % link_cell
122 s += '<td class="tree_cell_%d_2"> </td>' % link_cell
123
124 cell = line[-1]
125 if cell:
126 if cell.id == selected_node:
127 s += '<td class="tree_cell" rowspan="2"><div class="selected tree_cell">%s</div></td>' % (render_node(cell.id))
128 else:
129 s += '<td class="tree_cell" rowspan="2"><div class="tree_cell">%s</div></td>' % (render_node(cell.id))
130 else:
131 s += '<td rowspan="2"> </td>'
132
133 s += '</tr>\n'
134 if link_line:
135 s += '<tr>'
136 for j, link_cell in enumerate(link_line):
137 s += '<td class="tree_cell_%d_3"> </td>' % link_cell
138 s += '<td class="tree_cell_%d_4"> </td>' % link_cell
139 s += '</tr>\n'
140
141 s += '</table>'
142 return s
143