Modified: velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/ParserTreeConstants.java URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/ParserTreeConstants.java?rev=731779&r1=731778&r2=731779&view=diff ============================================================================== --- velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/ParserTreeConstants.java (original) +++ velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/ParserTreeConstants.java Mon Jan 5 16:10:57 2009 @@ -1,5 +1,4 @@ -/* Generated By:JJTree: Do not edit this line. ParserTreeConstants.java */ - +/* Generated By:JavaCC: Do not edit this line. ParserTreeConstants.java Version 4.1 */ package org.apache.velocity.runtime.parser; public interface ParserTreeConstants @@ -9,43 +8,44 @@ public int JJTESCAPEDDIRECTIVE = 2; public int JJTESCAPE = 3; public int JJTCOMMENT = 4; - public int JJTFLOATINGPOINTLITERAL = 5; - public int JJTINTEGERLITERAL = 6; - public int JJTSTRINGLITERAL = 7; - public int JJTIDENTIFIER = 8; - public int JJTWORD = 9; - public int JJTDIRECTIVE = 10; - public int JJTBLOCK = 11; - public int JJTMAP = 12; - public int JJTOBJECTARRAY = 13; - public int JJTINTEGERRANGE = 14; - public int JJTMETHOD = 15; - public int JJTINDEX = 16; - public int JJTREFERENCE = 17; - public int JJTTRUE = 18; - public int JJTFALSE = 19; - public int JJTTEXT = 20; - public int JJTIFSTATEMENT = 21; - public int JJTELSESTATEMENT = 22; - public int JJTELSEIFSTATEMENT = 23; - public int JJTSETDIRECTIVE = 24; - public int JJTSTOP = 25; - public int JJTEXPRESSION = 26; - public int JJTASSIGNMENT = 27; - public int JJTORNODE = 28; - public int JJTANDNODE = 29; - public int JJTEQNODE = 30; - public int JJTNENODE = 31; - public int JJTLTNODE = 32; - public int JJTGTNODE = 33; - public int JJTLENODE = 34; - public int JJTGENODE = 35; - public int JJTADDNODE = 36; - public int JJTSUBTRACTNODE = 37; - public int JJTMULNODE = 38; - public int JJTDIVNODE = 39; - public int JJTMODNODE = 40; - public int JJTNOTNODE = 41; + public int JJTTEXTBLOCK = 5; + public int JJTFLOATINGPOINTLITERAL = 6; + public int JJTINTEGERLITERAL = 7; + public int JJTSTRINGLITERAL = 8; + public int JJTIDENTIFIER = 9; + public int JJTWORD = 10; + public int JJTDIRECTIVE = 11; + public int JJTBLOCK = 12; + public int JJTMAP = 13; + public int JJTOBJECTARRAY = 14; + public int JJTINTEGERRANGE = 15; + public int JJTMETHOD = 16; + public int JJTINDEX = 17; + public int JJTREFERENCE = 18; + public int JJTTRUE = 19; + public int JJTFALSE = 20; + public int JJTTEXT = 21; + public int JJTIFSTATEMENT = 22; + public int JJTELSESTATEMENT = 23; + public int JJTELSEIFSTATEMENT = 24; + public int JJTSETDIRECTIVE = 25; + public int JJTSTOP = 26; + public int JJTEXPRESSION = 27; + public int JJTASSIGNMENT = 28; + public int JJTORNODE = 29; + public int JJTANDNODE = 30; + public int JJTEQNODE = 31; + public int JJTNENODE = 32; + public int JJTLTNODE = 33; + public int JJTGTNODE = 34; + public int JJTLENODE = 35; + public int JJTGENODE = 36; + public int JJTADDNODE = 37; + public int JJTSUBTRACTNODE = 38; + public int JJTMULNODE = 39; + public int JJTDIVNODE = 40; + public int JJTMODNODE = 41; + public int JJTNOTNODE = 42; public String[] jjtNodeName = { @@ -54,6 +54,7 @@ "EscapedDirective", "Escape", "Comment", + "Textblock", "FloatingPointLiteral", "IntegerLiteral", "StringLiteral", @@ -93,3 +94,4 @@ "NotNode", }; } +/* JavaCC - OriginalChecksum=6486d1e0227c52f059ed205018b7b6fa (do not edit this line) */
Added: velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTTextblock.java URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTTextblock.java?rev=731779&view=auto ============================================================================== --- velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTTextblock.java (added) +++ velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTTextblock.java Mon Jan 5 16:10:57 2009 @@ -0,0 +1,94 @@ +package org.apache.velocity.runtime.parser.node; + +/* + * 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.io.IOException; +import java.io.Writer; + +import org.apache.velocity.context.InternalContextAdapter; +import org.apache.velocity.exception.TemplateInitException; +import org.apache.velocity.runtime.parser.Parser; +import org.apache.velocity.runtime.parser.Token; + +/** + * This node holds the "Textblock" data which should not be interpreted by Velocity. + * + * Textblocks are marked in Velocity with #[[content here]]# notation. Velocity + * will output everything between the markers and does not attempt to parse it in any way. + */ +public class ASTTextblock extends SimpleNode +{ + public static final String START = "#[["; + public static final String END = "]]#"; + private char[] ctext; + + /** + * @param id + */ + public ASTTextblock(int id) + { + super(id); + } + + /** + * @param p + * @param id + */ + public ASTTextblock(Parser p, int id) + { + super(p, id); + } + + /** + * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object) + */ + public Object jjtAccept(ParserVisitor visitor, Object data) + { + return visitor.visit(this, data); + } + + /** + * @see org.apache.velocity.runtime.parser.node.SimpleNode#init(org.apache.velocity.context.InternalContextAdapter, java.lang.Object) + */ + public Object init( InternalContextAdapter context, Object data) + throws TemplateInitException + { + Token t = getFirstToken(); + + String text = t.image; + + // t.image is in format: #% <string> %# + // we must strip away the hash tags + text = text.substring(START.length(), text.length() - END.length()); + + ctext = text.toCharArray(); + return data; + } + + /** + * @see org.apache.velocity.runtime.parser.node.SimpleNode#render(org.apache.velocity.context.InternalContextAdapter, java.io.Writer) + */ + public boolean render( InternalContextAdapter context, Writer writer) + throws IOException + { + writer.write(ctext); + return true; + } +} Propchange: velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTTextblock.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTTextblock.java ------------------------------------------------------------------------------ svn:keywords = Revision Propchange: velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTTextblock.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: velocity/engine/trunk/src/parser/Parser.jjt URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/parser/Parser.jjt?rev=731779&r1=731778&r2=731779&view=diff ============================================================================== --- velocity/engine/trunk/src/parser/Parser.jjt (original) +++ velocity/engine/trunk/src/parser/Parser.jjt Mon Jan 5 16:10:57 2009 @@ -86,6 +86,7 @@ import org.apache.velocity.runtime.directive.Macro; import org.apache.velocity.runtime.directive.MacroParseException; import org.apache.velocity.util.StringUtils; +import org.apache.commons.lang.text.StrBuilder; /** * This class is responsible for parsing a Velocity @@ -104,9 +105,9 @@ public class Parser { /** - * This Hashtable contains a list of all of the dynamic directives. + * This Map contains a list of all of the dynamic directives. */ - private Hashtable directives = new Hashtable(0); + private Map directives = new HashMap(); /** * Name of current template we are parsing. Passed to us in parse() @@ -217,7 +218,7 @@ */ public void setDirectives(Hashtable directives) { - this.directives = directives; + this.directives = new HashMap(directives); } /** @@ -350,7 +351,8 @@ private int lparen = 0; private int rparen = 0; - Stack stateStack = new Stack(); + List stateStack = new ArrayList(50); + public boolean debugPrint = false; private boolean inReference; @@ -368,14 +370,14 @@ */ public boolean stateStackPop() { - Hashtable h; - + ParserState s; try { - h = (Hashtable) stateStack.pop(); + s = (ParserState) stateStack.remove(stateStack.size() - 1); // stack.pop } - catch( EmptyStackException e) + catch(IndexOutOfBoundsException e) { + // empty stack lparen=0; SwitchTo(DEFAULT); return false; @@ -384,13 +386,13 @@ if( debugPrint ) System.out.println( " stack pop (" + stateStack.size() + ") : lparen=" + - ( (Integer) h.get("lparen")).intValue() + - " newstate=" + ( (Integer) h.get("lexstate")).intValue() ); + s.lparen + + " newstate=" + s.lexstate ); - lparen = ( (Integer) h.get("lparen")).intValue(); - rparen = ( (Integer) h.get("rparen")).intValue(); + lparen = s.lparen; + rparen = s.rparen; - SwitchTo( ( (Integer) h.get("lexstate")).intValue() ); + SwitchTo(s.lexstate); return true; } @@ -405,16 +407,14 @@ if( debugPrint ) System.out.println(" (" + stateStack.size() + ") pushing cur state : " + curLexState ); - - Hashtable h = new Hashtable(); - - h.put("lexstate", new Integer( curLexState ) ); - h.put("lparen", new Integer( lparen )); - h.put("rparen", new Integer( rparen )); + + ParserState s = new ParserState(); + s.lparen = lparen; + s.rparen = rparen; + s.lexstate = curLexState; lparen = 0; - - stateStack.push( h ); + stateStack.add(s); // stack.push return true; } @@ -423,7 +423,6 @@ * Clears all state variables, resets to * start values, clears stateStack. Call * before parsing. - * @return void */ public void clearStateVars() { @@ -440,6 +439,16 @@ } /** + * Holds the state of the parsing process. + */ + private class ParserState + { + int lparen; + int rparen; + int lexstate; + } + + /** * handles the dropdown logic when encountering a RPAREN */ private void RPARENHandler() @@ -739,6 +748,16 @@ } } +| "#[[" + { + if (!inComment) + { + inComment = true; + stateStackPush(); + SwitchTo( IN_TEXTBLOCK ); + } + } + | <"#**" ~["#"]> { if (!inComment) @@ -759,7 +778,7 @@ SwitchTo( IN_MULTI_LINE_COMMENT ); } } - + | <HASH : "#" > { if (! inComment) @@ -855,12 +874,28 @@ } } +<IN_TEXTBLOCK> +TOKEN : +{ + <TEXTBLOCK: "]]#" > + { + inComment = false; + stateStackPop(); + } +} + <IN_SINGLE_LINE_COMMENT,IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT> SKIP : { < ~[] > } +<IN_TEXTBLOCK> +MORE : +{ + < ~[] > +} + /* ----------------------------------------------------------------------- * * DIRECTIVE Lexical State (some of it, anyway) @@ -1188,6 +1223,7 @@ | StopStatement() | LOOKAHEAD(2) Reference() | Comment() +| Textblock() | SetDirective() | EscapedDirective() | Escape() @@ -1276,6 +1312,11 @@ | <FORMAL_COMMENT> } +void Textblock() : {} +{ + <TEXTBLOCK> +} + void FloatingPointLiteral() : {} { <FLOATING_POINT_LITERAL> Added: velocity/engine/trunk/src/test/org/apache/velocity/test/TextblockTestCase.java URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/test/org/apache/velocity/test/TextblockTestCase.java?rev=731779&view=auto ============================================================================== --- velocity/engine/trunk/src/test/org/apache/velocity/test/TextblockTestCase.java (added) +++ velocity/engine/trunk/src/test/org/apache/velocity/test/TextblockTestCase.java Mon Jan 5 16:10:57 2009 @@ -0,0 +1,145 @@ +package org.apache.velocity.test; + +/* + * 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.io.StringWriter; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.parser.node.ASTTextblock; +import org.apache.velocity.test.misc.TestLogChute; +import org.apache.velocity.test.provider.ForeachMethodCallHelper; + +/** + * This class tests the Textblock directive. + */ +public class TextblockTestCase extends BaseEvalTestCase +{ + // these are all here so that the test case adapts instantly + // to changes in the textblock start/end sequences + private static final String START = ASTTextblock.START; + private static final String END = ASTTextblock.END; + private static final String PARTIAL_START = START.substring(0, START.length() - 1); + private static final String PARTIAL_END = END.substring(1, END.length()); + private static final String END_OF_START = START.substring(START.length() - 1, START.length()); + private static final String START_OF_END = END.substring(0, 1); + + public TextblockTestCase(String name) + { + super(name); + //DEBUG = true; + } + + public String textblock(String s) + { + return START + s + END; + } + + public void assertTextblockEvalEquals(String s) throws Exception + { + assertEvalEquals(s, textblock(s)); + } + + /** + * https://issues.apache.org/jira/browse/VELOCITY-661 + */ + public void testTextblockAjaxcode() throws Exception + { + String s = "var myId = 'someID';$('#test).append($.template('<div id=\"${myId}\"></div>').apply({myId: myId}));"; + assertEvalEquals(s + " 123", textblock(s)+" #foreach($i in [1..3])$i#end"); + } + + public void testLooseTextblockEnd() throws Exception + { + // just like a multi-line comment end (*#), this must be + // followed by a character. by itself, it bombs for some reason. + assertEvalEquals(END+" ", END+" "); + } + + public void testTextblockStartInTextblock() throws Exception + { + assertTextblockEvalEquals(START); + } + + public void testTextblockEndBetweenTwoTextblockHalves() throws Exception + { + // just like a multi-line comment end (*#), the end token + // in the middle must be followed by some character. + // by itself, it bombs. not sure why that is, but the + // same has been true of multi-line comments without complaints, + // so i'm not going to worry about it just yet. + assertEvalEquals(" "+END+" ", textblock(" ")+END+" "+textblock(" ")); + } + + public void testZerolengthTextblock() throws Exception + { + assertTextblockEvalEquals(""); + } + + public void testTextblockInsideForeachLoop() throws Exception + { + String s = "var myId = 'someID';$('#test).append($.template('<div id=\"${myId}\"></div>').apply({myId: myId}));"; + assertEvalEquals("1 "+s+"2 "+s+"3 "+s, "#foreach($i in [1..3])$i "+ textblock(s) + "#end"); + } + + public void testSingleHashInsideTextblock() throws Exception + { + assertTextblockEvalEquals(" # "); + } + + public void testDollarInsideTextblock() throws Exception + { + assertTextblockEvalEquals("$"); + } + + public void testTextblockInsideComment() throws Exception + { + String s = "FOOBAR"; + assertEvalEquals("", "#* comment "+textblock(s) + " *#"); + } + + public void testPartialStartEndTokensInsideTextblock() throws Exception + { + assertTextblockEvalEquals(PARTIAL_START+"foo"+PARTIAL_END); + } + + public void testDupeTokenChars() throws Exception + { + assertTextblockEvalEquals(END_OF_START+START_OF_END); + assertTextblockEvalEquals(END_OF_START+END_OF_START+START_OF_END+START_OF_END); + assertTextblockEvalEquals(END_OF_START+END_OF_START+"#"+START_OF_END+START_OF_END); + } + + /** + * https://issues.apache.org/jira/browse/VELOCITY-584 + */ + public void testServerSideIncludeEscaping() throws Exception + { + assertTextblockEvalEquals("<!--#include file=\"wisdom.inc\"--> "); + } + + +} Propchange: velocity/engine/trunk/src/test/org/apache/velocity/test/TextblockTestCase.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: velocity/engine/trunk/src/test/org/apache/velocity/test/TextblockTestCase.java ------------------------------------------------------------------------------ svn:keywords = Revision Propchange: velocity/engine/trunk/src/test/org/apache/velocity/test/TextblockTestCase.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: velocity/engine/trunk/xdocs/docs/translations/user-guide_fr.xml URL: http://svn.apache.org/viewvc/velocity/engine/trunk/xdocs/docs/translations/user-guide_fr.xml?rev=731779&r1=731778&r2=731779&view=diff ============================================================================== --- velocity/engine/trunk/xdocs/docs/translations/user-guide_fr.xml (original) +++ velocity/engine/trunk/xdocs/docs/translations/user-guide_fr.xml Mon Jan 5 16:10:57 2009 @@ -724,14 +724,14 @@ de Velocity. Ce comportement peut être changé en éditant le fichier <code>velocity.properties</code> et en y écrivant l'entrée: <code>stringliterals.interpolate=false</code>. </p> -<p>Ãgalement, la directive <em>#litteral</em> permet au concepteur de gabarits de facilement utiliser de gros morceaux de contenu +<p>Ãgalement, la directive <em>#[[ ]]#</em> permet au concepteur de gabarits de facilement utiliser de gros morceaux de contenu non interprété de code VTL. Ceci peut être particulièrement utile en remplacement de multiples <a href="#EchappementdesdirectivesVTL">échappements de directives</a>.</p> <source><![CDATA[ -#literal() +#[[ #foreach ($woogie in $boogie) nothing will happen to $woogie #end -#end +]]# ]]></source> <p>Sera rendu comme :</p> <source><![CDATA[ Modified: velocity/engine/trunk/xdocs/docs/user-guide.xml URL: http://svn.apache.org/viewvc/velocity/engine/trunk/xdocs/docs/user-guide.xml?rev=731779&r1=731778&r2=731779&view=diff ============================================================================== --- velocity/engine/trunk/xdocs/docs/user-guide.xml (original) +++ velocity/engine/trunk/xdocs/docs/user-guide.xml Mon Jan 5 16:10:57 2009 @@ -1100,18 +1100,20 @@ </p> <p> - Alternately, the <em>#literal</em> script element allows the + Alternately, the <em>#[[</em>don't parse me!<em>]]#</em> syntax allows the template designer to easily use large chunks of uninterpreted - content in VTL code. This can be especially useful in place of <a - href="#EscapingVTLDirectives">escaping</a> multiple directives. + and unparsed content in VTL code. This can be especially useful in place of <a + href="#EscapingVTLDirectives">escaping</a> multiple directives or escaping + sections which have content that would otherwise be invalid (and thus unparseable) + VTL. </p> <source><![CDATA[ -#literal() +#[[ #foreach ($woogie in $boogie) nothing will happen to $woogie #end -#end +]]# ]]></source> <p> Modified: velocity/engine/trunk/xdocs/docs/vtl-reference-guide.xml URL: http://svn.apache.org/viewvc/velocity/engine/trunk/xdocs/docs/vtl-reference-guide.xml?rev=731779&r1=731778&r2=731779&view=diff ============================================================================== --- velocity/engine/trunk/xdocs/docs/vtl-reference-guide.xml (original) +++ velocity/engine/trunk/xdocs/docs/vtl-reference-guide.xml Mon Jan 5 16:10:57 2009 @@ -570,6 +570,28 @@ </subsection> </section> +<section name="Unparsed Content" href="Unparsed"> + <p> + Unparsed content is rendered at runtime, but is not parsed or interpreted. + </p> + <p> + Example: + </p> + + <p> + <strong> + #[[<br/> + This has invalid syntax that would normally need + "poor man's escaping" like: + <ul> + <li>#define()</li> + <li>${blah</li> + </ul> + ]]# + </strong> + </p> +</section> + </body> </document>
