You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@velocity.apache.org by nb...@apache.org on 2010/04/12 18:28:33 UTC

svn commit: r933305 - /velocity/tools/trunk/src/main/java/org/apache/velocity/tools/generic/MarkupTool.java

Author: nbubna
Date: Mon Apr 12 16:28:33 2010
New Revision: 933305

URL: http://svn.apache.org/viewvc?rev=933305&view=rev
Log:
VELTOOLS-97 initial revision

Added:
    velocity/tools/trunk/src/main/java/org/apache/velocity/tools/generic/MarkupTool.java   (with props)

Added: velocity/tools/trunk/src/main/java/org/apache/velocity/tools/generic/MarkupTool.java
URL: http://svn.apache.org/viewvc/velocity/tools/trunk/src/main/java/org/apache/velocity/tools/generic/MarkupTool.java?rev=933305&view=auto
==============================================================================
--- velocity/tools/trunk/src/main/java/org/apache/velocity/tools/generic/MarkupTool.java (added)
+++ velocity/tools/trunk/src/main/java/org/apache/velocity/tools/generic/MarkupTool.java Mon Apr 12 16:28:33 2010
@@ -0,0 +1,507 @@
+package org.apache.velocity.tools.generic;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.velocity.tools.config.DefaultKey;
+import org.apache.velocity.tools.generic.SafeConfig;
+
+/**
+ * <b>NOTE: This tools is considered "alpha" quality due to lack of testing
+ * and a generally unpolished API.  Feel free to use but expect changes.
+ * Also, this is not automatically provided via the default tools.xml file.
+ * </b>
+ *
+ * <p>
+ * A tool to make it easy to generate XML or HTML on the fly.  It uses a CSS-type
+ * syntax with a vaguely jQuery-ish API to help you generate the markup you need.
+ * <p>
+ * <pre>
+ * Example uses in a template:
+ *   #set( $foospan = $markup.span.id($foo.id).body($foo) )
+ *   $markup.tag('table tr.bar td').body("This is $foospan")
+ *
+ * Output:
+ *   <table>
+ *     <tr class="bar">
+ *       <td>This is <span id="foo1">my first foo.</span></td>
+ *     </tr>
+ *   </table>
+ *
+ *
+ * Example tools.xml config:
+ * &lt;tools&gt;
+ *   &lt;toolbox scope="application"&gt;
+ *     &lt;tool class="org.apache.velocity.tools.generic.alpha.MarkupTool"/&gt;
+ *   &lt;/toolbox&gt;
+ * &lt;/tools&gt;
+ * </pre></p>
+ *
+ * @author Nathan Bubna
+ * @since VelocityTools 2.0
+ * @version $Id$
+ */
+@DefaultKey("mark")
+public class MarkupTool extends SafeConfig
+{
+    public static final String DEFAULT_TAB = "  ";
+    public static final String DEFAULT_DELIMITER = " ";
+
+    private String tab = DEFAULT_TAB;
+    private String delim = DEFAULT_DELIMITER;
+
+    public void setTab(String tab)
+    {
+        if (isConfigLocked())
+        {
+            //TODO: log setTab failure
+        }
+        else
+        {
+            this.tab = tab;
+        }
+    }
+
+    public String getTab()
+    {
+        return this.tab;
+    }
+
+    public Tag get(String tag)
+    {
+        return tag(tag);
+    }
+
+    public Tag tag(String definition)
+    {
+        String[] tags = split(definition);
+        Tag last = null;
+        for (int i=0; i < tags.length; i++)
+        {
+            Tag tag = parse(tags[i]);
+            if (last != null)
+            {
+                last.append(tag);
+            }
+            last = tag;
+        }
+        return last;
+    }
+
+    protected String[] split(String me)
+    {
+        //TODO: fix escaped delimiters
+        return me.split(delim);
+    }
+
+    private static enum Mode { NAME, ID, CLASS, ATTR }
+    protected Tag parse(String definition)
+    {
+        StringBuilder store = new StringBuilder();
+        Tag tag = new Tag(this);
+        Mode mode = Mode.NAME;
+        for (int i=0; i < definition.length(); i++)
+        {
+            char c = definition.charAt(i);
+            if (c == '#')
+            {
+                store = clear(mode, tag, store, true);
+                mode = Mode.ID;
+            }
+            else if (c == '.')
+            {
+                store = clear(mode, tag, store, true);
+                mode = Mode.CLASS;
+            }
+            else if (c == '[')
+            {
+                store = clear(mode, tag, store, true);
+                mode = Mode.ATTR;
+            }
+            else if (c == ']')
+            {
+                store = clear(mode, tag, store, true);
+                mode = Mode.NAME;
+            }
+            else
+            {
+                store.append(c);
+            }
+        }
+        clear(mode, tag, store, false);
+        return tag;
+    }
+    private StringBuilder clear(Mode mode, Tag tag, StringBuilder val, boolean emptyStore)
+    {
+        if (val.length() > 0)
+        {
+            String s = val.toString();
+            switch (mode)
+            {
+                case NAME:
+                    tag.name(s);
+                    break;
+                case ID:
+                    tag.id(s);
+                    break;
+                case CLASS:
+                    tag.addClass(s);
+                    break;
+                case ATTR:
+                    if (s.indexOf('=') > 0)
+                    {
+                        String[] kv = s.split("=");
+                        tag.attr(kv[0], kv[1]);
+                    }
+                    else
+                    {
+                        tag.attr(s, null);
+                    }
+                    break;
+            }
+            if (emptyStore)
+            {
+                return new StringBuilder();
+            }
+            return val;
+        }
+        else
+        {
+            // already is clean
+            return val;
+        }
+    }
+
+    public static class Tag
+    {
+        private MarkupTool tool;
+        private Tag parent;
+        private Object name;
+        private Object id;
+        private List<Object> classes;
+        private Map<Object,Object> attributes;
+        private List<Object> children;
+
+        public Tag(MarkupTool tool)
+        {
+            this.tool = tool;
+        }
+
+        public Tag name(Object name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Tag id(Object id)
+        {
+            this.id = id;
+            return this;
+        }
+
+        public Tag addClass(Object c)
+        {
+            if (c == null)
+            {
+                return null;
+            }
+
+            if (classes == null)
+            {
+                classes = new ArrayList<Object>();
+            }
+            classes.add(c);
+            return this;
+        }
+
+        public Tag attr(Object k, Object v)
+        {
+            if (k == null)
+            {
+                return null;
+            }
+            if (attributes == null)
+            {
+                attributes = new HashMap<Object,Object>();
+            }
+            attributes.put(k, v);
+            return this;
+        }
+
+        public Tag body(Object o)
+        {
+            if (children == null)
+            {
+                children = new ArrayList<Object>();
+            }
+            else
+            {
+                children.clear();
+            }
+            children.add(o);
+            return this;
+        }
+
+        public Tag append(Object o)
+        {
+            if (children == null)
+            {
+                children = new ArrayList<Object>();
+            }
+            children.add(o);
+            if (o instanceof Tag)
+            {
+                ((Tag)o).parent(this);
+            }
+            return this;
+        }
+
+        public Tag prepend(Object o)
+        {
+            if (children == null)
+            {
+                children = new ArrayList<Object>();
+                children.add(o);
+            }
+            else
+            {
+                children.add(0, o);
+            }
+            if (o instanceof Tag)
+            {
+                ((Tag)o).parent(this);
+            }
+            return this;
+        }
+
+        public Tag wrap(String tag)
+        {
+            // make new tag
+            Tag prnt = tool.tag(tag);
+            // give root of new tag our parent
+            prnt.root().parent(parent());
+            // make new tag our parent
+            parent(prnt);
+            return this;
+        }
+
+        public Tag orphan()
+        {
+            return parent(null);
+        }
+
+        public Tag parent(Tag parent)
+        {
+            this.parent = parent;
+            return this;
+        }
+
+        public Tag parent()
+        {
+            return this.parent;
+        }
+
+        public Tag root()
+        {
+            if (isOrphan())
+            {
+                return this;
+            }
+            return this.parent.root();
+        }
+
+        public List<Object> children()
+        {
+            return children;
+        }
+
+        public boolean isOrphan()
+        {
+            return (parent == null);
+        }
+
+        public boolean isEmpty()
+        {
+            return (children == null || children().isEmpty());
+        }
+
+        public boolean matches(Tag tag)
+        {
+            if (missed(name, tag.name) ||
+                missed(id, tag.id) ||
+                missed(classes, tag.classes))
+            {
+                return false;
+            }
+            //TODO: match attributes
+            return true;
+        }
+
+        protected boolean missed(Object target, Object arrow)
+        {
+            // no arrow, no miss
+            if (arrow == null)
+            {
+                return false;
+            }
+            // otherwise, the arrow must hit the target
+            return !arrow.equals(target);
+        }
+
+        protected boolean missed(List<Object> targets, List<Object> arrows)
+        {
+            // no arrows, no miss
+            if (arrows == null)
+            {
+                return false;
+            }
+            // no targets, always miss
+            if (targets == null)
+            {
+                return true;
+            }
+            for (Object o : arrows)
+            {
+                if (!targets.contains(o))
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+
+        /************* rendering methods **************/
+
+        protected void render(String indent, StringBuilder s)
+        {
+            if (render_start(indent, s))
+            {
+                render_body(indent, s);
+                render_end(indent, s);
+            }
+        }
+
+        protected boolean render_start(String indent, StringBuilder s)
+        {
+            if (indent != null)
+            {
+                s.append(indent);
+            }
+            s.append('<');
+            render_name(s);
+            render_id(s);
+            render_classes(s);
+            render_attributes(s);
+            if (isEmpty())
+            {
+                s.append("/>");
+                return false;
+            }
+            else
+            {
+                s.append('>');
+                return true;
+            }
+        }
+
+        protected void render_name(StringBuilder s)
+        {
+            s.append(name == null ? "div" : name);
+        }
+
+        protected void render_id(StringBuilder s)
+        {
+            if (id != null)
+            {
+                s.append(" id=\"").append(id).append('"');
+            }
+        }
+
+        protected void render_classes(StringBuilder s)
+        {
+            if (classes != null)
+            {
+                s.append(" class=\"");
+                for (int i=0; i < classes.size(); i++)
+                {
+                    s.append(classes.get(i));
+                    if (i + 1 != classes.size())
+                    {
+                        s.append(' ');
+                    }
+                }
+                s.append('"');
+            }
+        }
+
+        protected void render_attributes(StringBuilder s)
+        {
+            if (attributes != null)
+            {
+                for (Map.Entry<Object,Object> entry : attributes.entrySet())
+                {
+                    s.append(' ').append(entry.getKey()).append("=\"");
+                    if (entry.getValue() != null)
+                    {
+                        s.append(entry.getValue());
+                    }
+                    s.append('"');
+                }
+            }
+        }
+
+        protected void render_body(String indent, StringBuilder s)
+        {
+            String kidIndent = indent + tool.getTab();
+            for (Object o : children)
+            {
+                if (o instanceof Tag)
+                {
+                    ((Tag)o).render(kidIndent, s);
+                }
+                else
+                {
+                    s.append(kidIndent);
+                    s.append(o);
+                }
+            }
+        }
+
+        protected void render_end(String indent, StringBuilder s)
+        {
+            if (indent != null)
+            {
+                s.append(indent);
+            }
+            s.append("</").append(name).append('>');
+        }
+
+        public String toString()
+        {
+            StringBuilder s = new StringBuilder();
+            root().render("\n", s);
+            return s.toString();
+        }
+    }
+}

Propchange: velocity/tools/trunk/src/main/java/org/apache/velocity/tools/generic/MarkupTool.java
------------------------------------------------------------------------------
    svn:executable = *