diff options
author | Aurelien Campeas <aurelien.campeas@logilab.fr> | 2009-08-20 12:57:04 +0200 |
---|---|---|
committer | Aurelien Campeas <aurelien.campeas@logilab.fr> | 2009-08-20 12:57:04 +0200 |
commit | 2152e5f42897a8f6de6475c49e671f802dc71df8 (patch) | |
tree | fcc2dc937fbac9a7092b7ffcd753bbcdafc774de | |
parent | 1b31b5f655b08f3ba2112b3b4575ec92706498d9 (diff) | |
download | logilab-common-2152e5f42897a8f6de6475c49e671f802dc71df8.tar.gz |
[html] resurrect html module with functionnality from cubicweb.ui (actually not used in cw)
-rw-r--r-- | decorators.py | 1 | ||||
-rw-r--r-- | html.py | 125 | ||||
-rw-r--r-- | test/unittest_html.py | 59 |
3 files changed, 184 insertions, 1 deletions
diff --git a/decorators.py b/decorators.py index d7768a0..f5278cc 100644 --- a/decorators.py +++ b/decorators.py @@ -81,7 +81,6 @@ def copy_cache(obj, funcname, cacheobj): except KeyError: pass - class wproperty(object): """Simple descriptor expecting to take a modifier function as first argument and looking for a _<function name> to retrieve the attribute. @@ -0,0 +1,125 @@ +"""render a tree in HTML. + +:copyright: 2000-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +:license: General Public License version 2 - http://www.gnu.org/licenses +""" +__docformat__ = "restructuredtext en" + + +def render_HTML_tree(tree, selected_node=None, render_node=None, caption=None): + """ + Generate a pure HTML representation of a tree given as an instance + of a logilab.common.tree.Node + + selected_node is the currently selected node (if any) which will + have its surrounding <div> have id="selected" (which default + to a bold border libe with the default CSS). + + render_node is a function that should take a Node content (Node.id) + as parameter and should return a string (what will be displayed + in the cell). + + Warning: proper rendering of the generated html code depends on html_tree.css + """ + tree_depth = tree.depth_down() + if render_node is None: + render_node = str + + # helper function that build a matrix from the tree, like: + # +------+-----------+-----------+ + # | root | child_1_1 | child_2_1 | + # | root | child_1_1 | child_2_2 | + # | root | child_1_2 | | + # | root | child_1_3 | child_2_3 | + # | root | child_1_3 | child_2_4 | + # +------+-----------+-----------+ + # from: + # root -+- child_1_1 -+- child_2_1 + # | | + # | +- child_2_2 + # +- child_1_2 + # | + # +- child1_3 -+- child_2_3 + # | + # +- child_2_2 + def build_matrix(path, matrix): + if path[-1].is_leaf(): + matrix.append(path[:]) + else: + for child in path[-1].children: + build_matrix(path[:] + [child], matrix) + + matrix = [] + build_matrix([tree], matrix) + + # make all lines in the matrix have the same number of columns + for line in matrix: + line.extend([None]*(tree_depth-len(line))) + for i in range(len(matrix)-1, 0, -1): + prev_line, line = matrix[i-1:i+1] + for j in range(len(line)): + if line[j] == prev_line[j]: + line[j] = None + + # We build the matrix of link types (between 2 cells on a line of the matrix) + # link types are : + link_types = {(True, True, True ): 1, # T + (False, False, True ): 2, # | + (False, True, True ): 3, # + (actually, vert. bar with horiz. bar on the right) + (False, True, False): 4, # L + (True, True, False): 5, # - + } + links = [] + for i, line in enumerate(matrix): + links.append([]) + for j in range(tree_depth-1): + cell_11 = line[j] is not None + cell_12 = line[j+1] is not None + cell_21 = line[j+1] is not None and line[j+1].next_sibling() is not None + link_type = link_types.get((cell_11, cell_12, cell_21), 0) + if link_type == 0 and i > 0 and links[i-1][j] in (1, 2, 3): + link_type = 2 + links[-1].append(link_type) + + + # We can now generate the HTML code for the <table> + s = u'<table class="tree">\n' + if caption: + s += '<caption>%s</caption>\n' % caption + + for i, link_line in enumerate(links): + line = matrix[i] + + s += '<tr>' + for j, link_cell in enumerate(link_line): + cell = line[j] + if cell: + if cell.id == selected_node: + s += '<td class="tree_cell" rowspan="2"><div id="selected" class="tree_cell">%s</div></td>' % (render_node(cell.id)) + else: + s += '<td class="tree_cell" rowspan="2"><div class="tree_cell">%s</div></td>' % (render_node(cell.id)) + else: + s += '<td rowspan="2"> </td>' + s += '<td class="tree_cell_%d_1"> </td>' % link_cell + s += '<td class="tree_cell_%d_2"> </td>' % link_cell + + cell = line[-1] + if cell: + if cell.id == selected_node: + s += '<td class="tree_cell" rowspan="2"><div id="selected" class="tree_cell">%s</div></td>' % (render_node(cell.id)) + else: + s += '<td class="tree_cell" rowspan="2"><div class="tree_cell">%s</div></td>' % (render_node(cell.id)) + else: + s += '<td rowspan="2"> </td>' + + s += '</tr>\n' + if link_line: + s += '<tr>' + for j, link_cell in enumerate(link_line): + s += '<td class="tree_cell_%d_3"> </td>' % link_cell + s += '<td class="tree_cell_%d_4"> </td>' % link_cell + s += '</tr>\n' + + s += '</table>' + return s diff --git a/test/unittest_html.py b/test/unittest_html.py new file mode 100644 index 0000000..927425f --- /dev/null +++ b/test/unittest_html.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +"""unittests for logilab.common.html + +:organization: Logilab +:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses +""" + +__docformat__ = "restructuredtext en" + +from logilab.common.testlib import TestCase, unittest_main +from logilab.common.tree import Node + +from logilab.common import html + +tree = ('root', ( + ('child_1_1', ( + ('child_2_1', ()), ('child_2_2', ( + ('child_3_1', ()), + ('child_3_2', ()), + ('child_3_3', ()), + )))), + ('child_1_2', (('child_2_3', ()),)))) + +generated_html = """\ +<table class="tree"> +<tr><td class="tree_cell" rowspan="2"><div class="tree_cell">root</div></td><td class="tree_cell_1_1"> </td><td class="tree_cell_1_2"> </td><td class="tree_cell" rowspan="2"><div class="tree_cell">child_1_1</div></td><td class="tree_cell_1_1"> </td><td class="tree_cell_1_2"> </td><td class="tree_cell" rowspan="2"><div class="tree_cell">child_2_1</div></td><td class="tree_cell_0_1"> </td><td class="tree_cell_0_2"> </td><td rowspan="2"> </td></tr> +<tr><td class="tree_cell_1_3"> </td><td class="tree_cell_1_4"> </td><td class="tree_cell_1_3"> </td><td class="tree_cell_1_4"> </td><td class="tree_cell_0_3"> </td><td class="tree_cell_0_4"> </td></tr> +<tr><td rowspan="2"> </td><td class="tree_cell_2_1"> </td><td class="tree_cell_2_2"> </td><td rowspan="2"> </td><td class="tree_cell_4_1"> </td><td class="tree_cell_4_2"> </td><td class="tree_cell" rowspan="2"><div id="selected" class="tree_cell">child_2_2</div></td><td class="tree_cell_1_1"> </td><td class="tree_cell_1_2"> </td><td class="tree_cell" rowspan="2"><div class="tree_cell">child_3_1</div></td></tr> +<tr><td class="tree_cell_2_3"> </td><td class="tree_cell_2_4"> </td><td class="tree_cell_4_3"> </td><td class="tree_cell_4_4"> </td><td class="tree_cell_1_3"> </td><td class="tree_cell_1_4"> </td></tr> +<tr><td rowspan="2"> </td><td class="tree_cell_2_1"> </td><td class="tree_cell_2_2"> </td><td rowspan="2"> </td><td class="tree_cell_0_1"> </td><td class="tree_cell_0_2"> </td><td rowspan="2"> </td><td class="tree_cell_3_1"> </td><td class="tree_cell_3_2"> </td><td class="tree_cell" rowspan="2"><div class="tree_cell">child_3_2</div></td></tr> +<tr><td class="tree_cell_2_3"> </td><td class="tree_cell_2_4"> </td><td class="tree_cell_0_3"> </td><td class="tree_cell_0_4"> </td><td class="tree_cell_3_3"> </td><td class="tree_cell_3_4"> </td></tr> +<tr><td rowspan="2"> </td><td class="tree_cell_2_1"> </td><td class="tree_cell_2_2"> </td><td rowspan="2"> </td><td class="tree_cell_0_1"> </td><td class="tree_cell_0_2"> </td><td rowspan="2"> </td><td class="tree_cell_4_1"> </td><td class="tree_cell_4_2"> </td><td class="tree_cell" rowspan="2"><div class="tree_cell">child_3_3</div></td></tr> +<tr><td class="tree_cell_2_3"> </td><td class="tree_cell_2_4"> </td><td class="tree_cell_0_3"> </td><td class="tree_cell_0_4"> </td><td class="tree_cell_4_3"> </td><td class="tree_cell_4_4"> </td></tr> +<tr><td rowspan="2"> </td><td class="tree_cell_4_1"> </td><td class="tree_cell_4_2"> </td><td class="tree_cell" rowspan="2"><div class="tree_cell">child_1_2</div></td><td class="tree_cell_5_1"> </td><td class="tree_cell_5_2"> </td><td class="tree_cell" rowspan="2"><div class="tree_cell">child_2_3</div></td><td class="tree_cell_0_1"> </td><td class="tree_cell_0_2"> </td><td rowspan="2"> </td></tr> +<tr><td class="tree_cell_4_3"> </td><td class="tree_cell_4_4"> </td><td class="tree_cell_5_3"> </td><td class="tree_cell_5_4"> </td><td class="tree_cell_0_3"> </td><td class="tree_cell_0_4"> </td></tr> +</table>\ +""" + +def make_tree(tupletree): + n = Node(tupletree[0]) + for child in tupletree[1]: + n.append(make_tree(child)) + return n + +class UIlibHTMLGenerationTC(TestCase): + """ a basic tree node, caracterised by an id""" + def setUp(self): + """ called before each test from this class """ + self.o = make_tree(tree) + + def test_generated_html(self): + s = html.render_HTML_tree(self.o, selected_node="child_2_2") + self.assertTextEqual(s, generated_html) + + +if __name__ == '__main__': + unittest_main() |