You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by aw...@apache.org on 2009/04/20 22:24:01 UTC

svn commit: r766854 - in /incubator/shindig/trunk/java/gadgets/src: main/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessor.java test/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessorTest.java

Author: awiner
Date: Mon Apr 20 20:24:01 2009
New Revision: 766854

URL: http://svn.apache.org/viewvc?rev=766854&view=rev
Log:
Support boolean HTML4 attributes (enabled="enabled" and such)

Modified:
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessor.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessorTest.java

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessor.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessor.java?rev=766854&r1=766853&r2=766854&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessor.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessor.java Mon Apr 20 20:24:01 2009
@@ -24,8 +24,10 @@
 
 import java.io.IOException;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Set;
 import java.util.logging.Logger;
 
 import javax.el.ELContext;
@@ -44,7 +46,9 @@
 import org.w3c.dom.NodeList;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.inject.Inject;
 
@@ -70,6 +74,13 @@
   public static final String ATTRIBUTE_VAR = "var";
   public static final String ATTRIBUTE_CUR = "cur";
   
+  /** 
+   * Set of attributes in HTML 4 that are boolean, and may only be set
+   * to that value, and should be omitted to indicate "false". 
+   */
+  private static final Set<String> HTML4_BOOLEAN_ATTRIBUTES =
+    ImmutableSet.of("checked", "compact", "declare", "defer", "disabled", "ismap",
+        "multiple", "nohref", "noresize", "noshade", "nowrap", "readonly", "selected");
   private final Expressions expressions;
   // Reused buffer for creating template output
   private final StringBuilder outputBuffer;
@@ -350,15 +361,42 @@
   }
   
   /**
-   * Process expressions on attributes. For custom tags, in addition to 
-   * processing attributes, 
+   * Process expressions on attributes.
    * @param element The Element to process attributes on
    */
   private void processAttributes(Element element) {
     NamedNodeMap attributes = element.getAttributes();
+    List<Attr> attrsToRemove = null;
     for (int i = 0; i < attributes.getLength(); i++) {
       Attr attribute = (Attr) attributes.item(i);
-      attribute.setNodeValue(evaluate(attribute.getValue(), String.class, null));      
+      // Boolean attributes: evaluate as a boolean.  If true, set the value to the
+      // name of the attribute, e.g. selected="selected".  If false, remove the attribute
+      // altogether.  The check here has some limitations for efficiency:  it assumes the
+      // attribute is lowercase, and doesn't bother to check whether the boolean attribute
+      // actually exists on the referred element (but HTML has no attrs that are sometimes
+      // boolean and sometimes not)
+      if (element.getNamespaceURI() == null &&
+          HTML4_BOOLEAN_ATTRIBUTES.contains(attribute.getName())) {
+        if (Boolean.TRUE.equals(evaluate(attribute.getValue(), Boolean.class, Boolean.FALSE))) {
+          attribute.setNodeValue(attribute.getName());
+        } else {
+          // Because NamedNodeMaps are live, removing them interferes with iteration.
+          // Remove the attributes in a later pass
+          if (attrsToRemove == null) {
+            attrsToRemove = Lists.newArrayListWithCapacity(attributes.getLength());
+          }
+          
+          attrsToRemove.add(attribute);
+        }
+      } else {
+        attribute.setNodeValue(evaluate(attribute.getValue(), String.class, null));
+      }
+    }
+    
+    if (attrsToRemove != null) {
+      for (Attr attr : attrsToRemove) {
+        element.removeAttributeNode(attr);
+      }
     }
   }
   

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessorTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessorTest.java?rev=766854&r1=766853&r2=766854&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessorTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessorTest.java Mon Apr 20 20:24:01 2009
@@ -187,6 +187,13 @@
     assertEquals("<b>BAR</b>", output);
   }
 
+  @Test
+  public void testBooleanAttributes() throws Exception {
+    String output = executeTemplate("<input class=\"${1 == 2}\" readonly=\"${1 == 2}\"" +
+    		"disabled=\"${1 == 1}\">");
+    assertEquals("<input class=\"false\" disabled=\"disabled\">", output);
+  }
+
   private String executeTemplate(String markup) throws Exception {
     return executeTemplate(markup, "");
   }