Commits

Luke Plant committed a81d847

Implemented layout of inner rows and columns.

Implementation is fairly hideous, but serves as a basic working point.

Comments (0)

Files changed (2)

semanticeditor/tests.py

         outh = "<div class=\"row\"><div><div><h1>1</h1><p>para 1</p><h2>2</h2></div></div></div>"
         self.assertEqual(outh, format_html(html, {'h1_1':[NEWROW]}))
 
+    def test_nested_layout(self):
+        html = ("<h1>1</h1>"
+                "<h1>2</h1>"
+                "<h1>3</h1>"
+                "<h1>4</h1>"
+                "<h1>5</h1>"
+                "<h1>6</h1>"
+                "<h1>7</h1>")
+        # - row 1:
+        #   - 3 columns
+        #   - middle column has inner row structure with
+        #     - 1 row
+        #     - 2 columns
+        # - row 2:
+        #   - 2 columns
+        pres = {'newrow_h1_1':[NEWROW],
+                'newcol_h1_2':[NEWCOL],
+                'newinnerrow_h1_3':[NEWINNERROW],
+                'newinnercol_h1_4':[NEWINNERCOL],
+                'newcol_h1_5':[NEWCOL],
+                'newrow_h1_6':[NEWROW],
+                'newcol_h1_7':[NEWCOL],
+                }
+        outh = ('<div class="row columns3">'
+                  '<div class="column firstcolumn">'
+                    '<div><h1>1</h1></div>'
+                  '</div>'
+                  '<div class="column">'
+                    '<div>'
+                      '<h1>2</h1>'
+                      '<div class="row columns2">'
+                        '<div class="column firstcolumn">'
+                          '<div><h1>3</h1></div>'
+                        '</div>'
+                        '<div class="column lastcolumn">'
+                          '<div><h1>4</h1></div>'
+                        '</div>'
+                      '</div>'
+                    '</div>'
+                  '</div>'
+                  '<div class="column lastcolumn">'
+                      '<div><h1>5</h1></div>'
+                  '</div>'
+                '</div>'
+                '<div class="row columns2">'
+                  '<div class="column firstcolumn">'
+                    '<div><h1>6</h1></div>'
+                  '</div>'
+                  '<div class="column lastcolumn">'
+                    '<div><h1>7</h1></div>'
+                  '</div>'
+                '</div>'
+                )
+        self.assertEqual(outh, format_html(html, pres))
+
+    def test_nested_layout_2(self):
+        html = ("<h1>1</h1>"
+                "<h1>2</h1>"
+                "<h1>3</h1>"
+                "<h1>4</h1>")
+        # - row 1:
+        #   - 2 columns
+        #   - 2nd middle column has inner row structure with
+        #     - 1 row
+        #     - 2 columns
+        pres = {'newrow_h1_1':[NEWROW],
+                'newcol_h1_2':[NEWCOL],
+                'newinnerrow_h1_3':[NEWINNERROW],
+                'newinnercol_h1_4':[NEWINNERCOL],
+                }
+        outh = ('<div class="row columns2">'
+                  '<div class="column firstcolumn">'
+                    '<div><h1>1</h1></div>'
+                  '</div>'
+                  '<div class="column lastcolumn">'
+                    '<div>'
+                      '<h1>2</h1>'
+                      '<div class="row columns2">'
+                        '<div class="column firstcolumn">'
+                          '<div><h1>3</h1></div>'
+                        '</div>'
+                        '<div class="column lastcolumn">'
+                          '<div><h1>4</h1></div>'
+                        '</div>'
+                      '</div>'
+                    '</div>'
+                  '</div>'
+                '</div>'
+                )
+        self.assertEqual(outh, format_html(html, pres))
+
+    def test_max_cols_nested(self):
+        """
+        Tests the error message for when the first col contains a nested layout.
+        """
+        html = "<h1>1</h1><h1>2</h1><h1>3</h1><h1>4</h1><h1>5</h1><h1>6</h1>"
+        self.assertRaises(TooManyColumns, format_html, html,
+                          {'newrow_h1_1':[NEWROW],
+                           'newinnerrow_h1_1':[NEWINNERROW],
+                           'newinnercol_h1_2':[NEWINNERCOL],
+                           'newcol_h1_3':[NEWCOL],
+                           'newcol_h1_4':[NEWCOL],
+                           'newcol_h1_5':[NEWCOL],
+                           'newcol_h1_6':[NEWCOL],
+                           })
+
+
     def test_format_pre(self):
         html = "<pre>This\r\nis\r\na\r\ntest</pre>"
         # check that format_html doesn't do anything nasty inside the pre

semanticeditor/utils/presentation.py

     def __init__(self, node):
         self.node = node
 
-    def as_nodes(self):
+    def as_nodes(self, layout_strategy):
         return [self.node]
 
 # Layout contains a list of content, where content can be either ElementTree
