added support for escaping strategy in the autoescape tag (closes #19)
authorFabien Potencier <fabien.potencier@gmail.com>
Thu, 4 Mar 2010 10:08:16 +0000 (11:08 +0100)
committerFabien Potencier <fabien.potencier@gmail.com>
Thu, 4 Mar 2010 10:08:16 +0000 (11:08 +0100)
CHANGELOG
doc/02-Twig-for-Template-Designers.markdown
lib/Twig/Node/AutoEscape.php
lib/Twig/NodeVisitor/Escaper.php
lib/Twig/TokenParser/AutoEscape.php
test/fixtures/tags/autoescape/strategy.test [new file with mode: 0644]
test/unit/integrationTest.php

index 2428d7b..7e05726 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,6 @@
 * 0.9.6-DEV
 
+ * added support for escaping strategy in the autoescape tag
  * fixed lexer when a template has a big chunk of text between/in a block
 
 * 0.9.5 (2010-01-20)
index 5747696..4cf967e 100644 (file)
@@ -361,6 +361,11 @@ template to be escaped or not by using the `autoescape` tag:
       Everything will be outputed as is in this block
     {% endautoescape %}
 
+    {% autoescape on js %}
+      Everything will be automatically escaped in this block
+      using the js escaping strategy
+    {% endautoescape %}
+
 When automatic escaping is enabled everything is escaped by default except for
 values explicitly marked as safe. Those can be marked in the template by using
 the `|safe` filter.
index 97c6e6d..98df7f7 100644 (file)
 /**
  * Represents an autoescape node.
  *
+ * The value is the escaping strategy (can be html, js, ...)
+ *
+ * The true value is equivalent to html.
+ *
+ * If autoescaping is disabled, then the value is false.
+ *
  * @package    twig
  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
  * @version    SVN: $Id$
index 098345a..1859dcb 100644 (file)
@@ -19,9 +19,9 @@ class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
     {
       $this->statusStack[] = $node->getValue();
     }
-    elseif ($node instanceof Twig_Node_Print && true === $this->needEscaping($env))
+    elseif ($node instanceof Twig_Node_Print)
     {
-      return $this->escapeNode($node, $env);
+      return $this->escapeNode($node, $env, $this->needEscaping($env));
     }
     elseif ($node instanceof Twig_Node_Block)
     {
@@ -45,8 +45,13 @@ class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
     return $node;
   }
 
-  protected function escapeNode(Twig_Node $node, Twig_Environment $env)
+  protected function escapeNode(Twig_Node $node, Twig_Environment $env, $type)
   {
+    if (false === $type)
+    {
+      return $node;
+    }
+
     $expression = $node instanceof Twig_Node_Print ? $node->getExpression() : $node;
 
     if ($expression instanceof Twig_Node_Expression_Filter)
@@ -83,25 +88,25 @@ class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
       {
         foreach ($filter[1] as $j => $argument)
         {
-          $filters[$i][1][$j] = $this->escapeNode($argument, $env);
+          $filters[$i][1][$j] = $this->escapeNode($argument, $env, $type);
         }
       }
 
       $expression->setFilters($filters);
-      $expression->prependFilter($this->getEscaperFilter());
+      $expression->prependFilter($this->getEscaperFilter($type));
 
       return $node;
     }
     elseif ($node instanceof Twig_Node_Print)
     {
       return new Twig_Node_Print(
-        new Twig_Node_Expression_Filter($expression, array($this->getEscaperFilter()), $node->getLine())
+        new Twig_Node_Expression_Filter($expression, array($this->getEscaperFilter($type)), $node->getLine())
         , $node->getLine()
       );
     }
     else
     {
-      return new Twig_Node_Expression_Filter($node, array($this->getEscaperFilter()), $node->getLine());
+      return new Twig_Node_Expression_Filter($node, array($this->getEscaperFilter($type)), $node->getLine());
     }
   }
 
@@ -117,8 +122,8 @@ class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
     }
   }
 
-  protected function getEscaperFilter()
+  protected function getEscaperFilter($type)
   {
-    return array('escape', array());
+    return array('escape', array(new Twig_Node_Expression_Constant((string) $type, -1)));
   }
 }
index 45e514a..8943e2e 100644 (file)
@@ -18,12 +18,23 @@ class Twig_TokenParser_AutoEscape extends Twig_TokenParser
     {
       throw new Twig_SyntaxError("Autoescape value must be 'on' or 'off'", $lineno);
     }
+    $value = 'on' === $value ? true : false;
+
+    if ($this->parser->getStream()->test(Twig_Token::NAME_TYPE))
+    {
+      if (false === $value)
+      {
+        throw new Twig_SyntaxError(sprintf('Unexpected escaping strategy as you set autoescaping to off.', $lineno), -1);
+      }
+
+      $value = $this->parser->getStream()->next()->getValue();
+    }
 
     $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
     $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
     $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
 
-    return new Twig_Node_AutoEscape('on' === $value ? true : false, $body, $lineno, $this->getTag());
+    return new Twig_Node_AutoEscape($value, $body, $lineno, $this->getTag());
   }
 
   public function decideBlockEnd($token)
diff --git a/test/fixtures/tags/autoescape/strategy.test b/test/fixtures/tags/autoescape/strategy.test
new file mode 100644 (file)
index 0000000..f3e09dd
--- /dev/null
@@ -0,0 +1,11 @@
+--TEST--
+"autoescape" tag accepts an escaping strategy
+--TEMPLATE--
+{% autoescape on js %}{{ var }}{% endautoescape %}
+
+{% autoescape on html %}{{ var }}{% endautoescape %}
+--DATA--
+return array('var' => '<br />"')
+--EXPECT--
+<br />\"
+&lt;br /&gt;&quot;
index 2ac44d7..f8baf68 100644 (file)
@@ -51,7 +51,7 @@ class TestExtension extends Twig_Extension
   }
 }
 
-$t = new LimeTest(61);
+$t = new LimeTest(62);
 $fixturesDir = realpath(dirname(__FILE__).'/../fixtures/');
 
 foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($fixturesDir), RecursiveIteratorIterator::LEAVES_ONLY) as $file)