You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@click.apache.org by sa...@apache.org on 2009/03/09 19:20:16 UTC

svn commit: r751785 [2/2] - in /incubator/click/trunk/click/framework/src/org/apache/click: ./ control/ util/

Modified: incubator/click/trunk/click/framework/src/org/apache/click/util/PageImports.java
URL: http://svn.apache.org/viewvc/incubator/click/trunk/click/framework/src/org/apache/click/util/PageImports.java?rev=751785&r1=751784&r2=751785&view=diff
==============================================================================
--- incubator/click/trunk/click/framework/src/org/apache/click/util/PageImports.java (original)
+++ incubator/click/trunk/click/framework/src/org/apache/click/util/PageImports.java Mon Mar  9 18:20:16 2009
@@ -19,13 +19,17 @@
 package org.apache.click.util;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import java.util.StringTokenizer;
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.click.Control;
 import org.apache.click.Page;
+import org.apache.click.control.Container;
+import org.apache.click.control.Table;
 import org.apache.click.service.LogService;
 
 import org.apache.commons.lang.StringUtils;
@@ -76,10 +80,10 @@
  * <span class="blue">$jsImports</span>
  * </pre>
  *
- * Please also see {@link Page#getHtmlImports()} and
- * {@link Control#getHtmlImports()}.
- *
- * @see Format
+ * Please also see {@link org.apache.click.Page#getHtmlHeaders()},
+ * {@link org.apache.click.Control#getHtmlHeaders()},
+ * {@link org.apache.click.Page#getHtmlImports()} and
+ * {@link org.apache.click.Control#getHtmlImports()}.
  *
  * @author Malcolm Edgar
  */
@@ -97,6 +101,9 @@
     /** The list of JS script block lines. */
     protected List jsScripts = new ArrayList();
 
+    /** The list of CSS styles. */
+    protected List cssStyles = new ArrayList();
+
     /** The page instance. */
     protected final Page page;
 
@@ -114,9 +121,52 @@
     // --------------------------------------------------------- Public Methods
 
     /**
-     * Process the given control HTML import line.
+     * Add the given HtmlHeader to the Page HTML imports.
+     *
+     * @param htmlHeader the HtmlHeader to add
+     */
+    public void add(HtmlHeader htmlHeader) {
+        if (htmlHeader instanceof JavascriptImport) {
+            if (jsImports.contains(htmlHeader)) {
+                return;
+            }
+            jsImports.add(htmlHeader);
+
+        } else if (htmlHeader instanceof Javascript) {
+            if (((Javascript) htmlHeader).isUnique()) {
+                if (jsScripts.contains(htmlHeader)) {
+                    return;
+                }
+            }
+            jsScripts.add(htmlHeader);
+
+        } else if (htmlHeader instanceof CssImport) {
+            if (cssImports.contains(htmlHeader)) {
+                return;
+            }
+            cssImports.add(htmlHeader);
+
+        } else if (htmlHeader instanceof Css) {
+            if (((Css) htmlHeader).isUnique()) {
+                if (cssStyles.contains(htmlHeader)) {
+                    return;
+                }
+            }
+            cssStyles.add(htmlHeader);
+
+        } else {
+            throw new IllegalArgumentException(htmlHeader.getClass().getName()
+                + " is not a supported type.");
+        }
+    }
+
+    /**
+     * Add the given HTML import line to the Page HTML imports.
      *
-     * @param value the HTML import line to process
+     * @deprecated use the new {@link #add(org.apache.click.util.HtmlHeader)}
+     * instead
+     *
+     * @param value the HTML import line to add
      */
     public void addImport(String value) {
         if (value == null || value.length() == 0) {
@@ -128,17 +178,23 @@
         for (int i = 0; i  < lines.length; i++) {
             String line = lines[i].trim().toLowerCase();
             if (line.startsWith("<link") && line.indexOf("text/css") != -1) {
-                addToList(lines[i], cssImports);
+                CssImport cssImport = asCssImport(lines[i]);
+                add(cssImport);
 
             } else if (line.startsWith("<style") && line.indexOf("text/css") != -1) {
-                addToList(lines[i], cssImports);
+                Css css = asCss(lines[i]);
+                css.setUnique(true);
+                add(css);
 
             } else if (line.startsWith("<script")) {
                 if (line.indexOf(" src=") != -1) {
-                    addToList(lines[i], jsImports);
+                    JavascriptImport javascriptImport = asJavascriptImport(lines[i]);
+                    add(javascriptImport);
 
                 } else {
-                    addToList(lines[i], jsScripts);
+                    Javascript javascript = asJavascript(lines[i]);
+                    javascript.setUnique(true);
+                    add(javascript);
 
                 }
             } else {
@@ -239,85 +295,58 @@
     // ------------------------------------------------------ Protected Methods
 
     /**
-     * Return a HTML string of all the page's HTML imports, including:
-     * CSS imports, JS imports and JS script blocks.
+     * Render an HTML representation of all the page's HTML imports,
+     * including: CSS imports, CSS styles, JS imports and JS scripts.
      *
-     * @return a HTML string of all the page's HTML imports, including:
-     * CSS imports, JS imports and JS script blocks.
+     * @param buffer the specified buffer to render the page's HTML imports to
      */
-    protected String getAllIncludes() {
-        processPageControls();
-
-        int size = 80 * cssImports.size() + jsImports.size() + jsScripts.size();
-        HtmlStringBuffer buffer = new HtmlStringBuffer(size);
-
-        for (int i = 0; i  < cssImports.size(); i++) {
-            String line = cssImports.get(i).toString();
-            buffer.append(line);
-            buffer.append('\n');
-        }
-        for (int i = 0; i  < jsImports.size(); i++) {
-            String line = jsImports.get(i).toString();
-            buffer.append(line);
-            buffer.append('\n');
-        }
-        for (int i = 0; i  < jsScripts.size(); i++) {
-            String line = jsScripts.get(i).toString();
-            buffer.append(line);
-            buffer.append('\n');
-        }
-
-        return buffer.toString();
+    protected void renderAllIncludes(HtmlStringBuffer buffer) {
+        renderCssImports(buffer);
+        renderJsImports(buffer);
     }
 
     /**
-     * Return a HTML string of all the page's HTML CSS imports.
+     * Render an HTML representation of all all the page's HTML CSS
+     * {@link #cssImports imports} and {@link #cssStyles styles}.
      *
-     * @return a HTML string of all the page's HTML CSS imports.
+     * @param buffer the specified buffer to render the page's HTML imports to
      */
-    protected String getCssImports() {
-        processPageControls();
-
-        HtmlStringBuffer buffer = new HtmlStringBuffer(80 * cssImports.size());
-
-        for (int i = 0; i  < cssImports.size(); i++) {
-            String line = cssImports.get(i).toString();
-            buffer.append(line);
-            if (i < cssImports.size() - 1) {
-                buffer.append('\n');
-            }
+    protected void renderCssImports(HtmlStringBuffer buffer) {
+        // First include all the imports e.g. <link href="...">
+        for (Iterator it = cssImports.iterator(); it.hasNext();) {
+            CssImport cssImport = (CssImport) it.next();
+            cssImport.render(buffer);
+            buffer.append('\n');
         }
 
-        return buffer.toString();
+        // Then include all the styles e.g. <style>...</style>
+        for (Iterator it = cssStyles.iterator(); it.hasNext();) {
+            Css cssInclude = (Css) it.next();
+            cssInclude.render(buffer);
+            buffer.append('\n');
+        }
     }
 
     /**
-     * Return a HTML string of all the page's HTML JS imports and scripts.
+     * Render an HTML representation of all the page's HTML JavaScript
+     * {@link #jsImports imports} and {@link #jsScripts scripts}.
      *
-     * @return a HTML string of all the page's HTML JS imports and scripts.
+     * @param buffer the specified buffer to render the page's HTML imports to
      */
-    protected String getJsImports() {
-        processPageControls();
-
-        HtmlStringBuffer buffer = new HtmlStringBuffer(80 * jsImports.size());
-
-        for (int i = 0; i  < jsImports.size(); i++) {
-            String line = jsImports.get(i).toString();
-            buffer.append(line);
-            if (i < jsImports.size() - 1 || !jsScripts.isEmpty()) {
-                buffer.append('\n');
-            }
+    protected void renderJsImports(HtmlStringBuffer buffer) {
+        // First include all the imports e.g. <script src="...">
+        for (Iterator it = jsImports.iterator(); it.hasNext();) {
+            JavascriptImport javascriptImport = (JavascriptImport) it.next();
+            javascriptImport.render(buffer);
+            buffer.append('\n');
         }
 
-        for (int i = 0; i  < jsScripts.size(); i++) {
-            String line = jsScripts.get(i).toString();
-            buffer.append(line);
-            if (i < jsScripts.size() - 1) {
-                buffer.append('\n');
-            }
+        // Then include all the scripts e.g. <script>...</script>
+        for (Iterator it = jsScripts.iterator(); it.hasNext();) {
+            Javascript javascriptInclude = (Javascript) it.next();
+            javascriptInclude.render(buffer);
+            buffer.append('\n');
         }
-
-        return buffer.toString();
     }
 
     /**
@@ -334,40 +363,75 @@
             for (int i = 0; i < page.getControls().size(); i++) {
                 Control control = (Control) page.getControls().get(i);
 
+                // import from getHtmlImports
                 addImport(control.getHtmlImports());
+
+                // import from getHtmlHeaders
+                processControl(control);
             }
         }
 
         addImport(page.getHtmlImports());
+
+        processHtmlHeaders(page.getHtmlHeaders());
     }
 
     /**
-     * Add the given string item to the list if it is not already present.
+     * Process the given control HTML headers. This method will recursively
+     * process Containers and all child controls.
+     * <p/>
+     * This method delegates to {@link #processHtmlHeaders(java.util.List)}
+     * to add the HTML headers to the Page imports.
      *
-     * @param item the line item to add
-     * @param list the list to add the item to
+     * @param control the control to process
      */
-    protected void addToList(String item, List list) {
-        item = item.trim();
+    protected void processControl(Control control) {
+        processHtmlHeaders(control.getHtmlHeaders());
 
-        boolean found = false;
+        if (control instanceof Container) {
+            Container container = (Container) control;
+            if (container.hasControls()) {
+                List controls = container.getControls();
+                for (int i = 0, size = controls.size(); i < size; i++) {
+                    processControl((Control) controls.get(i));
+                }
+            }
 
-        for (int i = 0; i < list.size(); i++) {
-            if (list.get(i).equals(item)) {
-                found = true;
-                break;
+        } else if (control instanceof Table) {
+            Table table = (Table) control;
+            if (table.hasControls()) {
+                List controls = table.getControls();
+                for (int i = 0, size = controls.size(); i < size; i++) {
+                    processControl((Control) controls.get(i));
+                }
             }
         }
+    }
+
+    /**
+     * Process the given list of HTML headers.
+     * <p/>
+     * This method invokes {@link #add(org.apache.click.util.HtmlHeader)} for
+     * every <tt>HtmlHeader</tt> entry in the specified list.
+     *
+     * @param htmlHeaders the list of HTML headers to process
+     */
+    protected void processHtmlHeaders(List htmlHeaders) {
+        if (htmlHeaders == null || htmlHeaders.isEmpty()) {
+            return;
+        }
 
-        if (!found) {
-            list.add(item);
+        Iterator it = htmlHeaders.iterator();
+        while (it.hasNext()) {
+            add((HtmlHeader) it.next());
         }
     }
 
     // ------------------------------------------------------- Internal Classes
 
     /**
-     * This class enables lazy, on demand importing for {@link #getAllIncludes()}.
+     * This class enables lazy, on demand importing for
+     * {@link #renderAllIncludes(org.apache.click.util.HtmlStringBuffer)}.
      */
     class Imports {
 
@@ -377,12 +441,20 @@
          * @return a string representing all includes
          */
         public String toString() {
-            return PageImports.this.getAllIncludes();
+            processPageControls();
+            HtmlStringBuffer buffer = new HtmlStringBuffer(
+                80 * jsImports.size()
+                + 80 * jsScripts.size()
+                + 80 * cssImports.size()
+                + 80 * cssStyles.size());
+            PageImports.this.renderAllIncludes(buffer);
+            return buffer.toString();
         }
     }
 
     /**
-     * This class enables lazy, on demand importing for {@link #getJsImports()}.
+     * This class enables lazy, on demand importing for
+     * {@link #renderJsImports(org.apache.click.util.HtmlStringBuffer)}.
      */
     class JsImports {
 
@@ -392,12 +464,18 @@
          * @return a string representing all JavaScript imports
          */
         public String toString() {
-            return PageImports.this.getJsImports();
+            processPageControls();
+            HtmlStringBuffer buffer = new HtmlStringBuffer(
+                80 * jsImports.size() + 80 * jsScripts.size());
+
+            PageImports.this.renderJsImports(buffer);
+            return buffer.toString();
         }
     }
 
     /**
-     * This class enables lazy, on demand importing for {@link #getCssImports()}.
+     * This class enables lazy, on demand importing for
+     * {@link #renderCssImports(org.apache.click.util.HtmlStringBuffer)}.
      */
     class CssImports {
 
@@ -407,7 +485,123 @@
          * @return a string representing all CSS imports
          */
         public String toString() {
-            return PageImports.this.getCssImports();
+            processPageControls();
+            HtmlStringBuffer buffer = new HtmlStringBuffer(
+                80 * cssImports.size() + 80 * cssStyles.size());
+
+            PageImports.this.renderCssImports(buffer);
+            return buffer.toString();
+        }
+    }
+
+    // -------------------------------------------------------- Private Methods
+
+    /**
+     * Convert the given HTML import line to a {@link CssImport} instance.
+     *
+     * @param line the HTML import line to convert to a CssImport instance
+     * @return a CssImport instance
+     */
+    private CssImport asCssImport(String line) {
+        CssImport cssImport = new CssImport();
+        copyAttributes(cssImport, line);
+        return cssImport;
+    }
+
+    /**
+     * Convert the given HTML import line to a {@link Css} instance.
+     *
+     * @param line the HTML import line to convert to a Css instance
+     * @return a Css instance
+     */
+    private Css asCss(String line) {
+        Css css = new Css();
+        copyAttributes(css, line);
+        css.append(extractContent(line));
+        return css;
+    }
+
+    /**
+     * Convert the given HTML import line to a {@link JavascriptImport} instance.
+     *
+     * @param line the HTML import line to convert to a JavaScriptImport instance
+     * @return a JavascriptImport instance
+     */
+    private JavascriptImport asJavascriptImport(String line) {
+        JavascriptImport javascriptImport = new JavascriptImport();
+        copyAttributes(javascriptImport, line);
+        return javascriptImport;
+    }
+
+    /**
+     * Convert the given HTML import line to a {@link Javascript} instance.
+     *
+     * @param line the HTML import line to convert to a JavaScript instance
+     * @return a Javascript instance
+     */
+    private Javascript asJavascript(String line) {
+        Javascript javascript = new Javascript();
+        copyAttributes(javascript, line);
+        javascript.append(extractContent(line));
+        return javascript;
+    }
+
+    /**
+     * Extract the JavaScript or CSS content from the given HTML import line.
+     *
+     * @param line the HTML import line
+     * @return the JavaScript or CSS content contained in the HTML import line
+     */
+    private String extractContent(String line) {
+        if (line.endsWith("/>")) {
+            // If tag has no content, exit early
+            return "";
+        }
+
+        // Find index where tag ends
+        int start = line.indexOf('>');
+        if (start == -1) {
+            throw new IllegalArgumentException(line + " is not a valid element");
+        }
+        int end = line.indexOf('<', start);
+        if (end == -1) {
+            return "";
+        }
+        return line.substring(start + 1, end);
+    }
+
+    /**
+     * Copy all available attributes from HTML import line to the HtmlHeader
+     * instance.
+     *
+     * @param htmlHeader the HTML header to copy the attributes to
+     * @param line the HTML import line to copy attributes from
+     */
+    private void copyAttributes(HtmlHeader htmlHeader, String line) {
+        // Find index where attributes start: the first space
+        int start = line.indexOf(' ');
+        if (start == -1) {
+            // If no attributes found, exit early
+            return;
+        }
+
+        // Find index where attributes end: closing tag
+        int end = line.indexOf("/>");
+        if (end == -1) {
+            end = line.indexOf(">");
+        }
+        if (end == -1) {
+            throw new IllegalArgumentException(line + " is not a valid HTML import");
+        }
+
+        line = line.substring(start, end);
+        StringTokenizer tokens = new StringTokenizer(line, " ");
+        while (tokens.hasMoreTokens()) {
+            String token = tokens.nextToken();
+            StringTokenizer attribute = new StringTokenizer(token, "=");
+            String key = attribute.nextToken();
+            String value = attribute.nextToken();
+            htmlHeader.setAttribute(key, StringUtils.strip(value, "'\""));
         }
     }
 }