-# nodes or LayoutRows.
+# nodes (wrapped in NodeContent) or LayoutRows.
 class Layout(list):
 
     def as_nodes(self, layout_strategy):
                 else:
                     contentdiv = coldiv
                 for n in col.content:
-                    contentdiv.extend(n.as_nodes())
+                    contentdiv.extend(n.as_nodes(layout_strategy))
                 rowdiv.append(coldiv)
 
                 logical_column_num += _layout_column_width(col)
     command_info = _find_layout_commands(root, structure, styleinfo)
     row_info = command_info[NEWROW.name]
     col_info = command_info[NEWCOL.name]
+    innerrow_info = command_info[NEWINNERROW.name]
+    innercol_info = command_info[NEWINNERCOL.name]
 
     # Build a Layout structure
 
     layout = Layout()
     row = LayoutRow()
     col = LayoutColumn()
+    innerlayout = None
+    innercol = None
+    innerrow = None
     sect_dict = dict((si.node, si) for si in structure)
 
     # Build Layout
             if row_presinfo is not None:
                 # We have a NEWROW against si.sect_id
 
+                # Finish any inner rows/columns
+                if innercol is not None and innercol.content:
+                    innerrow.columns.append(innercol)
+                    if innerrow.columns:
+                        innerlayout.append(innerrow)
+                    col.content.append(innerlayout)
+                    innerlayout = None
+                    innercol = None
+                    innerrow = None
+
                 # Finish current col and row, if they have anything in them
                 if col.content:
                     row.columns.append(col)
                 # Start new col
                 col = LayoutColumn()
 
+
             col_presinfo = col_info.get(si.sect_id)
             if col_presinfo is not None:
                 # We have NEWCOL against si.sect_id
 
+                # Finish any inner rows/columns
+                if innercol is not None and innercol.content:
+                    innerrow.columns.append(innercol)
+                    if innerrow.columns:
+                        innerlayout.append(innerrow)
+                    col.content.append(innerlayout)
+                    innerlayout = None
+                    innercol = None
+                    innerrow = None
+
                 # Finish current col, if it is non-empty
                 if col.content:
                     row.columns.append(col)
                 # Start new col with styles
                 col = LayoutColumn(presinfo=col_presinfo)
 
+            innerrow_presinfo = innerrow_info.get(si.sect_id)
+            if innerrow_presinfo is not None:
+                # We have a NEWINNERROW against si.sect_id
+
+                # Finish current col and row, if they have anything in them
+                if innerlayout is None:
+                    innerlayout = Layout()
+                    innerrow = LayoutRow()
+                    innercol = LayoutColumn()
+                else:
+                    if innercol.content:
+                        innerrow.columns.append(innercol)
+                    if innerrow.columns:
+                        innerlayout.append(innerrow)
+
+                    # Start new inner row
+                    innerrow = LayoutRow(innerrow_presinfo)
+                    # Start new inner column
+                    innercol = LayoutColumn()
+
+            innercol_presinfo = innercol_info.get(si.sect_id)
+            if innercol_presinfo is not None:
+                # We have NEWINNERCOL against si.sect_id
+
+                # Finish current col, if it is non-empty
+                if innerlayout is None:
+                    # This could occur if there an NEWINNERROW command was
+                    # missing.
+                    innerlayout = Layout()
+                    innerrow = LayoutRow()
+                    innercol = LayoutColumn()
+                elif innercol.content:
+                    innerrow.columns.append(innercol)
+                # Start new col with styles
+                innercol = LayoutColumn(presinfo=innercol_presinfo)
+
         # Now deal with content itself
-        col.content.append(NodeContent(node))
+        if innercol is not None:
+            innercol.content.append(NodeContent(node))
+        else:
+            col.content.append(NodeContent(node))
+
+    # Finish any inner rows/columns
+    if innercol is not None and innercol.content:
+        innerrow.columns.append(innercol)
+        if innerrow.columns:
+            innerlayout.append(innerrow)
+        col.content.append(innerlayout)
 
     # Close last col and row
     if col.content:
             # Because columns can be multiple width, we can't easily work out
             # which column needs to be moved, so just refer user to whole
             # section.
-            node = row.columns[0].content[0].as_nodes()[0]
-            sect = sect_dict[node]
+
+            nodes = row.columns[0].content[0].as_nodes(layout_strategy)
+            while True:
+                # nodes[0] might be a div created for layout.  If so, it won't
+                # be in sect_dict. But one of its children will be.
+                sect = sect_dict.get(nodes[0], None)
+                if sect is not None:
+                    break
+                else:
+                    nodes = nodes[0]
+
             raise TooManyColumns("The maximum number of columns is %(max)d. "
                                  "Please adjust columns in section '%(name)s'." %
                                  dict(max=max_cols, name=sect.name))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.