]> source.dussan.org Git - vaadin-framework.git/commitdiff
Refactor node traversal and empty node removal. 58/358/1
authorHenri Sara <hesara@vaadin.com>
Fri, 23 Nov 2012 10:28:04 +0000 (12:28 +0200)
committerHenri Sara <hesara@vaadin.com>
Fri, 23 Nov 2012 10:28:26 +0000 (12:28 +0200)
Change-Id: If5c66e3fd01341636e481a093f90471c92755ce9

theme-compiler/src/com/vaadin/sass/ScssStylesheet.java
theme-compiler/src/com/vaadin/sass/tree/Node.java
theme-compiler/src/com/vaadin/sass/visitor/BlockNodeHandler.java

index 216b03edbe153b91e00d3083505e50deb94f96e9..a557187ab42795cfbaffc82520326e20e27a8d5a 100644 (file)
@@ -34,6 +34,7 @@ import com.vaadin.sass.handler.SCSSErrorHandler;
 import com.vaadin.sass.parser.Parser;
 import com.vaadin.sass.resolver.ScssStylesheetResolver;
 import com.vaadin.sass.resolver.VaadinResolver;
+import com.vaadin.sass.tree.BlockNode;
 import com.vaadin.sass.tree.MixinDefNode;
 import com.vaadin.sass.tree.Node;
 import com.vaadin.sass.tree.VariableNode;
@@ -136,6 +137,7 @@ public class ScssStylesheet extends Node {
         importOtherFiles(this);
         populateDefinitions(this);
         traverse(this);
+        removeEmptyBlocks(this);
     }
 
     private void importOtherFiles(ScssStylesheet node) {
@@ -197,30 +199,61 @@ public class ScssStylesheet extends Node {
         // Not used for ScssStylesheet
     }
 
-    public void traverse(Node node) {
+    /**
+     * Traverses a node and its children recursively, calling all the
+     * appropriate handlers via {@link Node#traverse()}.
+     * 
+     * The node itself may be removed during the traversal and replaced with
+     * other nodes at the same position or later on the child list of its
+     * parent.
+     * 
+     * @param node
+     *            node to traverse
+     * @return true if the node was removed (and possibly replaced by others),
+     *         false if not
+     */
+    public boolean traverse(Node node) {
+        Node originalParent = node.getParentNode();
+
         node.traverse();
 
         @SuppressWarnings("unchecked")
         HashMap<String, VariableNode> variableScope = (HashMap<String, VariableNode>) variables
                 .clone();
 
-        int maxSize = node.getChildren().size();
-        ArrayList<Node> oldChildren = new ArrayList<Node>(node.getChildren());
-        for (int i = 0; i < maxSize; i++) {
-
+        // the size of the child list may change on each iteration: current node
+        // may get deleted and possibly other nodes have been inserted where it
+        // was or after that position
+        for (int i = 0; i < node.getChildren().size(); i++) {
             Node current = node.getChildren().get(i);
-            traverse(current);
-
-            if (!node.getChildren().equals(oldChildren)) {
-                oldChildren = new ArrayList<Node>(node.getChildren());
-                maxSize = node.getChildren().size();
-                i = i - 1;
+            if (traverse(current)) {
+                // current has been removed
+                --i;
             }
-
         }
 
         variables.clear();
         variables.putAll(variableScope);
+
+        // has the node been removed from its parent?
+        if (originalParent != null) {
+            return !originalParent.getChildren().contains(node);
+        } else {
+            return false;
+        }
+    }
+
+    public void removeEmptyBlocks(Node node) {
+        // depth first for avoiding re-checking parents of removed nodes
+        for (Node child : new ArrayList<Node>(node.getChildren())) {
+            removeEmptyBlocks(child);
+        }
+        Node parent = node.getParentNode();
+        if (node instanceof BlockNode && node.getChildren().isEmpty()
+                && parent != null) {
+            // remove empty block
+            parent.removeChild(node);
+        }
     }
 
     public static void addVariable(VariableNode node) {
index ccbd6d64da8a5f19ad7db1a6740fc4beda4da2b7..aaf887b76b2667a3a599d089b13d2d5fd7652f30 100644 (file)
@@ -98,6 +98,11 @@ public abstract class Node implements Serializable {
 
     /**
      * Method for manipulating the data contained within the {@link Node}.
+     * 
+     * Traversing a node is allowed to modify the node, replace it with one or
+     * more nodes at the same or later position in its parent and modify the
+     * children of the node, but not modify or remove preceding nodes in its
+     * parent.
      */
     public abstract void traverse();
 
index f8f893b8fddf88036b4d54726e86bf105ad792fd..a131208ecef2b64c49aab9083f5f677b2fa3324d 100644 (file)
@@ -46,19 +46,13 @@ public class BlockNodeHandler {
 
     public static void traverse(BlockNode node) {
 
-        Node parent = node.getParentNode();
         if (node.getChildren().size() == 0) {
-            parent.removeChild(node);
-            while (parent != null && parent instanceof BlockNode
-                    && parent.getChildren().size() == 0) {
-                Node temp = parent;
-                parent = parent.getParentNode();
-                parent.removeChild(temp);
-            }
-
+            // empty blocks are removed later
             return;
         }
 
+        Node parent = node.getParentNode();
+
         if (parent instanceof BlockNode) {
             combineParentSelectorListToChild(node);