summaryrefslogtreecommitdiff
path: root/node_modules/twig/docs/twig.html
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/twig/docs/twig.html')
-rw-r--r--node_modules/twig/docs/twig.html11250
1 files changed, 11250 insertions, 0 deletions
diff --git a/node_modules/twig/docs/twig.html b/node_modules/twig/docs/twig.html
new file mode 100644
index 0000000..687abbd
--- /dev/null
+++ b/node_modules/twig/docs/twig.html
@@ -0,0 +1,11250 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <title>twig.js</title>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
+ <link rel="stylesheet" media="all" href="docco.css" />
+</head>
+<body>
+ <div id="container">
+ <div id="background"></div>
+
+ <ul class="sections">
+
+ <li id="title">
+ <div class="annotation">
+ <h1>twig.js</h1>
+ </div>
+ </li>
+
+
+
+ <li id="section-1">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-1">&#182;</a>
+ </div>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="hljs-comment">/**
+ * Twig.js 0.8.9
+ *
+ * @copyright 2011-2015 John Roepke and the Twig.js Contributors
+ * @license Available under the BSD 2-Clause License
+ * @link https://github.com/justjohn/twig.js
+ */</span>
+
+<span class="hljs-keyword">var</span> Twig = (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Twig</span>) </span>{
+
+ Twig.VERSION = <span class="hljs-string">"0.8.9"</span>;
+
+ <span class="hljs-keyword">return</span> Twig;
+})(Twig || {});</pre></div></div>
+
+ </li>
+
+
+ <li id="section-2">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-2">&#182;</a>
+ </div>
+ <pre><code>Twig.js
+Available under the BSD <span class="hljs-number">2</span>-Clause License
+https:<span class="hljs-comment">//github.com/justjohn/twig.js</span>
+</code></pre>
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+<span class="hljs-keyword">var</span> Twig = (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Twig</span>) </span>{
+<span class="hljs-meta"> "use strict"</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-3">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-3">&#182;</a>
+ </div>
+ <h2 id="twig-core-js">twig.core.js</h2>
+<p>This file handles template level tokenizing, compiling and parsing.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ Twig.trace = <span class="hljs-literal">false</span>;
+ Twig.debug = <span class="hljs-literal">false</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-4">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-4">&#182;</a>
+ </div>
+ <p>Default caching to true for the improved performance it offers</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.cache = <span class="hljs-literal">true</span>;
+
+ Twig.placeholders = {
+ parent: <span class="hljs-string">"{{|PARENT|}}"</span>
+ };
+
+ <span class="hljs-comment">/**
+ * Fallback for Array.indexOf for IE8 et al
+ */</span>
+ Twig.indexOf = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">arr, searchElement <span class="hljs-comment">/*, fromIndex */</span> </span>) </span>{
+ <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.prototype.hasOwnProperty(<span class="hljs-string">"indexOf"</span>)) {
+ <span class="hljs-keyword">return</span> arr.indexOf(searchElement);
+ }
+ <span class="hljs-keyword">if</span> (arr === <span class="hljs-keyword">void</span> <span class="hljs-number">0</span> || arr === <span class="hljs-literal">null</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>();
+ }
+ <span class="hljs-keyword">var</span> t = <span class="hljs-built_in">Object</span>(arr);
+ <span class="hljs-keyword">var</span> len = t.length &gt;&gt;&gt; <span class="hljs-number">0</span>;
+ <span class="hljs-keyword">if</span> (len === <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
+ }
+ <span class="hljs-keyword">var</span> n = <span class="hljs-number">0</span>;
+ <span class="hljs-keyword">if</span> (<span class="hljs-built_in">arguments</span>.length &gt; <span class="hljs-number">0</span>) {
+ n = <span class="hljs-built_in">Number</span>(<span class="hljs-built_in">arguments</span>[<span class="hljs-number">1</span>]);
+ <span class="hljs-keyword">if</span> (n !== n) { <span class="hljs-comment">// shortcut for verifying if it's NaN</span>
+ n = <span class="hljs-number">0</span>;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (n !== <span class="hljs-number">0</span> &amp;&amp; n !== <span class="hljs-literal">Infinity</span> &amp;&amp; n !== -<span class="hljs-literal">Infinity</span>) {
+ n = (n &gt; <span class="hljs-number">0</span> || <span class="hljs-number">-1</span>) * <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.abs(n));
+ }
+ }
+ <span class="hljs-keyword">if</span> (n &gt;= len) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-5">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-5">&#182;</a>
+ </div>
+ <p>console.log(“indexOf not found1 “, JSON.stringify(searchElement), JSON.stringify(arr));</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
+ }
+ <span class="hljs-keyword">var</span> k = n &gt;= <span class="hljs-number">0</span> ? n : <span class="hljs-built_in">Math</span>.max(len - <span class="hljs-built_in">Math</span>.abs(n), <span class="hljs-number">0</span>);
+ <span class="hljs-keyword">for</span> (; k &lt; len; k++) {
+ <span class="hljs-keyword">if</span> (k <span class="hljs-keyword">in</span> t &amp;&amp; t[k] === searchElement) {
+ <span class="hljs-keyword">return</span> k;
+ }
+ }
+ <span class="hljs-keyword">if</span> (arr == searchElement) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-6">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-6">&#182;</a>
+ </div>
+ <p>console.log(“indexOf not found2 “, JSON.stringify(searchElement), JSON.stringify(arr));</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
+ }
+
+ Twig.forEach = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">arr, callback, thisArg</span>) </span>{
+ <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.prototype.forEach ) {
+ <span class="hljs-keyword">return</span> arr.forEach(callback, thisArg);
+ }
+
+ <span class="hljs-keyword">var</span> T, k;
+
+ <span class="hljs-keyword">if</span> ( arr == <span class="hljs-literal">null</span> ) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>( <span class="hljs-string">" this is null or not defined"</span> );
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-7">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-7">&#182;</a>
+ </div>
+ <ol>
+<li>Let O be the result of calling ToObject passing the |this| value as the argument.</li>
+</ol>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> O = <span class="hljs-built_in">Object</span>(arr);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-8">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-8">&#182;</a>
+ </div>
+ <ol>
+<li>Let lenValue be the result of calling the Get internal method of O with the argument “length”.</li>
+<li>Let len be ToUint32(lenValue).</li>
+</ol>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> len = O.length &gt;&gt;&gt; <span class="hljs-number">0</span>; <span class="hljs-comment">// Hack to convert O.length to a UInt32</span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-9">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-9">&#182;</a>
+ </div>
+ <ol>
+<li>If IsCallable(callback) is false, throw a TypeError exception.
+See: <a href="http://es5.github.com/#x9.11">http://es5.github.com/#x9.11</a></li>
+</ol>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> ( {}.toString.call(callback) != <span class="hljs-string">"[object Function]"</span> ) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>( callback + <span class="hljs-string">" is not a function"</span> );
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-10">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-10">&#182;</a>
+ </div>
+ <ol>
+<li>If thisArg was supplied, let T be thisArg; else let T be undefined.</li>
+</ol>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> ( thisArg ) {
+ T = thisArg;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-11">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-11">&#182;</a>
+ </div>
+ <ol>
+<li>Let k be 0</li>
+</ol>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> k = <span class="hljs-number">0</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-12">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-12">&#182;</a>
+ </div>
+ <ol>
+<li>Repeat, while k &lt; len</li>
+</ol>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">while</span>( k &lt; len ) {
+
+ <span class="hljs-keyword">var</span> kValue;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-13">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-13">&#182;</a>
+ </div>
+ <p>a. Let Pk be ToString(k).
+ This is implicit for LHS operands of the in operator
+b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
+ This step can be combined with c
+c. If kPresent is true, then</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> ( k <span class="hljs-keyword">in</span> O ) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-14">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-14">&#182;</a>
+ </div>
+ <p>i. Let kValue be the result of calling the Get internal method of O with argument Pk.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> kValue = O[ k ];</pre></div></div>
+
+ </li>
+
+
+ <li id="section-15">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-15">&#182;</a>
+ </div>
+ <p>ii. Call the Call internal method of callback with T as the this value and
+argument list containing kValue, k, and O.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> callback.call( T, kValue, k, O );
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-16">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-16">&#182;</a>
+ </div>
+ <p>d. Increase k by 1.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> k++;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-17">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-17">&#182;</a>
+ </div>
+ <ol>
+<li>return undefined</li>
+</ol>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> };
+
+ Twig.merge = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">target, source, onlyChanged</span>) </span>{
+ Twig.forEach(<span class="hljs-built_in">Object</span>.keys(source), <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">key</span>) </span>{
+ <span class="hljs-keyword">if</span> (onlyChanged &amp;&amp; !(key <span class="hljs-keyword">in</span> target)) {
+ <span class="hljs-keyword">return</span>;
+ }
+
+ target[key] = source[key]
+ });
+
+ <span class="hljs-keyword">return</span> target;
+ };
+
+ <span class="hljs-comment">/**
+ * Exception thrown by twig.js.
+ */</span>
+ Twig.Error = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">message</span>) </span>{
+ <span class="hljs-keyword">this</span>.message = message;
+ <span class="hljs-keyword">this</span>.name = <span class="hljs-string">"TwigException"</span>;
+ <span class="hljs-keyword">this</span>.type = <span class="hljs-string">"TwigException"</span>;
+ };
+
+ <span class="hljs-comment">/**
+ * Get the string representation of a Twig error.
+ */</span>
+ Twig.Error.prototype.toString = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
+ <span class="hljs-keyword">var</span> output = <span class="hljs-keyword">this</span>.name + <span class="hljs-string">": "</span> + <span class="hljs-keyword">this</span>.message;
+
+ <span class="hljs-keyword">return</span> output;
+ };
+
+ <span class="hljs-comment">/**
+ * Wrapper for logging to the console.
+ */</span>
+ Twig.log = {
+ trace: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{<span class="hljs-keyword">if</span> (Twig.trace &amp;&amp; <span class="hljs-built_in">console</span>) {<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">Array</span>.prototype.slice.call(<span class="hljs-built_in">arguments</span>));}},
+ debug: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{<span class="hljs-keyword">if</span> (Twig.debug &amp;&amp; <span class="hljs-built_in">console</span>) {<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">Array</span>.prototype.slice.call(<span class="hljs-built_in">arguments</span>));}}
+ };
+
+
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">console</span> !== <span class="hljs-string">"undefined"</span>) {
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">console</span>.error !== <span class="hljs-string">"undefined"</span>) {
+ Twig.log.error = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
+ <span class="hljs-built_in">console</span>.error.apply(<span class="hljs-built_in">console</span>, <span class="hljs-built_in">arguments</span>);
+ }
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">console</span>.log !== <span class="hljs-string">"undefined"</span>) {
+ Twig.log.error = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
+ <span class="hljs-built_in">console</span>.log.apply(<span class="hljs-built_in">console</span>, <span class="hljs-built_in">arguments</span>);
+ }
+ }
+ } <span class="hljs-keyword">else</span> {
+ Twig.log.error = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{};
+ }
+
+ <span class="hljs-comment">/**
+ * Wrapper for child context objects in Twig.
+ *
+ * @param {Object} context Values to initialize the context with.
+ */</span>
+ Twig.ChildContext = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">context</span>) </span>{
+ <span class="hljs-keyword">var</span> ChildContext = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ChildContext</span>(<span class="hljs-params"></span>) </span>{};
+ ChildContext.prototype = context;
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ChildContext();
+ };
+
+ <span class="hljs-comment">/**
+ * Container for methods related to handling high level template tokens
+ * (for example: {{ expression }}, {% logic %}, {# comment #}, raw data)
+ */</span>
+ Twig.token = {};
+
+ <span class="hljs-comment">/**
+ * Token types.
+ */</span>
+ Twig.token.type = {
+ output: <span class="hljs-string">'output'</span>,
+ logic: <span class="hljs-string">'logic'</span>,
+ comment: <span class="hljs-string">'comment'</span>,
+ raw: <span class="hljs-string">'raw'</span>,
+ output_whitespace_pre: <span class="hljs-string">'output_whitespace_pre'</span>,
+ output_whitespace_post: <span class="hljs-string">'output_whitespace_post'</span>,
+ output_whitespace_both: <span class="hljs-string">'output_whitespace_both'</span>,
+ logic_whitespace_pre: <span class="hljs-string">'logic_whitespace_pre'</span>,
+ logic_whitespace_post: <span class="hljs-string">'logic_whitespace_post'</span>,
+ logic_whitespace_both: <span class="hljs-string">'logic_whitespace_both'</span>
+ };
+
+ <span class="hljs-comment">/**
+ * Token syntax definitions.
+ */</span>
+ Twig.token.definitions = [
+ {
+ type: Twig.token.type.raw,
+ open: <span class="hljs-string">'{% raw %}'</span>,
+ close: <span class="hljs-string">'{% endraw %}'</span>
+ },
+ {
+ type: Twig.token.type.raw,
+ open: <span class="hljs-string">'{% verbatim %}'</span>,
+ close: <span class="hljs-string">'{% endverbatim %}'</span>
+ },</pre></div></div>
+
+ </li>
+
+
+ <li id="section-18">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-18">&#182;</a>
+ </div>
+ <p><em>Whitespace type tokens</em></p>
+<p>These typically take the form <code>{{- expression -}}</code> or <code>{{- expression }}</code> or <code>{{ expression -}}</code>.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> {
+ type: Twig.token.type.output_whitespace_pre,
+ open: <span class="hljs-string">'{{-'</span>,
+ close: <span class="hljs-string">'}}'</span>
+ },
+ {
+ type: Twig.token.type.output_whitespace_post,
+ open: <span class="hljs-string">'{{'</span>,
+ close: <span class="hljs-string">'-}}'</span>
+ },
+ {
+ type: Twig.token.type.output_whitespace_both,
+ open: <span class="hljs-string">'{{-'</span>,
+ close: <span class="hljs-string">'-}}'</span>
+ },
+ {
+ type: Twig.token.type.logic_whitespace_pre,
+ open: <span class="hljs-string">'{%-'</span>,
+ close: <span class="hljs-string">'%}'</span>
+ },
+ {
+ type: Twig.token.type.logic_whitespace_post,
+ open: <span class="hljs-string">'{%'</span>,
+ close: <span class="hljs-string">'-%}'</span>
+ },
+ {
+ type: Twig.token.type.logic_whitespace_both,
+ open: <span class="hljs-string">'{%-'</span>,
+ close: <span class="hljs-string">'-%}'</span>
+ },</pre></div></div>
+
+ </li>
+
+
+ <li id="section-19">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-19">&#182;</a>
+ </div>
+ <p><em>Output type tokens</em></p>
+<p>These typically take the form <code>{{ expression }}</code>.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> {
+ type: Twig.token.type.output,
+ open: <span class="hljs-string">'{{'</span>,
+ close: <span class="hljs-string">'}}'</span>
+ },</pre></div></div>
+
+ </li>
+
+
+ <li id="section-20">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-20">&#182;</a>
+ </div>
+ <p><em>Logic type tokens</em></p>
+<p>These typically take a form like <code>{% if expression %}</code> or <code>{% endif %}</code></p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> {
+ type: Twig.token.type.logic,
+ open: <span class="hljs-string">'{%'</span>,
+ close: <span class="hljs-string">'%}'</span>
+ },</pre></div></div>
+
+ </li>
+
+
+ <li id="section-21">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-21">&#182;</a>
+ </div>
+ <p><em>Comment type tokens</em></p>
+<p>These take the form <code>{# anything #}</code></p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> {
+ type: Twig.token.type.comment,
+ open: <span class="hljs-string">'{#'</span>,
+ close: <span class="hljs-string">'#}'</span>
+ }
+ ];
+
+
+ <span class="hljs-comment">/**
+ * What characters start "strings" in token definitions. We need this to ignore token close
+ * strings inside an expression.
+ */</span>
+ Twig.token.strings = [<span class="hljs-string">'"'</span>, <span class="hljs-string">"'"</span>];
+
+ Twig.token.findStart = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">template</span>) </span>{
+ <span class="hljs-keyword">var</span> output = {
+ position: <span class="hljs-literal">null</span>,
+ close_position: <span class="hljs-literal">null</span>,
+ def: <span class="hljs-literal">null</span>
+ },
+ i,
+ token_template,
+ first_key_position,
+ close_key_position;
+
+ <span class="hljs-keyword">for</span> (i=<span class="hljs-number">0</span>;i&lt;Twig.token.definitions.length;i++) {
+ token_template = Twig.token.definitions[i];
+ first_key_position = template.indexOf(token_template.open);
+ close_key_position = template.indexOf(token_template.close);
+
+ Twig.log.trace(<span class="hljs-string">"Twig.token.findStart: "</span>, <span class="hljs-string">"Searching for "</span>, token_template.open, <span class="hljs-string">" found at "</span>, first_key_position);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-22">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-22">&#182;</a>
+ </div>
+ <p>Special handling for mismatched tokens</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (first_key_position &gt;= <span class="hljs-number">0</span>) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-23">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-23">&#182;</a>
+ </div>
+ <p>This token matches the template</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (token_template.open.length !== token_template.close.length) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-24">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-24">&#182;</a>
+ </div>
+ <p>This token has mismatched closing and opening tags</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (close_key_position &lt; <span class="hljs-number">0</span>) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-25">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-25">&#182;</a>
+ </div>
+ <p>This token’s closing tag does not match the template</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">continue</span>;
+ }
+ }
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-26">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-26">&#182;</a>
+ </div>
+ <p>Does this token occur before any other types?</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (first_key_position &gt;= <span class="hljs-number">0</span> &amp;&amp; (output.position === <span class="hljs-literal">null</span> || first_key_position &lt; output.position)) {
+ output.position = first_key_position;
+ output.def = token_template;
+ output.close_position = close_key_position;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (first_key_position &gt;= <span class="hljs-number">0</span> &amp;&amp; output.position !== <span class="hljs-literal">null</span> &amp;&amp; first_key_position === output.position) {
+ <span class="hljs-comment">/*This token exactly matches another token,
+ greedily match to check if this token has a greater specificity*/</span>
+ <span class="hljs-keyword">if</span> (token_template.open.length &gt; output.def.open.length) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-27">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-27">&#182;</a>
+ </div>
+ <p>This token’s opening tag is more specific than the previous match</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> output.position = first_key_position;
+ output.def = token_template;
+ output.close_position = close_key_position;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (token_template.open.length === output.def.open.length) {
+ <span class="hljs-keyword">if</span> (token_template.close.length &gt; output.def.close.length) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-28">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-28">&#182;</a>
+ </div>
+ <p>This token’s opening tag is as specific as the previous match,
+but the closing tag has greater specificity</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (close_key_position &gt;= <span class="hljs-number">0</span> &amp;&amp; close_key_position &lt; output.close_position) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-29">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-29">&#182;</a>
+ </div>
+ <p>This token’s closing tag exists in the template,
+and it occurs sooner than the previous match</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> output.position = first_key_position;
+ output.def = token_template;
+ output.close_position = close_key_position;
+ }
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (close_key_position &gt;= <span class="hljs-number">0</span> &amp;&amp; close_key_position &lt; output.close_position) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-30">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-30">&#182;</a>
+ </div>
+ <p>This token’s closing tag is not more specific than the previous match,
+but it occurs sooner than the previous match</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> output.position = first_key_position;
+ output.def = token_template;
+ output.close_position = close_key_position;
+ }
+ }
+ }
+ }
+
+ <span class="hljs-keyword">delete</span> output[<span class="hljs-string">'close_position'</span>];
+
+ <span class="hljs-keyword">return</span> output;
+ };
+
+ Twig.token.findEnd = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">template, token_def, start</span>) </span>{
+ <span class="hljs-keyword">var</span> end = <span class="hljs-literal">null</span>,
+ found = <span class="hljs-literal">false</span>,
+ offset = <span class="hljs-number">0</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-31">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-31">&#182;</a>
+ </div>
+ <p>String position variables</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> str_pos = <span class="hljs-literal">null</span>,
+ str_found = <span class="hljs-literal">null</span>,
+ pos = <span class="hljs-literal">null</span>,
+ end_offset = <span class="hljs-literal">null</span>,
+ this_str_pos = <span class="hljs-literal">null</span>,
+ end_str_pos = <span class="hljs-literal">null</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-32">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-32">&#182;</a>
+ </div>
+ <p>For loop variables</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> i,
+ l;
+
+ <span class="hljs-keyword">while</span> (!found) {
+ str_pos = <span class="hljs-literal">null</span>;
+ str_found = <span class="hljs-literal">null</span>;
+ pos = template.indexOf(token_def.close, offset);
+
+ <span class="hljs-keyword">if</span> (pos &gt;= <span class="hljs-number">0</span>) {
+ end = pos;
+ found = <span class="hljs-literal">true</span>;
+ } <span class="hljs-keyword">else</span> {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-33">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-33">&#182;</a>
+ </div>
+ <p>throw an exception</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Unable to find closing bracket '"</span> + token_def.close +
+ <span class="hljs-string">"'"</span> + <span class="hljs-string">" opened near template position "</span> + start);
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-34">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-34">&#182;</a>
+ </div>
+ <p>Ignore quotes within comments; just look for the next comment close sequence,
+regardless of what comes before it. <a href="https://github.com/justjohn/twig.js/issues/95">https://github.com/justjohn/twig.js/issues/95</a></p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (token_def.type === Twig.token.type.comment) {
+ <span class="hljs-keyword">break</span>;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-35">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-35">&#182;</a>
+ </div>
+ <p>Ignore quotes within raw tag
+Fixes #283</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (token_def.type === Twig.token.type.raw) {
+ <span class="hljs-keyword">break</span>;
+ }
+
+ l = Twig.token.strings.length;
+ <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; l; i += <span class="hljs-number">1</span>) {
+ this_str_pos = template.indexOf(Twig.token.strings[i], offset);
+
+ <span class="hljs-keyword">if</span> (this_str_pos &gt; <span class="hljs-number">0</span> &amp;&amp; this_str_pos &lt; pos &amp;&amp;
+ (str_pos === <span class="hljs-literal">null</span> || this_str_pos &lt; str_pos)) {
+ str_pos = this_str_pos;
+ str_found = Twig.token.strings[i];
+ }
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-36">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-36">&#182;</a>
+ </div>
+ <p>We found a string before the end of the token, now find the string’s end and set the search offset to it</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (str_pos !== <span class="hljs-literal">null</span>) {
+ end_offset = str_pos + <span class="hljs-number">1</span>;
+ end = <span class="hljs-literal">null</span>;
+ found = <span class="hljs-literal">false</span>;
+ <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
+ end_str_pos = template.indexOf(str_found, end_offset);
+ <span class="hljs-keyword">if</span> (end_str_pos &lt; <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-string">"Unclosed string in template"</span>;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-37">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-37">&#182;</a>
+ </div>
+ <p>Ignore escaped quotes</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (template.substr(end_str_pos - <span class="hljs-number">1</span>, <span class="hljs-number">1</span>) !== <span class="hljs-string">"\\"</span>) {
+ offset = end_str_pos + <span class="hljs-number">1</span>;
+ <span class="hljs-keyword">break</span>;
+ } <span class="hljs-keyword">else</span> {
+ end_offset = end_str_pos + <span class="hljs-number">1</span>;
+ }
+ }
+ }
+ }
+ <span class="hljs-keyword">return</span> end;
+ };
+
+ <span class="hljs-comment">/**
+ * Convert a template into high-level tokens.
+ */</span>
+ Twig.tokenize = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">template</span>) </span>{
+ <span class="hljs-keyword">var</span> tokens = [],</pre></div></div>
+
+ </li>
+
+
+ <li id="section-38">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-38">&#182;</a>
+ </div>
+ <p>An offset for reporting errors locations in the template.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> error_offset = <span class="hljs-number">0</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-39">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-39">&#182;</a>
+ </div>
+ <p>The start and type of the first token found in the template.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> found_token = <span class="hljs-literal">null</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-40">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-40">&#182;</a>
+ </div>
+ <p>The end position of the matched token.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> end = <span class="hljs-literal">null</span>;
+
+ <span class="hljs-keyword">while</span> (template.length &gt; <span class="hljs-number">0</span>) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-41">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-41">&#182;</a>
+ </div>
+ <p>Find the first occurance of any token type in the template</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> found_token = Twig.token.findStart(template);
+
+ Twig.log.trace(<span class="hljs-string">"Twig.tokenize: "</span>, <span class="hljs-string">"Found token: "</span>, found_token);
+
+ <span class="hljs-keyword">if</span> (found_token.position !== <span class="hljs-literal">null</span>) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-42">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-42">&#182;</a>
+ </div>
+ <p>Add a raw type token for anything before the start of the token</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (found_token.position &gt; <span class="hljs-number">0</span>) {
+ tokens.push({
+ type: Twig.token.type.raw,
+ value: template.substring(<span class="hljs-number">0</span>, found_token.position)
+ });
+ }
+ template = template.substr(found_token.position + found_token.def.open.length);
+ error_offset += found_token.position + found_token.def.open.length;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-43">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-43">&#182;</a>
+ </div>
+ <p>Find the end of the token</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> end = Twig.token.findEnd(template, found_token.def, error_offset);
+
+ Twig.log.trace(<span class="hljs-string">"Twig.tokenize: "</span>, <span class="hljs-string">"Token ends at "</span>, end);
+
+ tokens.push({
+ type: found_token.def.type,
+ value: template.substring(<span class="hljs-number">0</span>, end).trim()
+ });
+
+ <span class="hljs-keyword">if</span> (template.substr( end + found_token.def.close.length, <span class="hljs-number">1</span> ) === <span class="hljs-string">"\n"</span>) {
+ <span class="hljs-keyword">switch</span> (found_token.def.type) {
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"logic_whitespace_pre"</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"logic_whitespace_post"</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"logic_whitespace_both"</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"logic"</span>:</pre></div></div>
+
+ </li>
+
+
+ <li id="section-44">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-44">&#182;</a>
+ </div>
+ <p>Newlines directly after logic tokens are ignored</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> end += <span class="hljs-number">1</span>;
+ <span class="hljs-keyword">break</span>;
+ }
+ }
+
+ template = template.substr(end + found_token.def.close.length);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-45">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-45">&#182;</a>
+ </div>
+ <p>Increment the position in the template</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> error_offset += end + found_token.def.close.length;
+
+ } <span class="hljs-keyword">else</span> {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-46">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-46">&#182;</a>
+ </div>
+ <p>No more tokens -&gt; add the rest of the template as a raw-type token</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> tokens.push({
+ type: Twig.token.type.raw,
+ value: template
+ });
+ template = <span class="hljs-string">''</span>;
+ }
+ }
+
+ <span class="hljs-keyword">return</span> tokens;
+ };
+
+
+ Twig.compile = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">tokens</span>) </span>{
+ <span class="hljs-keyword">try</span> {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-47">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-47">&#182;</a>
+ </div>
+ <p>Output and intermediate stacks</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> output = [],
+ stack = [],</pre></div></div>
+
+ </li>
+
+
+ <li id="section-48">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-48">&#182;</a>
+ </div>
+ <p>The tokens between open and close tags</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> intermediate_output = [],
+
+ token = <span class="hljs-literal">null</span>,
+ logic_token = <span class="hljs-literal">null</span>,
+ unclosed_token = <span class="hljs-literal">null</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-49">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-49">&#182;</a>
+ </div>
+ <p>Temporary previous token.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> prev_token = <span class="hljs-literal">null</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-50">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-50">&#182;</a>
+ </div>
+ <p>Temporary previous output.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> prev_output = <span class="hljs-literal">null</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-51">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-51">&#182;</a>
+ </div>
+ <p>Temporary previous intermediate output.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> prev_intermediate_output = <span class="hljs-literal">null</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-52">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-52">&#182;</a>
+ </div>
+ <p>The previous token’s template</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> prev_template = <span class="hljs-literal">null</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-53">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-53">&#182;</a>
+ </div>
+ <p>Token lookahead</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> next_token = <span class="hljs-literal">null</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-54">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-54">&#182;</a>
+ </div>
+ <p>The output token</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> tok_output = <span class="hljs-literal">null</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-55">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-55">&#182;</a>
+ </div>
+ <p>Logic Token values</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> type = <span class="hljs-literal">null</span>,
+ open = <span class="hljs-literal">null</span>,
+ next = <span class="hljs-literal">null</span>;
+
+ <span class="hljs-keyword">var</span> compile_output = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token</span>) </span>{
+ Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [token]);
+ <span class="hljs-keyword">if</span> (stack.length &gt; <span class="hljs-number">0</span>) {
+ intermediate_output.push(token);
+ } <span class="hljs-keyword">else</span> {
+ output.push(token);
+ }
+ };
+
+ <span class="hljs-keyword">var</span> compile_logic = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-56">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-56">&#182;</a>
+ </div>
+ <p>Compile the logic token</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> logic_token = Twig.logic.compile.apply(<span class="hljs-keyword">this</span>, [token]);
+
+ type = logic_token.type;
+ open = Twig.logic.handler[type].open;
+ next = Twig.logic.handler[type].next;
+
+ Twig.log.trace(<span class="hljs-string">"Twig.compile: "</span>, <span class="hljs-string">"Compiled logic token to "</span>, logic_token,
+ <span class="hljs-string">" next is: "</span>, next, <span class="hljs-string">" open is : "</span>, open);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-57">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-57">&#182;</a>
+ </div>
+ <p>Not a standalone token, check logic stack to see if this is expected</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (open !== <span class="hljs-literal">undefined</span> &amp;&amp; !open) {
+ prev_token = stack.pop();
+ prev_template = Twig.logic.handler[prev_token.type];
+
+ <span class="hljs-keyword">if</span> (Twig.indexOf(prev_template.next, type) &lt; <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(type + <span class="hljs-string">" not expected after a "</span> + prev_token.type);
+ }
+
+ prev_token.output = prev_token.output || [];
+
+ prev_token.output = prev_token.output.concat(intermediate_output);
+ intermediate_output = [];
+
+ tok_output = {
+ type: Twig.token.type.logic,
+ token: prev_token
+ };
+ <span class="hljs-keyword">if</span> (stack.length &gt; <span class="hljs-number">0</span>) {
+ intermediate_output.push(tok_output);
+ } <span class="hljs-keyword">else</span> {
+ output.push(tok_output);
+ }
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-58">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-58">&#182;</a>
+ </div>
+ <p>This token requires additional tokens to complete the logic structure.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (next !== <span class="hljs-literal">undefined</span> &amp;&amp; next.length &gt; <span class="hljs-number">0</span>) {
+ Twig.log.trace(<span class="hljs-string">"Twig.compile: "</span>, <span class="hljs-string">"Pushing "</span>, logic_token, <span class="hljs-string">" to logic stack."</span>);
+
+ <span class="hljs-keyword">if</span> (stack.length &gt; <span class="hljs-number">0</span>) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-59">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-59">&#182;</a>
+ </div>
+ <p>Put any currently held output into the output list of the logic operator
+currently at the head of the stack before we push a new one on.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> prev_token = stack.pop();
+ prev_token.output = prev_token.output || [];
+ prev_token.output = prev_token.output.concat(intermediate_output);
+ stack.push(prev_token);
+ intermediate_output = [];
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-60">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-60">&#182;</a>
+ </div>
+ <p>Push the new logic token onto the logic stack</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> stack.push(logic_token);
+
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (open !== <span class="hljs-literal">undefined</span> &amp;&amp; open) {
+ tok_output = {
+ type: Twig.token.type.logic,
+ token: logic_token
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-61">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-61">&#182;</a>
+ </div>
+ <p>Standalone token (like {% set … %}</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (stack.length &gt; <span class="hljs-number">0</span>) {
+ intermediate_output.push(tok_output);
+ } <span class="hljs-keyword">else</span> {
+ output.push(tok_output);
+ }
+ }
+ };
+
+ <span class="hljs-keyword">while</span> (tokens.length &gt; <span class="hljs-number">0</span>) {
+ token = tokens.shift();
+ prev_output = output[output.length - <span class="hljs-number">1</span>];
+ prev_intermediate_output = intermediate_output[intermediate_output.length - <span class="hljs-number">1</span>];
+ next_token = tokens[<span class="hljs-number">0</span>];
+ Twig.log.trace(<span class="hljs-string">"Compiling token "</span>, token);
+ <span class="hljs-keyword">switch</span> (token.type) {
+ <span class="hljs-keyword">case</span> Twig.token.type.raw:
+ <span class="hljs-keyword">if</span> (stack.length &gt; <span class="hljs-number">0</span>) {
+ intermediate_output.push(token);
+ } <span class="hljs-keyword">else</span> {
+ output.push(token);
+ }
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> Twig.token.type.logic:
+ compile_logic.call(<span class="hljs-keyword">this</span>, token);
+ <span class="hljs-keyword">break</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-62">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-62">&#182;</a>
+ </div>
+ <p>Do nothing, comments should be ignored</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> Twig.token.type.comment:
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> Twig.token.type.output:
+ compile_output.call(<span class="hljs-keyword">this</span>, token);
+ <span class="hljs-keyword">break</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-63">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-63">&#182;</a>
+ </div>
+ <p>Kill whitespace ahead and behind this token</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> Twig.token.type.logic_whitespace_pre:
+ <span class="hljs-keyword">case</span> Twig.token.type.logic_whitespace_post:
+ <span class="hljs-keyword">case</span> Twig.token.type.logic_whitespace_both:
+ <span class="hljs-keyword">case</span> Twig.token.type.output_whitespace_pre:
+ <span class="hljs-keyword">case</span> Twig.token.type.output_whitespace_post:
+ <span class="hljs-keyword">case</span> Twig.token.type.output_whitespace_both:
+ <span class="hljs-keyword">if</span> (token.type !== Twig.token.type.output_whitespace_post &amp;&amp; token.type !== Twig.token.type.logic_whitespace_post) {
+ <span class="hljs-keyword">if</span> (prev_output) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-64">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-64">&#182;</a>
+ </div>
+ <p>If the previous output is raw, pop it off</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (prev_output.type === Twig.token.type.raw) {
+ output.pop();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-65">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-65">&#182;</a>
+ </div>
+ <p>If the previous output is not just whitespace, trim it</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (prev_output.value.match(<span class="hljs-regexp">/^\s*$/</span>) === <span class="hljs-literal">null</span>) {
+ prev_output.value = prev_output.value.trim();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-66">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-66">&#182;</a>
+ </div>
+ <p>Repush the previous output</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> output.push(prev_output);
+ }
+ }
+ }
+
+ <span class="hljs-keyword">if</span> (prev_intermediate_output) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-67">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-67">&#182;</a>
+ </div>
+ <p>If the previous intermediate output is raw, pop it off</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (prev_intermediate_output.type === Twig.token.type.raw) {
+ intermediate_output.pop();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-68">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-68">&#182;</a>
+ </div>
+ <p>If the previous output is not just whitespace, trim it</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (prev_intermediate_output.value.match(<span class="hljs-regexp">/^\s*$/</span>) === <span class="hljs-literal">null</span>) {
+ prev_intermediate_output.value = prev_intermediate_output.value.trim();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-69">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-69">&#182;</a>
+ </div>
+ <p>Repush the previous intermediate output</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> intermediate_output.push(prev_intermediate_output);
+ }
+ }
+ }
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-70">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-70">&#182;</a>
+ </div>
+ <p>Compile this token</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">switch</span> (token.type) {
+ <span class="hljs-keyword">case</span> Twig.token.type.output_whitespace_pre:
+ <span class="hljs-keyword">case</span> Twig.token.type.output_whitespace_post:
+ <span class="hljs-keyword">case</span> Twig.token.type.output_whitespace_both:
+ compile_output.call(<span class="hljs-keyword">this</span>, token);
+ <span class="hljs-keyword">break</span>;
+ <span class="hljs-keyword">case</span> Twig.token.type.logic_whitespace_pre:
+ <span class="hljs-keyword">case</span> Twig.token.type.logic_whitespace_post:
+ <span class="hljs-keyword">case</span> Twig.token.type.logic_whitespace_both:
+ compile_logic.call(<span class="hljs-keyword">this</span>, token);
+ <span class="hljs-keyword">break</span>;
+ }
+
+ <span class="hljs-keyword">if</span> (token.type !== Twig.token.type.output_whitespace_pre &amp;&amp; token.type !== Twig.token.type.logic_whitespace_pre) {
+ <span class="hljs-keyword">if</span> (next_token) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-71">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-71">&#182;</a>
+ </div>
+ <p>If the next token is raw, shift it out</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (next_token.type === Twig.token.type.raw) {
+ tokens.shift();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-72">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-72">&#182;</a>
+ </div>
+ <p>If the next token is not just whitespace, trim it</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (next_token.value.match(<span class="hljs-regexp">/^\s*$/</span>) === <span class="hljs-literal">null</span>) {
+ next_token.value = next_token.value.trim();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-73">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-73">&#182;</a>
+ </div>
+ <p>Unshift the next token</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> tokens.unshift(next_token);
+ }
+ }
+ }
+ }
+
+ <span class="hljs-keyword">break</span>;
+ }
+
+ Twig.log.trace(<span class="hljs-string">"Twig.compile: "</span>, <span class="hljs-string">" Output: "</span>, output,
+ <span class="hljs-string">" Logic Stack: "</span>, stack,
+ <span class="hljs-string">" Pending Output: "</span>, intermediate_output );
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-74">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-74">&#182;</a>
+ </div>
+ <p>Verify that there are no logic tokens left in the stack.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (stack.length &gt; <span class="hljs-number">0</span>) {
+ unclosed_token = stack.pop();
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Unable to find an end tag for "</span> + unclosed_token.type +
+ <span class="hljs-string">", expecting one of "</span> + unclosed_token.next);
+ }
+ <span class="hljs-keyword">return</span> output;
+ } <span class="hljs-keyword">catch</span> (ex) {
+ Twig.log.error(<span class="hljs-string">"Error compiling twig template "</span> + <span class="hljs-keyword">this</span>.id + <span class="hljs-string">": "</span>);
+ <span class="hljs-keyword">if</span> (ex.stack) {
+ Twig.log.error(ex.stack);
+ } <span class="hljs-keyword">else</span> {
+ Twig.log.error(ex.toString());
+ }
+
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.options.rethrow) <span class="hljs-keyword">throw</span> ex;
+ }
+ };
+
+ <span class="hljs-comment">/**
+ * Parse a compiled template.
+ *
+ * @param {Array} tokens The compiled tokens.
+ * @param {Object} context The render context.
+ *
+ * @return {string} The parsed template.
+ */</span>
+ Twig.parse = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">tokens, context</span>) </span>{
+ <span class="hljs-keyword">try</span> {
+ <span class="hljs-keyword">var</span> output = [],</pre></div></div>
+
+ </li>
+
+
+ <li id="section-75">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-75">&#182;</a>
+ </div>
+ <p>Track logic chains</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> chain = <span class="hljs-literal">true</span>,
+ that = <span class="hljs-keyword">this</span>;
+
+ Twig.forEach(tokens, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseToken</span>(<span class="hljs-params">token</span>) </span>{
+ Twig.log.debug(<span class="hljs-string">"Twig.parse: "</span>, <span class="hljs-string">"Parsing token: "</span>, token);
+
+ <span class="hljs-keyword">switch</span> (token.type) {
+ <span class="hljs-keyword">case</span> Twig.token.type.raw:
+ output.push(Twig.filters.raw(token.value));
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> Twig.token.type.logic:
+ <span class="hljs-keyword">var</span> logic_token = token.token,
+ logic = Twig.logic.parse.apply(that, [logic_token, context, chain]);
+
+ <span class="hljs-keyword">if</span> (logic.chain !== <span class="hljs-literal">undefined</span>) {
+ chain = logic.chain;
+ }
+ <span class="hljs-keyword">if</span> (logic.context !== <span class="hljs-literal">undefined</span>) {
+ context = logic.context;
+ }
+ <span class="hljs-keyword">if</span> (logic.output !== <span class="hljs-literal">undefined</span>) {
+ output.push(logic.output);
+ }
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> Twig.token.type.comment:</pre></div></div>
+
+ </li>
+
+
+ <li id="section-76">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-76">&#182;</a>
+ </div>
+ <p>Do nothing, comments should be ignored</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">break</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-77">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-77">&#182;</a>
+ </div>
+ <p>Fall through whitespace to output</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> Twig.token.type.output_whitespace_pre:
+ <span class="hljs-keyword">case</span> Twig.token.type.output_whitespace_post:
+ <span class="hljs-keyword">case</span> Twig.token.type.output_whitespace_both:
+ <span class="hljs-keyword">case</span> Twig.token.type.output:
+ Twig.log.debug(<span class="hljs-string">"Twig.parse: "</span>, <span class="hljs-string">"Output token: "</span>, token.stack);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-78">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-78">&#182;</a>
+ </div>
+ <p>Parse the given expression in the given context</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> output.push(Twig.expression.parse.apply(that, [token.stack, context]));
+ <span class="hljs-keyword">break</span>;
+ }
+ });
+ <span class="hljs-keyword">return</span> Twig.output.apply(<span class="hljs-keyword">this</span>, [output]);
+ } <span class="hljs-keyword">catch</span> (ex) {
+ Twig.log.error(<span class="hljs-string">"Error parsing twig template "</span> + <span class="hljs-keyword">this</span>.id + <span class="hljs-string">": "</span>);
+ <span class="hljs-keyword">if</span> (ex.stack) {
+ Twig.log.error(ex.stack);
+ } <span class="hljs-keyword">else</span> {
+ Twig.log.error(ex.toString());
+ }
+
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.options.rethrow) <span class="hljs-keyword">throw</span> ex;
+
+ <span class="hljs-keyword">if</span> (Twig.debug) {
+ <span class="hljs-keyword">return</span> ex.toString();
+ }
+ }
+ };
+
+ <span class="hljs-comment">/**
+ * Tokenize and compile a string template.
+ *
+ * @param {string} data The template.
+ *
+ * @return {Array} The compiled tokens.
+ */</span>
+ Twig.prepare = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>) </span>{
+ <span class="hljs-keyword">var</span> tokens, raw_tokens;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-79">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-79">&#182;</a>
+ </div>
+ <p>Tokenize</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.log.debug(<span class="hljs-string">"Twig.prepare: "</span>, <span class="hljs-string">"Tokenizing "</span>, data);
+ raw_tokens = Twig.tokenize.apply(<span class="hljs-keyword">this</span>, [data]);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-80">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-80">&#182;</a>
+ </div>
+ <p>Compile</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.log.debug(<span class="hljs-string">"Twig.prepare: "</span>, <span class="hljs-string">"Compiling "</span>, raw_tokens);
+ tokens = Twig.compile.apply(<span class="hljs-keyword">this</span>, [raw_tokens]);
+
+ Twig.log.debug(<span class="hljs-string">"Twig.prepare: "</span>, <span class="hljs-string">"Compiled "</span>, tokens);
+
+ <span class="hljs-keyword">return</span> tokens;
+ };
+
+ <span class="hljs-comment">/**
+ * Join the output token's stack and escape it if needed
+ *
+ * @param {Array} Output token's stack
+ *
+ * @return {string|String} Autoescaped output
+ */</span>
+ Twig.output = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">output</span>) </span>{
+ <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.options.autoescape) {
+ <span class="hljs-keyword">return</span> output.join(<span class="hljs-string">""</span>);
+ }
+
+ <span class="hljs-keyword">var</span> strategy = <span class="hljs-string">'html'</span>;
+ <span class="hljs-keyword">if</span>(<span class="hljs-keyword">typeof</span> <span class="hljs-keyword">this</span>.options.autoescape == <span class="hljs-string">'string'</span>)
+ strategy = <span class="hljs-keyword">this</span>.options.autoescape;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-81">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-81">&#182;</a>
+ </div>
+ <p>[].map would be better but it’s not supported by IE8-</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> escaped_output = [];
+ Twig.forEach(output, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">str</span>) </span>{
+ <span class="hljs-keyword">if</span> (str &amp;&amp; (str.twig_markup !== <span class="hljs-literal">true</span> &amp;&amp; str.twig_markup != strategy)) {
+ str = Twig.filters.escape(str, [ strategy ]);
+ }
+ escaped_output.push(str);
+ });
+ <span class="hljs-keyword">return</span> Twig.Markup(escaped_output.join(<span class="hljs-string">""</span>));
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-82">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-82">&#182;</a>
+ </div>
+ <p>Namespace for template storage and retrieval</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.Templates = {
+ <span class="hljs-comment">/**
+ * Registered template loaders - use Twig.Templates.registerLoader to add supported loaders
+ * @type {Object}
+ */</span>
+ loaders: {},
+
+ <span class="hljs-comment">/**
+ * Registered template parsers - use Twig.Templates.registerParser to add supported parsers
+ * @type {Object}
+ */</span>
+ parsers: {},
+
+ <span class="hljs-comment">/**
+ * Cached / loaded templates
+ * @type {Object}
+ */</span>
+ registry: {}
+ };
+
+ <span class="hljs-comment">/**
+ * Is this id valid for a twig template?
+ *
+ * @param {string} id The ID to check.
+ *
+ * @throws {Twig.Error} If the ID is invalid or used.
+ * @return {boolean} True if the ID is valid.
+ */</span>
+ Twig.validateId = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">id</span>) </span>{
+ <span class="hljs-keyword">if</span> (id === <span class="hljs-string">"prototype"</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(id + <span class="hljs-string">" is not a valid twig identifier"</span>);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (Twig.cache &amp;&amp; Twig.Templates.registry.hasOwnProperty(id)) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"There is already a template with the ID "</span> + id);
+ }
+ <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
+ }
+
+ <span class="hljs-comment">/**
+ * Register a template loader
+ *
+ * @example
+ * Twig.extend(function(Twig) {
+ * Twig.Templates.registerLoader('custom_loader', function(location, params, callback, error_callback) {
+ * // ... load the template ...
+ * params.data = loadedTemplateData;
+ * // create and return the template
+ * var template = new Twig.Template(params);
+ * if (typeof callback === 'function') {
+ * callback(template);
+ * }
+ * return template;
+ * });
+ * });
+ *
+ * @param {String} method_name The method this loader is intended for (ajax, fs)
+ * @param {Function} func The function to execute when loading the template
+ * @param {Object|undefined} scope Optional scope parameter to bind func to
+ *
+ * @throws Twig.Error
+ *
+ * @return {void}
+ */</span>
+ Twig.Templates.registerLoader = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">method_name, func, scope</span>) </span>{
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> func !== <span class="hljs-string">'function'</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">'Unable to add loader for '</span> + method_name + <span class="hljs-string">': Invalid function reference given.'</span>);
+ }
+ <span class="hljs-keyword">if</span> (scope) {
+ func = func.bind(scope);
+ }
+ <span class="hljs-keyword">this</span>.loaders[method_name] = func;
+ };
+
+ <span class="hljs-comment">/**
+ * Remove a registered loader
+ *
+ * @param {String} method_name The method name for the loader you wish to remove
+ *
+ * @return {void}
+ */</span>
+ Twig.Templates.unRegisterLoader = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">method_name</span>) </span>{
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.isRegisteredLoader(method_name)) {
+ <span class="hljs-keyword">delete</span> <span class="hljs-keyword">this</span>.loaders[method_name];
+ }
+ };
+
+ <span class="hljs-comment">/**
+ * See if a loader is registered by its method name
+ *
+ * @param {String} method_name The name of the loader you are looking for
+ *
+ * @return {boolean}
+ */</span>
+ Twig.Templates.isRegisteredLoader = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">method_name</span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.loaders.hasOwnProperty(method_name);
+ };
+
+ <span class="hljs-comment">/**
+ * Register a template parser
+ *
+ * @example
+ * Twig.extend(function(Twig) {
+ * Twig.Templates.registerParser('custom_parser', function(params) {
+ * // this template source can be accessed in params.data
+ * var template = params.data
+ *
+ * // ... custom process that modifies the template
+ *
+ * // return the parsed template
+ * return template;
+ * });
+ * });
+ *
+ * @param {String} method_name The method this parser is intended for (twig, source)
+ * @param {Function} func The function to execute when parsing the template
+ * @param {Object|undefined} scope Optional scope parameter to bind func to
+ *
+ * @throws Twig.Error
+ *
+ * @return {void}
+ */</span>
+ Twig.Templates.registerParser = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">method_name, func, scope</span>) </span>{
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> func !== <span class="hljs-string">'function'</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">'Unable to add parser for '</span> + method_name + <span class="hljs-string">': Invalid function regerence given.'</span>);
+ }
+
+ <span class="hljs-keyword">if</span> (scope) {
+ func = func.bind(scope);
+ }
+
+ <span class="hljs-keyword">this</span>.parsers[method_name] = func;
+ };
+
+ <span class="hljs-comment">/**
+ * Remove a registered parser
+ *
+ * @param {String} method_name The method name for the parser you wish to remove
+ *
+ * @return {void}
+ */</span>
+ Twig.Templates.unRegisterParser = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">method_name</span>) </span>{
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.isRegisteredParser(method_name)) {
+ <span class="hljs-keyword">delete</span> <span class="hljs-keyword">this</span>.parsers[method_name];
+ }
+ };
+
+ <span class="hljs-comment">/**
+ * See if a parser is registered by its method name
+ *
+ * @param {String} method_name The name of the parser you are looking for
+ *
+ * @return {boolean}
+ */</span>
+ Twig.Templates.isRegisteredParser = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">method_name</span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.parsers.hasOwnProperty(method_name);
+ };
+
+ <span class="hljs-comment">/**
+ * Save a template object to the store.
+ *
+ * @param {Twig.Template} template The twig.js template to store.
+ */</span>
+ Twig.Templates.save = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">template</span>) </span>{
+ <span class="hljs-keyword">if</span> (template.id === <span class="hljs-literal">undefined</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Unable to save template with no id"</span>);
+ }
+ Twig.Templates.registry[template.id] = template;
+ };
+
+ <span class="hljs-comment">/**
+ * Load a previously saved template from the store.
+ *
+ * @param {string} id The ID of the template to load.
+ *
+ * @return {Twig.Template} A twig.js template stored with the provided ID.
+ */</span>
+ Twig.Templates.load = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">id</span>) </span>{
+ <span class="hljs-keyword">if</span> (!Twig.Templates.registry.hasOwnProperty(id)) {
+ <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
+ }
+ <span class="hljs-keyword">return</span> Twig.Templates.registry[id];
+ };
+
+ <span class="hljs-comment">/**
+ * Load a template from a remote location using AJAX and saves in with the given ID.
+ *
+ * Available parameters:
+ *
+ * async: Should the HTTP request be performed asynchronously.
+ * Defaults to true.
+ * method: What method should be used to load the template
+ * (fs or ajax)
+ * parser: What method should be used to parse the template
+ * (twig or source)
+ * precompiled: Has the template already been compiled.
+ *
+ * @param {string} location The remote URL to load as a template.
+ * @param {Object} params The template parameters.
+ * @param {function} callback A callback triggered when the template finishes loading.
+ * @param {function} error_callback A callback triggered if an error occurs loading the template.
+ *
+ *
+ */</span>
+ Twig.Templates.loadRemote = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">location, params, callback, error_callback</span>) </span>{
+ <span class="hljs-keyword">var</span> loader;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-83">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-83">&#182;</a>
+ </div>
+ <p>Default to async</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (params.async === <span class="hljs-literal">undefined</span>) {
+ params.async = <span class="hljs-literal">true</span>;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-84">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-84">&#182;</a>
+ </div>
+ <p>Default to the URL so the template is cached.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (params.id === <span class="hljs-literal">undefined</span>) {
+ params.id = location;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-85">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-85">&#182;</a>
+ </div>
+ <p>Check for existing template</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (Twig.cache &amp;&amp; Twig.Templates.registry.hasOwnProperty(params.id)) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-86">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-86">&#182;</a>
+ </div>
+ <p>A template is already saved with the given id.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> callback === <span class="hljs-string">'function'</span>) {
+ callback(Twig.Templates.registry[params.id]);
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-87">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-87">&#182;</a>
+ </div>
+ <p>TODO: if async, return deferred promise</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> Twig.Templates.registry[params.id];
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-88">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-88">&#182;</a>
+ </div>
+ <p>if the parser name hasn’t been set, default it to twig</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> params.parser = params.parser || <span class="hljs-string">'twig'</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-89">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-89">&#182;</a>
+ </div>
+ <p>Assume ‘fs’ if the loader is not defined</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> loader = <span class="hljs-keyword">this</span>.loaders[params.method] || <span class="hljs-keyword">this</span>.loaders.fs;
+ <span class="hljs-keyword">return</span> loader.apply(<span class="hljs-keyword">this</span>, <span class="hljs-built_in">arguments</span>);
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-90">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-90">&#182;</a>
+ </div>
+ <p>Determine object type</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">is</span>(<span class="hljs-params">type, obj</span>) </span>{
+ <span class="hljs-keyword">var</span> clas = <span class="hljs-built_in">Object</span>.prototype.toString.call(obj).slice(<span class="hljs-number">8</span>, <span class="hljs-number">-1</span>);
+ <span class="hljs-keyword">return</span> obj !== <span class="hljs-literal">undefined</span> &amp;&amp; obj !== <span class="hljs-literal">null</span> &amp;&amp; clas === type;
+ }
+
+ <span class="hljs-comment">/**
+ * Create a new twig.js template.
+ *
+ * Parameters: {
+ * data: The template, either pre-compiled tokens or a string template
+ * id: The name of this template
+ * blocks: Any pre-existing block from a child template
+ * }
+ *
+ * @param {Object} params The template parameters.
+ */</span>
+ Twig.Template = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"> params </span>) </span>{
+ <span class="hljs-keyword">var</span> data = params.data,
+ id = params.id,
+ blocks = params.blocks,
+ macros = params.macros || {},
+ base = params.base,
+ path = params.path,
+ url = params.url,
+ name = params.name,
+ method = params.method,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-91">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-91">&#182;</a>
+ </div>
+ <p>parser options</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> options = params.options;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-92">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-92">&#182;</a>
+ </div>
+ <h1 id="what-is-stored-in-a-twig-template">What is stored in a Twig.Template</h1>
+<p>The Twig Template hold several chucks of data.</p>
+<pre><code>{
+ id: The token ID (<span class="hljs-keyword">if</span> any)
+ tokens: The list <span class="hljs-keyword">of</span> tokens that makes up <span class="hljs-keyword">this</span> template.
+ blocks: The list <span class="hljs-keyword">of</span> block <span class="hljs-keyword">this</span> template contains.
+ base: The base template (<span class="hljs-keyword">if</span> any)
+ options: {
+ Compiler/parser options
+
+ strict_variables: <span class="hljs-literal">true</span>/<span class="hljs-literal">false</span>
+ Should missing variable/keys emit an error message. If <span class="hljs-literal">false</span>, they <span class="hljs-keyword">default</span> to <span class="hljs-literal">null</span>.
+ }
+}
+</code></pre>
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ <span class="hljs-keyword">this</span>.id = id;
+ <span class="hljs-keyword">this</span>.method = method;
+ <span class="hljs-keyword">this</span>.base = base;
+ <span class="hljs-keyword">this</span>.path = path;
+ <span class="hljs-keyword">this</span>.url = url;
+ <span class="hljs-keyword">this</span>.name = name;
+ <span class="hljs-keyword">this</span>.macros = macros;
+ <span class="hljs-keyword">this</span>.options = options;
+
+ <span class="hljs-keyword">this</span>.reset(blocks);
+
+ <span class="hljs-keyword">if</span> (is(<span class="hljs-string">'String'</span>, data)) {
+ <span class="hljs-keyword">this</span>.tokens = Twig.prepare.apply(<span class="hljs-keyword">this</span>, [data]);
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">this</span>.tokens = data;
+ }
+
+ <span class="hljs-keyword">if</span> (id !== <span class="hljs-literal">undefined</span>) {
+ Twig.Templates.save(<span class="hljs-keyword">this</span>);
+ }
+ };
+
+ Twig.Template.prototype.reset = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">blocks</span>) </span>{
+ Twig.log.debug(<span class="hljs-string">"Twig.Template.reset"</span>, <span class="hljs-string">"Reseting template "</span> + <span class="hljs-keyword">this</span>.id);
+ <span class="hljs-keyword">this</span>.blocks = {};
+ <span class="hljs-keyword">this</span>.importedBlocks = [];
+ <span class="hljs-keyword">this</span>.originalBlockTokens = {};
+ <span class="hljs-keyword">this</span>.child = {
+ blocks: blocks || {}
+ };
+ <span class="hljs-keyword">this</span>.extend = <span class="hljs-literal">null</span>;
+ };
+
+ Twig.Template.prototype.render = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">context, params</span>) </span>{
+ params = params || {};
+
+ <span class="hljs-keyword">var</span> output,
+ url;
+
+ <span class="hljs-keyword">this</span>.context = context || {};</pre></div></div>
+
+ </li>
+
+
+ <li id="section-93">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-93">&#182;</a>
+ </div>
+ <p>Clear any previous state</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">this</span>.reset();
+ <span class="hljs-keyword">if</span> (params.blocks) {
+ <span class="hljs-keyword">this</span>.blocks = params.blocks;
+ }
+ <span class="hljs-keyword">if</span> (params.macros) {
+ <span class="hljs-keyword">this</span>.macros = params.macros;
+ }
+
+ output = Twig.parse.apply(<span class="hljs-keyword">this</span>, [<span class="hljs-keyword">this</span>.tokens, <span class="hljs-keyword">this</span>.context]);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-94">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-94">&#182;</a>
+ </div>
+ <p>Does this template extend another</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.extend) {
+ <span class="hljs-keyword">var</span> ext_template;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-95">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-95">&#182;</a>
+ </div>
+ <p>check if the template is provided inline</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> ( <span class="hljs-keyword">this</span>.options.allowInlineIncludes ) {
+ ext_template = Twig.Templates.load(<span class="hljs-keyword">this</span>.extend);
+ <span class="hljs-keyword">if</span> ( ext_template ) {
+ ext_template.options = <span class="hljs-keyword">this</span>.options;
+ }
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-96">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-96">&#182;</a>
+ </div>
+ <p>check for the template file via include</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (!ext_template) {
+ url = Twig.path.parsePath(<span class="hljs-keyword">this</span>, <span class="hljs-keyword">this</span>.extend);
+
+ ext_template = Twig.Templates.loadRemote(url, {
+ method: <span class="hljs-keyword">this</span>.getLoaderMethod(),
+ base: <span class="hljs-keyword">this</span>.base,
+ <span class="hljs-keyword">async</span>: <span class="hljs-literal">false</span>,
+ id: url,
+ options: <span class="hljs-keyword">this</span>.options
+ });
+ }
+
+ <span class="hljs-keyword">this</span>.parent = ext_template;
+
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.parent.render(<span class="hljs-keyword">this</span>.context, {
+ blocks: <span class="hljs-keyword">this</span>.blocks
+ });
+ }
+
+ <span class="hljs-keyword">if</span> (params.output == <span class="hljs-string">'blocks'</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.blocks;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (params.output == <span class="hljs-string">'macros'</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.macros;
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">return</span> output;
+ }
+ };
+
+ Twig.Template.prototype.importFile = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">file</span>) </span>{
+ <span class="hljs-keyword">var</span> url, sub_template;
+ <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.url &amp;&amp; <span class="hljs-keyword">this</span>.options.allowInlineIncludes) {
+ file = <span class="hljs-keyword">this</span>.path ? <span class="hljs-keyword">this</span>.path + <span class="hljs-string">'/'</span> + file : file;
+ sub_template = Twig.Templates.load(file);
+
+ <span class="hljs-keyword">if</span> (!sub_template) {
+ sub_template = Twig.Templates.loadRemote(url, {
+ id: file,
+ method: <span class="hljs-keyword">this</span>.getLoaderMethod(),
+ <span class="hljs-keyword">async</span>: <span class="hljs-literal">false</span>,
+ options: <span class="hljs-keyword">this</span>.options
+ });
+
+ <span class="hljs-keyword">if</span> (!sub_template) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Unable to find the template "</span> + file);
+ }
+ }
+
+ sub_template.options = <span class="hljs-keyword">this</span>.options;
+
+ <span class="hljs-keyword">return</span> sub_template;
+ }
+
+ url = Twig.path.parsePath(<span class="hljs-keyword">this</span>, file);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-97">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-97">&#182;</a>
+ </div>
+ <p>Load blocks from an external file</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> sub_template = Twig.Templates.loadRemote(url, {
+ method: <span class="hljs-keyword">this</span>.getLoaderMethod(),
+ base: <span class="hljs-keyword">this</span>.base,
+ <span class="hljs-keyword">async</span>: <span class="hljs-literal">false</span>,
+ options: <span class="hljs-keyword">this</span>.options,
+ id: url
+ });
+
+ <span class="hljs-keyword">return</span> sub_template;
+ };
+
+ Twig.Template.prototype.importBlocks = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">file, override</span>) </span>{
+ <span class="hljs-keyword">var</span> sub_template = <span class="hljs-keyword">this</span>.importFile(file),
+ context = <span class="hljs-keyword">this</span>.context,
+ that = <span class="hljs-keyword">this</span>,
+ key;
+
+ override = override || <span class="hljs-literal">false</span>;
+
+ sub_template.render(context);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-98">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-98">&#182;</a>
+ </div>
+ <p>Mixin blocks</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.forEach(<span class="hljs-built_in">Object</span>.keys(sub_template.blocks), <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">key</span>) </span>{
+ <span class="hljs-keyword">if</span> (override || that.blocks[key] === <span class="hljs-literal">undefined</span>) {
+ that.blocks[key] = sub_template.blocks[key];
+ that.importedBlocks.push(key);
+ }
+ });
+ };
+
+ Twig.Template.prototype.importMacros = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">file</span>) </span>{
+ <span class="hljs-keyword">var</span> url = Twig.path.parsePath(<span class="hljs-keyword">this</span>, file);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-99">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-99">&#182;</a>
+ </div>
+ <p>load remote template</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> remoteTemplate = Twig.Templates.loadRemote(url, {
+ method: <span class="hljs-keyword">this</span>.getLoaderMethod(),
+ <span class="hljs-keyword">async</span>: <span class="hljs-literal">false</span>,
+ id: url
+ });
+
+ <span class="hljs-keyword">return</span> remoteTemplate;
+ };
+
+ Twig.Template.prototype.getLoaderMethod = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.path) {
+ <span class="hljs-keyword">return</span> <span class="hljs-string">'fs'</span>;
+ }
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.url) {
+ <span class="hljs-keyword">return</span> <span class="hljs-string">'ajax'</span>;
+ }
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.method || <span class="hljs-string">'fs'</span>;
+ };
+
+ Twig.Template.prototype.compile = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">options</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-100">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-100">&#182;</a>
+ </div>
+ <p>compile the template into raw JS</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> Twig.compiler.compile(<span class="hljs-keyword">this</span>, options);
+ };
+
+ <span class="hljs-comment">/**
+ * Create safe output
+ *
+ * @param {string} Content safe to output
+ *
+ * @return {String} Content wrapped into a String
+ */</span>
+
+ Twig.Markup = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">content, strategy</span>) </span>{
+ <span class="hljs-keyword">if</span>(<span class="hljs-keyword">typeof</span> strategy == <span class="hljs-string">'undefined'</span>) {
+ strategy = <span class="hljs-literal">true</span>;
+ }
+
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> content === <span class="hljs-string">'string'</span> &amp;&amp; content.length &gt; <span class="hljs-number">0</span>) {
+ content = <span class="hljs-keyword">new</span> <span class="hljs-built_in">String</span>(content);
+ content.twig_markup = strategy;
+ }
+ <span class="hljs-keyword">return</span> content;
+ };
+
+ <span class="hljs-keyword">return</span> Twig;
+
+}) (Twig || { });
+
+(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">Twig</span>) </span>{
+<span class="hljs-meta">
+ 'use strict'</span>;
+
+ Twig.Templates.registerLoader(<span class="hljs-string">'ajax'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">location, params, callback, error_callback</span>) </span>{
+ <span class="hljs-keyword">var</span> template,
+ xmlhttp,
+ precompiled = params.precompiled,
+ parser = <span class="hljs-keyword">this</span>.parsers[params.parser] || <span class="hljs-keyword">this</span>.parser.twig;
+
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> XMLHttpRequest === <span class="hljs-string">"undefined"</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">'Unsupported platform: Unable to do ajax requests '</span> +
+ <span class="hljs-string">'because there is no "XMLHTTPRequest" implementation'</span>);
+ }
+
+ xmlhttp = <span class="hljs-keyword">new</span> XMLHttpRequest();
+ xmlhttp.onreadystatechange = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
+ <span class="hljs-keyword">var</span> data = <span class="hljs-literal">null</span>;
+
+ <span class="hljs-keyword">if</span>(xmlhttp.readyState === <span class="hljs-number">4</span>) {
+ <span class="hljs-keyword">if</span> (xmlhttp.status === <span class="hljs-number">200</span> || (<span class="hljs-built_in">window</span>.cordova &amp;&amp; xmlhttp.status == <span class="hljs-number">0</span>)) {
+ Twig.log.debug(<span class="hljs-string">"Got template "</span>, xmlhttp.responseText);
+
+ <span class="hljs-keyword">if</span> (precompiled === <span class="hljs-literal">true</span>) {
+ data = <span class="hljs-built_in">JSON</span>.parse(xmlhttp.responseText);
+ } <span class="hljs-keyword">else</span> {
+ data = xmlhttp.responseText;
+ }
+
+ params.url = location;
+ params.data = data;
+
+ template = parser.call(<span class="hljs-keyword">this</span>, params);
+
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> callback === <span class="hljs-string">'function'</span>) {
+ callback(template);
+ }
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> error_callback === <span class="hljs-string">'function'</span>) {
+ error_callback(xmlhttp);
+ }
+ }
+ }
+ };
+ xmlhttp.open(<span class="hljs-string">"GET"</span>, location, !!params.async);
+ xmlhttp.send();
+
+ <span class="hljs-keyword">if</span> (params.async) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-101">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-101">&#182;</a>
+ </div>
+ <p>TODO: return deferred promise</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">return</span> template;
+ }
+ });
+
+}(Twig));(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">Twig</span>) </span>{
+<span class="hljs-meta"> 'use strict'</span>;
+
+ <span class="hljs-keyword">var</span> fs, path;
+
+ <span class="hljs-keyword">try</span> {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-102">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-102">&#182;</a>
+ </div>
+ <p>require lib dependencies at runtime</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);
+ path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>);
+ } <span class="hljs-keyword">catch</span> (e) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-103">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-103">&#182;</a>
+ </div>
+ <p>NOTE: this is in a try/catch to avoid errors cross platform</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> }
+
+ Twig.Templates.registerLoader(<span class="hljs-string">'fs'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">location, params, callback, error_callback</span>) </span>{
+ <span class="hljs-keyword">var</span> template,
+ data = <span class="hljs-literal">null</span>,
+ precompiled = params.precompiled,
+ parser = <span class="hljs-keyword">this</span>.parsers[params.parser] || <span class="hljs-keyword">this</span>.parser.twig;
+
+ <span class="hljs-keyword">if</span> (!fs || !path) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">'Unsupported platform: Unable to load from file '</span> +
+ <span class="hljs-string">'because there is no "fs" or "path" implementation'</span>);
+ }
+
+ <span class="hljs-keyword">var</span> loadTemplateFn = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">err, data</span>) </span>{
+ <span class="hljs-keyword">if</span> (err) {
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> error_callback === <span class="hljs-string">'function'</span>) {
+ error_callback(err);
+ }
+ <span class="hljs-keyword">return</span>;
+ }
+
+ <span class="hljs-keyword">if</span> (precompiled === <span class="hljs-literal">true</span>) {
+ data = <span class="hljs-built_in">JSON</span>.parse(data);
+ }
+
+ params.data = data;
+ params.path = params.path || location;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-104">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-104">&#182;</a>
+ </div>
+ <p>template is in data</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> template = parser.call(<span class="hljs-keyword">this</span>, params);
+
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> callback === <span class="hljs-string">'function'</span>) {
+ callback(template);
+ }
+ };
+ params.path = params.path || location;
+
+ <span class="hljs-keyword">if</span> (params.async) {
+ fs.stat(params.path, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err, stats</span>) </span>{
+ <span class="hljs-keyword">if</span> (err || !stats.isFile()) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">'Unable to find template file '</span> + location);
+ }
+ fs.readFile(params.path, <span class="hljs-string">'utf8'</span>, loadTemplateFn);
+ });</pre></div></div>
+
+ </li>
+
+
+ <li id="section-105">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-105">&#182;</a>
+ </div>
+ <p>TODO: return deferred promise</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">if</span> (!fs.statSync(params.path).isFile()) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">'Unable to find template file '</span> + location);
+ }
+ data = fs.readFileSync(params.path, <span class="hljs-string">'utf8'</span>);
+ loadTemplateFn(<span class="hljs-literal">undefined</span>, data);
+ <span class="hljs-keyword">return</span> template
+ }
+ });
+
+}(Twig));(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">Twig</span>)</span>{
+<span class="hljs-meta"> 'use strict'</span>;
+
+ Twig.Templates.registerParser(<span class="hljs-string">'source'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">params</span>) </span>{
+ <span class="hljs-keyword">return</span> params.data || <span class="hljs-string">''</span>;
+ });
+})(Twig);
+(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">Twig</span>)</span>{
+<span class="hljs-meta"> 'use strict'</span>;
+
+ Twig.Templates.registerParser(<span class="hljs-string">'twig'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">params</span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Twig.Template(params);
+ });
+})(Twig);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-106">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-106">&#182;</a>
+ </div>
+ <p>The following methods are from MDN and are available under a
+<a href="http://www.opensource.org/licenses/mit-license.php">MIT License</a> or are
+<a href="https://developer.mozilla.org/Project:Copyrights">Public Domain</a>.</p>
+<p>See:</p>
+<ul>
+<li><a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys">Object.keys - MDN</a></li>
+</ul>
+
+ </div>
+
+ </li>
+
+
+ <li id="section-107">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-107">&#182;</a>
+ </div>
+ <h2 id="twig-fills-js">twig.fills.js</h2>
+<p>This file contains fills for backwards compatability.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
+<span class="hljs-meta"> "use strict"</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-108">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-108">&#182;</a>
+ </div>
+ <p>Handle methods that don’t yet exist in every browser</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">String</span>.prototype.trim) {
+ <span class="hljs-built_in">String</span>.prototype.trim = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.replace(<span class="hljs-regexp">/^\s+|\s+$/g</span>,<span class="hljs-string">''</span>);
+ }
+ };
+
+ <span class="hljs-keyword">if</span>(!<span class="hljs-built_in">Object</span>.keys) <span class="hljs-built_in">Object</span>.keys = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">o</span>)</span>{
+ <span class="hljs-keyword">if</span> (o !== <span class="hljs-built_in">Object</span>(o)) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>(<span class="hljs-string">'Object.keys called on non-object'</span>);
+ }
+ <span class="hljs-keyword">var</span> ret = [], p;
+ <span class="hljs-keyword">for</span> (p <span class="hljs-keyword">in</span> o) <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Object</span>.prototype.hasOwnProperty.call(o, p)) ret.push(p);
+ <span class="hljs-keyword">return</span> ret;
+ }
+
+})();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-109">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-109">&#182;</a>
+ </div>
+ <h2 id="twig-lib-js">twig.lib.js</h2>
+<p>This file contains 3rd party libraries used within twig.</p>
+<p>Copies of the licenses for the code included here can be found in the
+LICENSES.md file.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+<span class="hljs-keyword">var</span> Twig = (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">Twig</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-110">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-110">&#182;</a>
+ </div>
+ <p>Namespace for libraries</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.lib = { };
+
+ <span class="hljs-comment">/**
+ sprintf() for JavaScript 1.0.3
+ https://github.com/alexei/sprintf.js
+ **/</span>
+ <span class="hljs-keyword">var</span> sprintfLib = (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
+ <span class="hljs-keyword">var</span> re = {
+ not_string: <span class="hljs-regexp">/[^s]/</span>,
+ number: <span class="hljs-regexp">/[diefg]/</span>,
+ json: <span class="hljs-regexp">/[j]/</span>,
+ not_json: <span class="hljs-regexp">/[^j]/</span>,
+ text: <span class="hljs-regexp">/^[^\x25]+/</span>,
+ modulo: <span class="hljs-regexp">/^\x25{2}/</span>,
+ placeholder: <span class="hljs-regexp">/^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-gijosuxX])/</span>,
+ key: <span class="hljs-regexp">/^([a-z_][a-z_\d]*)/i</span>,
+ key_access: <span class="hljs-regexp">/^\.([a-z_][a-z_\d]*)/i</span>,
+ index_access: <span class="hljs-regexp">/^\[(\d+)\]/</span>,
+ sign: <span class="hljs-regexp">/^[\+\-]/</span>
+ }
+
+ <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sprintf</span>(<span class="hljs-params"></span>) </span>{
+ <span class="hljs-keyword">var</span> key = <span class="hljs-built_in">arguments</span>[<span class="hljs-number">0</span>], cache = sprintf.cache
+ <span class="hljs-keyword">if</span> (!(cache[key] &amp;&amp; cache.hasOwnProperty(key))) {
+ cache[key] = sprintf.parse(key)
+ }
+ <span class="hljs-keyword">return</span> sprintf.format.call(<span class="hljs-literal">null</span>, cache[key], <span class="hljs-built_in">arguments</span>)
+ }
+
+ sprintf.format = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">parse_tree, argv</span>) </span>{
+ <span class="hljs-keyword">var</span> cursor = <span class="hljs-number">1</span>, tree_length = parse_tree.length, node_type = <span class="hljs-string">""</span>, arg, output = [], i, k, match, pad, pad_character, pad_length, is_positive = <span class="hljs-literal">true</span>, sign = <span class="hljs-string">""</span>
+ <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; tree_length; i++) {
+ node_type = get_type(parse_tree[i])
+ <span class="hljs-keyword">if</span> (node_type === <span class="hljs-string">"string"</span>) {
+ output[output.length] = parse_tree[i]
+ }
+ <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (node_type === <span class="hljs-string">"array"</span>) {
+ match = parse_tree[i] <span class="hljs-comment">// convenience purposes only</span>
+ <span class="hljs-keyword">if</span> (match[<span class="hljs-number">2</span>]) { <span class="hljs-comment">// keyword argument</span>
+ arg = argv[cursor]
+ <span class="hljs-keyword">for</span> (k = <span class="hljs-number">0</span>; k &lt; match[<span class="hljs-number">2</span>].length; k++) {
+ <span class="hljs-keyword">if</span> (!arg.hasOwnProperty(match[<span class="hljs-number">2</span>][k])) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(sprintf(<span class="hljs-string">"[sprintf] property '%s' does not exist"</span>, match[<span class="hljs-number">2</span>][k]))
+ }
+ arg = arg[match[<span class="hljs-number">2</span>][k]]
+ }
+ }
+ <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">1</span>]) { <span class="hljs-comment">// positional argument (explicit)</span>
+ arg = argv[match[<span class="hljs-number">1</span>]]
+ }
+ <span class="hljs-keyword">else</span> { <span class="hljs-comment">// positional argument (implicit)</span>
+ arg = argv[cursor++]
+ }
+
+ <span class="hljs-keyword">if</span> (get_type(arg) == <span class="hljs-string">"function"</span>) {
+ arg = arg()
+ }
+
+ <span class="hljs-keyword">if</span> (re.not_string.test(match[<span class="hljs-number">8</span>]) &amp;&amp; re.not_json.test(match[<span class="hljs-number">8</span>]) &amp;&amp; (get_type(arg) != <span class="hljs-string">"number"</span> &amp;&amp; <span class="hljs-built_in">isNaN</span>(arg))) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>(sprintf(<span class="hljs-string">"[sprintf] expecting number but found %s"</span>, get_type(arg)))
+ }
+
+ <span class="hljs-keyword">if</span> (re.number.test(match[<span class="hljs-number">8</span>])) {
+ is_positive = arg &gt;= <span class="hljs-number">0</span>
+ }
+
+ <span class="hljs-keyword">switch</span> (match[<span class="hljs-number">8</span>]) {
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"b"</span>:
+ arg = arg.toString(<span class="hljs-number">2</span>)
+ <span class="hljs-keyword">break</span>
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"c"</span>:
+ arg = <span class="hljs-built_in">String</span>.fromCharCode(arg)
+ <span class="hljs-keyword">break</span>
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"d"</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"i"</span>:
+ arg = <span class="hljs-built_in">parseInt</span>(arg, <span class="hljs-number">10</span>)
+ <span class="hljs-keyword">break</span>
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"j"</span>:
+ arg = <span class="hljs-built_in">JSON</span>.stringify(arg, <span class="hljs-literal">null</span>, match[<span class="hljs-number">6</span>] ? <span class="hljs-built_in">parseInt</span>(match[<span class="hljs-number">6</span>]) : <span class="hljs-number">0</span>)
+ <span class="hljs-keyword">break</span>
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"e"</span>:
+ arg = match[<span class="hljs-number">7</span>] ? arg.toExponential(match[<span class="hljs-number">7</span>]) : arg.toExponential()
+ <span class="hljs-keyword">break</span>
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"f"</span>:
+ arg = match[<span class="hljs-number">7</span>] ? <span class="hljs-built_in">parseFloat</span>(arg).toFixed(match[<span class="hljs-number">7</span>]) : <span class="hljs-built_in">parseFloat</span>(arg)
+ <span class="hljs-keyword">break</span>
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"g"</span>:
+ arg = match[<span class="hljs-number">7</span>] ? <span class="hljs-built_in">parseFloat</span>(arg).toPrecision(match[<span class="hljs-number">7</span>]) : <span class="hljs-built_in">parseFloat</span>(arg)
+ <span class="hljs-keyword">break</span>
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"o"</span>:
+ arg = arg.toString(<span class="hljs-number">8</span>)
+ <span class="hljs-keyword">break</span>
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"s"</span>:
+ arg = ((arg = <span class="hljs-built_in">String</span>(arg)) &amp;&amp; match[<span class="hljs-number">7</span>] ? arg.substring(<span class="hljs-number">0</span>, match[<span class="hljs-number">7</span>]) : arg)
+ <span class="hljs-keyword">break</span>
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"u"</span>:
+ arg = arg &gt;&gt;&gt; <span class="hljs-number">0</span>
+ <span class="hljs-keyword">break</span>
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"x"</span>:
+ arg = arg.toString(<span class="hljs-number">16</span>)
+ <span class="hljs-keyword">break</span>
+ <span class="hljs-keyword">case</span> <span class="hljs-string">"X"</span>:
+ arg = arg.toString(<span class="hljs-number">16</span>).toUpperCase()
+ <span class="hljs-keyword">break</span>
+ }
+ <span class="hljs-keyword">if</span> (re.json.test(match[<span class="hljs-number">8</span>])) {
+ output[output.length] = arg
+ }
+ <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">if</span> (re.number.test(match[<span class="hljs-number">8</span>]) &amp;&amp; (!is_positive || match[<span class="hljs-number">3</span>])) {
+ sign = is_positive ? <span class="hljs-string">"+"</span> : <span class="hljs-string">"-"</span>
+ arg = arg.toString().replace(re.sign, <span class="hljs-string">""</span>)
+ }
+ <span class="hljs-keyword">else</span> {
+ sign = <span class="hljs-string">""</span>
+ }
+ pad_character = match[<span class="hljs-number">4</span>] ? match[<span class="hljs-number">4</span>] === <span class="hljs-string">"0"</span> ? <span class="hljs-string">"0"</span> : match[<span class="hljs-number">4</span>].charAt(<span class="hljs-number">1</span>) : <span class="hljs-string">" "</span>
+ pad_length = match[<span class="hljs-number">6</span>] - (sign + arg).length
+ pad = match[<span class="hljs-number">6</span>] ? (pad_length &gt; <span class="hljs-number">0</span> ? str_repeat(pad_character, pad_length) : <span class="hljs-string">""</span>) : <span class="hljs-string">""</span>
+ output[output.length] = match[<span class="hljs-number">5</span>] ? sign + arg + pad : (pad_character === <span class="hljs-string">"0"</span> ? sign + pad + arg : pad + sign + arg)
+ }
+ }
+ }
+ <span class="hljs-keyword">return</span> output.join(<span class="hljs-string">""</span>)
+ }
+
+ sprintf.cache = {}
+
+ sprintf.parse = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">fmt</span>) </span>{
+ <span class="hljs-keyword">var</span> _fmt = fmt, match = [], parse_tree = [], arg_names = <span class="hljs-number">0</span>
+ <span class="hljs-keyword">while</span> (_fmt) {
+ <span class="hljs-keyword">if</span> ((match = re.text.exec(_fmt)) !== <span class="hljs-literal">null</span>) {
+ parse_tree[parse_tree.length] = match[<span class="hljs-number">0</span>]
+ }
+ <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ((match = re.modulo.exec(_fmt)) !== <span class="hljs-literal">null</span>) {
+ parse_tree[parse_tree.length] = <span class="hljs-string">"%"</span>
+ }
+ <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ((match = re.placeholder.exec(_fmt)) !== <span class="hljs-literal">null</span>) {
+ <span class="hljs-keyword">if</span> (match[<span class="hljs-number">2</span>]) {
+ arg_names |= <span class="hljs-number">1</span>
+ <span class="hljs-keyword">var</span> field_list = [], replacement_field = match[<span class="hljs-number">2</span>], field_match = []
+ <span class="hljs-keyword">if</span> ((field_match = re.key.exec(replacement_field)) !== <span class="hljs-literal">null</span>) {
+ field_list[field_list.length] = field_match[<span class="hljs-number">1</span>]
+ <span class="hljs-keyword">while</span> ((replacement_field = replacement_field.substring(field_match[<span class="hljs-number">0</span>].length)) !== <span class="hljs-string">""</span>) {
+ <span class="hljs-keyword">if</span> ((field_match = re.key_access.exec(replacement_field)) !== <span class="hljs-literal">null</span>) {
+ field_list[field_list.length] = field_match[<span class="hljs-number">1</span>]
+ }
+ <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ((field_match = re.index_access.exec(replacement_field)) !== <span class="hljs-literal">null</span>) {
+ field_list[field_list.length] = field_match[<span class="hljs-number">1</span>]
+ }
+ <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">SyntaxError</span>(<span class="hljs-string">"[sprintf] failed to parse named argument key"</span>)
+ }
+ }
+ }
+ <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">SyntaxError</span>(<span class="hljs-string">"[sprintf] failed to parse named argument key"</span>)
+ }
+ match[<span class="hljs-number">2</span>] = field_list
+ }
+ <span class="hljs-keyword">else</span> {
+ arg_names |= <span class="hljs-number">2</span>
+ }
+ <span class="hljs-keyword">if</span> (arg_names === <span class="hljs-number">3</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"[sprintf] mixing positional and named placeholders is not (yet) supported"</span>)
+ }
+ parse_tree[parse_tree.length] = match
+ }
+ <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">SyntaxError</span>(<span class="hljs-string">"[sprintf] unexpected placeholder"</span>)
+ }
+ _fmt = _fmt.substring(match[<span class="hljs-number">0</span>].length)
+ }
+ <span class="hljs-keyword">return</span> parse_tree
+ }
+
+ <span class="hljs-keyword">var</span> vsprintf = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">fmt, argv, _argv</span>) </span>{
+ _argv = (argv || []).slice(<span class="hljs-number">0</span>)
+ _argv.splice(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, fmt)
+ <span class="hljs-keyword">return</span> sprintf.apply(<span class="hljs-literal">null</span>, _argv)
+ }
+
+ <span class="hljs-comment">/**
+ * helpers
+ */</span>
+ <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">get_type</span>(<span class="hljs-params">variable</span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-built_in">Object</span>.prototype.toString.call(variable).slice(<span class="hljs-number">8</span>, <span class="hljs-number">-1</span>).toLowerCase()
+ }
+
+ <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">str_repeat</span>(<span class="hljs-params">input, multiplier</span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-built_in">Array</span>(multiplier + <span class="hljs-number">1</span>).join(input)
+ }
+
+ <span class="hljs-comment">/**
+ * export
+ */</span>
+ <span class="hljs-keyword">return</span> {
+ sprintf: sprintf,
+ vsprintf: vsprintf
+ }
+ })();
+
+ <span class="hljs-keyword">var</span> sprintf = sprintfLib.sprintf;
+ <span class="hljs-keyword">var</span> vsprintf = sprintfLib.vsprintf;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-111">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-111">&#182;</a>
+ </div>
+ <p>Expose to Twig</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.lib.sprintf = sprintf;
+ Twig.lib.vsprintf = vsprintf;
+
+
+ <span class="hljs-comment">/**
+ * jPaq - A fully customizable JavaScript/JScript library
+ * http://jpaq.org/
+ *
+ * Copyright (c) 2011 Christopher West
+ * Licensed under the MIT license.
+ * http://jpaq.org/license/
+ *
+ * Version: 1.0.6.0000W
+ * Revised: April 6, 2011
+ */</span>
+ ; (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
+ <span class="hljs-keyword">var</span> shortDays = <span class="hljs-string">"Sun,Mon,Tue,Wed,Thu,Fri,Sat"</span>.split(<span class="hljs-string">","</span>);
+ <span class="hljs-keyword">var</span> fullDays = <span class="hljs-string">"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday"</span>.split(<span class="hljs-string">","</span>);
+ <span class="hljs-keyword">var</span> shortMonths = <span class="hljs-string">"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec"</span>.split(<span class="hljs-string">","</span>);
+ <span class="hljs-keyword">var</span> fullMonths = <span class="hljs-string">"January,February,March,April,May,June,July,August,September,October,November,December"</span>.split(<span class="hljs-string">","</span>);
+ <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrdinalFor</span>(<span class="hljs-params">intNum</span>) </span>{
+ <span class="hljs-keyword">return</span> (((intNum = <span class="hljs-built_in">Math</span>.abs(intNum) % <span class="hljs-number">100</span>) % <span class="hljs-number">10</span> == <span class="hljs-number">1</span> &amp;&amp; intNum != <span class="hljs-number">11</span>) ? <span class="hljs-string">"st"</span>
+ : (intNum % <span class="hljs-number">10</span> == <span class="hljs-number">2</span> &amp;&amp; intNum != <span class="hljs-number">12</span>) ? <span class="hljs-string">"nd"</span> : (intNum % <span class="hljs-number">10</span> == <span class="hljs-number">3</span>
+ &amp;&amp; intNum != <span class="hljs-number">13</span>) ? <span class="hljs-string">"rd"</span> : <span class="hljs-string">"th"</span>);
+ }
+ <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getISO8601Year</span>(<span class="hljs-params">aDate</span>) </span>{
+ <span class="hljs-keyword">var</span> d = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(aDate.getFullYear() + <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">4</span>);
+ <span class="hljs-keyword">if</span>((d - aDate) / <span class="hljs-number">86400000</span> &lt; <span class="hljs-number">7</span> &amp;&amp; (aDate.getDay() + <span class="hljs-number">6</span>) % <span class="hljs-number">7</span> &lt; (d.getDay() + <span class="hljs-number">6</span>) % <span class="hljs-number">7</span>)
+ <span class="hljs-keyword">return</span> d.getFullYear();
+ <span class="hljs-keyword">if</span>(aDate.getMonth() &gt; <span class="hljs-number">0</span> || aDate.getDate() &gt;= <span class="hljs-number">4</span>)
+ <span class="hljs-keyword">return</span> aDate.getFullYear();
+ <span class="hljs-keyword">return</span> aDate.getFullYear() - (((aDate.getDay() + <span class="hljs-number">6</span>) % <span class="hljs-number">7</span> - aDate.getDate() &gt; <span class="hljs-number">2</span>) ? <span class="hljs-number">1</span> : <span class="hljs-number">0</span>);
+ }
+ <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getISO8601Week</span>(<span class="hljs-params">aDate</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-112">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-112">&#182;</a>
+ </div>
+ <p>Get a day during the first week of the year.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> d = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(getISO8601Year(aDate), <span class="hljs-number">0</span>, <span class="hljs-number">4</span>);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-113">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-113">&#182;</a>
+ </div>
+ <p>Get the first monday of the year.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> d.setDate(d.getDate() - (d.getDay() + <span class="hljs-number">6</span>) % <span class="hljs-number">7</span>);
+ <span class="hljs-keyword">return</span> <span class="hljs-built_in">parseInt</span>((aDate - d) / <span class="hljs-number">604800000</span>) + <span class="hljs-number">1</span>;
+ }
+ Twig.lib.formatDate = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">date, format</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-114">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-114">&#182;</a>
+ </div>
+ <p>/ <summary>
+/ Gets a string for this date, formatted according to the given format
+/ string.
+/ </summary>
+/ <param name="format" type="String">
+/ The format of the output date string. The format string works in a
+/ nearly identical way to the PHP date function which is highlighted here:
+/ <a href="http://php.net/manual/en/function.date.php">http://php.net/manual/en/function.date.php</a>.
+/ The only difference is the fact that “u” signifies milliseconds
+/ instead of microseconds. The following characters are recognized in
+/ the format parameter string:
+/ d - Day of the month, 2 digits with leading zeros
+/ D - A textual representation of a day, three letters
+/ j - Day of the month without leading zeros
+/ l (lowercase ‘L’) - A full textual representation of the day of the week
+/ N - ISO-8601 numeric representation of the day of the week (starting from 1)
+/ S - English ordinal suffix for the day of the month, 2 characters st,
+/ nd, rd or th. Works well with j.
+/ w - Numeric representation of the day of the week (starting from 0)
+/ z - The day of the year (starting from 0)
+/ W - ISO-8601 week number of year, weeks starting on Monday
+/ F - A full textual representation of a month, such as January or March
+/ m - Numeric representation of a month, with leading zeros
+/ M - A short textual representation of a month, three letters
+/ n - Numeric representation of a month, without leading zeros
+/ t - Number of days in the given month
+/ L - Whether it’s a leap year
+/ o - ISO-8601 year number. This has the same value as Y, except that if
+/ the ISO week number (W) belongs to the previous or next year, that
+/ year is used instead.
+/ Y - A full numeric representation of a year, 4 digits
+/ y - A two digit representation of a year
+/ a - Lowercase Ante meridiem and Post meridiem
+/ A - Uppercase Ante meridiem and Post meridiem
+/ B - Swatch Internet time
+/ g - 12-hour format of an hour without leading zeros
+/ G - 24-hour format of an hour without leading zeros
+/ h - 12-hour format of an hour with leading zeros
+/ H - 24-hour format of an hour with leading zeros
+/ i - Minutes with leading zeros
+/ s - Seconds, with leading zeros
+/ u - Milliseconds
+/ U - Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
+/ </param>
+/ <returns type="String">
+/ Returns the string for this date, formatted according to the given
+/ format string.
+/ </returns>
+If the format was not passed, use the default toString method.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span>(<span class="hljs-keyword">typeof</span> format !== <span class="hljs-string">"string"</span> || <span class="hljs-regexp">/^\s*$/</span>.test(format))
+ <span class="hljs-keyword">return</span> date + <span class="hljs-string">""</span>;
+ <span class="hljs-keyword">var</span> jan1st = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(date.getFullYear(), <span class="hljs-number">0</span>, <span class="hljs-number">1</span>);
+ <span class="hljs-keyword">var</span> me = date;
+ <span class="hljs-keyword">return</span> format.replace(<span class="hljs-regexp">/[dDjlNSwzWFmMntLoYyaABgGhHisuU]/g</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">option</span>) </span>{
+ <span class="hljs-keyword">switch</span>(option) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-115">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-115">&#182;</a>
+ </div>
+ <p>Day of the month, 2 digits with leading zeros</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"d"</span>: <span class="hljs-keyword">return</span> (<span class="hljs-string">"0"</span> + me.getDate()).replace(<span class="hljs-regexp">/^.+(..)$/</span>, <span class="hljs-string">"$1"</span>);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-116">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-116">&#182;</a>
+ </div>
+ <p>A textual representation of a day, three letters</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"D"</span>: <span class="hljs-keyword">return</span> shortDays[me.getDay()];</pre></div></div>
+
+ </li>
+
+
+ <li id="section-117">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-117">&#182;</a>
+ </div>
+ <p>Day of the month without leading zeros</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"j"</span>: <span class="hljs-keyword">return</span> me.getDate();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-118">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-118">&#182;</a>
+ </div>
+ <p>A full textual representation of the day of the week</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"l"</span>: <span class="hljs-keyword">return</span> fullDays[me.getDay()];</pre></div></div>
+
+ </li>
+
+
+ <li id="section-119">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-119">&#182;</a>
+ </div>
+ <p>ISO-8601 numeric representation of the day of the week</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"N"</span>: <span class="hljs-keyword">return</span> (me.getDay() + <span class="hljs-number">6</span>) % <span class="hljs-number">7</span> + <span class="hljs-number">1</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-120">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-120">&#182;</a>
+ </div>
+ <p>English ordinal suffix for the day of the month, 2 characters</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"S"</span>: <span class="hljs-keyword">return</span> getOrdinalFor(me.getDate());</pre></div></div>
+
+ </li>
+
+
+ <li id="section-121">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-121">&#182;</a>
+ </div>
+ <p>Numeric representation of the day of the week</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"w"</span>: <span class="hljs-keyword">return</span> me.getDay();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-122">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-122">&#182;</a>
+ </div>
+ <p>The day of the year (starting from 0)</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"z"</span>: <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.ceil((jan1st - me) / <span class="hljs-number">86400000</span>);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-123">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-123">&#182;</a>
+ </div>
+ <p>ISO-8601 week number of year, weeks starting on Monday</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"W"</span>: <span class="hljs-keyword">return</span> (<span class="hljs-string">"0"</span> + getISO8601Week(me)).replace(<span class="hljs-regexp">/^.(..)$/</span>, <span class="hljs-string">"$1"</span>);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-124">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-124">&#182;</a>
+ </div>
+ <p>A full textual representation of a month, such as January or March</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"F"</span>: <span class="hljs-keyword">return</span> fullMonths[me.getMonth()];</pre></div></div>
+
+ </li>
+
+
+ <li id="section-125">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-125">&#182;</a>
+ </div>
+ <p>Numeric representation of a month, with leading zeros</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"m"</span>: <span class="hljs-keyword">return</span> (<span class="hljs-string">"0"</span> + (me.getMonth() + <span class="hljs-number">1</span>)).replace(<span class="hljs-regexp">/^.+(..)$/</span>, <span class="hljs-string">"$1"</span>);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-126">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-126">&#182;</a>
+ </div>
+ <p>A short textual representation of a month, three letters</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"M"</span>: <span class="hljs-keyword">return</span> shortMonths[me.getMonth()];</pre></div></div>
+
+ </li>
+
+
+ <li id="section-127">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-127">&#182;</a>
+ </div>
+ <p>Numeric representation of a month, without leading zeros</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"n"</span>: <span class="hljs-keyword">return</span> me.getMonth() + <span class="hljs-number">1</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-128">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-128">&#182;</a>
+ </div>
+ <p>Number of days in the given month</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"t"</span>: <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(me.getFullYear(), me.getMonth() + <span class="hljs-number">1</span>, <span class="hljs-number">-1</span>).getDate();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-129">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-129">&#182;</a>
+ </div>
+ <p>Whether it’s a leap year</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"L"</span>: <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(me.getFullYear(), <span class="hljs-number">1</span>, <span class="hljs-number">29</span>).getDate() == <span class="hljs-number">29</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">0</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-130">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-130">&#182;</a>
+ </div>
+ <p>ISO-8601 year number. This has the same value as Y, except that if the
+ISO week number (W) belongs to the previous or next year, that year is
+used instead.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"o"</span>: <span class="hljs-keyword">return</span> getISO8601Year(me);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-131">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-131">&#182;</a>
+ </div>
+ <p>A full numeric representation of a year, 4 digits</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"Y"</span>: <span class="hljs-keyword">return</span> me.getFullYear();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-132">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-132">&#182;</a>
+ </div>
+ <p>A two digit representation of a year</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"y"</span>: <span class="hljs-keyword">return</span> (me.getFullYear() + <span class="hljs-string">""</span>).replace(<span class="hljs-regexp">/^.+(..)$/</span>, <span class="hljs-string">"$1"</span>);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-133">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-133">&#182;</a>
+ </div>
+ <p>Lowercase Ante meridiem and Post meridiem</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"a"</span>: <span class="hljs-keyword">return</span> me.getHours() &lt; <span class="hljs-number">12</span> ? <span class="hljs-string">"am"</span> : <span class="hljs-string">"pm"</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-134">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-134">&#182;</a>
+ </div>
+ <p>Uppercase Ante meridiem and Post meridiem</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"A"</span>: <span class="hljs-keyword">return</span> me.getHours() &lt; <span class="hljs-number">12</span> ? <span class="hljs-string">"AM"</span> : <span class="hljs-string">"PM"</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-135">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-135">&#182;</a>
+ </div>
+ <p>Swatch Internet time</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"B"</span>: <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.floor((((me.getUTCHours() + <span class="hljs-number">1</span>) % <span class="hljs-number">24</span>) + me.getUTCMinutes() / <span class="hljs-number">60</span> + me.getUTCSeconds() / <span class="hljs-number">3600</span>) * <span class="hljs-number">1000</span> / <span class="hljs-number">24</span>);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-136">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-136">&#182;</a>
+ </div>
+ <p>12-hour format of an hour without leading zeros</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"g"</span>: <span class="hljs-keyword">return</span> me.getHours() % <span class="hljs-number">12</span> != <span class="hljs-number">0</span> ? me.getHours() % <span class="hljs-number">12</span> : <span class="hljs-number">12</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-137">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-137">&#182;</a>
+ </div>
+ <p>24-hour format of an hour without leading zeros</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"G"</span>: <span class="hljs-keyword">return</span> me.getHours();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-138">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-138">&#182;</a>
+ </div>
+ <p>12-hour format of an hour with leading zeros</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"h"</span>: <span class="hljs-keyword">return</span> (<span class="hljs-string">"0"</span> + (me.getHours() % <span class="hljs-number">12</span> != <span class="hljs-number">0</span> ? me.getHours() % <span class="hljs-number">12</span> : <span class="hljs-number">12</span>)).replace(<span class="hljs-regexp">/^.+(..)$/</span>, <span class="hljs-string">"$1"</span>);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-139">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-139">&#182;</a>
+ </div>
+ <p>24-hour format of an hour with leading zeros</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"H"</span>: <span class="hljs-keyword">return</span> (<span class="hljs-string">"0"</span> + me.getHours()).replace(<span class="hljs-regexp">/^.+(..)$/</span>, <span class="hljs-string">"$1"</span>);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-140">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-140">&#182;</a>
+ </div>
+ <p>Minutes with leading zeros</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"i"</span>: <span class="hljs-keyword">return</span> (<span class="hljs-string">"0"</span> + me.getMinutes()).replace(<span class="hljs-regexp">/^.+(..)$/</span>, <span class="hljs-string">"$1"</span>);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-141">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-141">&#182;</a>
+ </div>
+ <p>Seconds, with leading zeros</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"s"</span>: <span class="hljs-keyword">return</span> (<span class="hljs-string">"0"</span> + me.getSeconds()).replace(<span class="hljs-regexp">/^.+(..)$/</span>, <span class="hljs-string">"$1"</span>);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-142">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-142">&#182;</a>
+ </div>
+ <p>Milliseconds</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"u"</span>: <span class="hljs-keyword">return</span> me.getMilliseconds();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-143">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-143">&#182;</a>
+ </div>
+ <p>Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">"U"</span>: <span class="hljs-keyword">return</span> me.getTime() / <span class="hljs-number">1000</span>;
+ }
+ });
+ };
+ })();
+
+ Twig.lib.strip_tags = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">input, allowed</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-144">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-144">&#182;</a>
+ </div>
+ <p>Strips HTML and PHP tags from a string</p>
+<p>version: 1109.2015
+discuss at: <a href="http://phpjs.org/functions/strip_tags">http://phpjs.org/functions/strip_tags</a></p>
+<ul>
+<li>original by: Kevin van Zonneveld (<a href="http://kevin.vanzonneveld.net">http://kevin.vanzonneveld.net</a>)</li>
+<li>improved by: Luke Godfrey</li>
+<li>input by: Pul</li>
+<li>bugfixed by: Kevin van Zonneveld (<a href="http://kevin.vanzonneveld.net">http://kevin.vanzonneveld.net</a>)</li>
+<li>bugfixed by: Onno Marsman</li>
+<li>input by: Alex</li>
+<li>bugfixed by: Kevin van Zonneveld (<a href="http://kevin.vanzonneveld.net">http://kevin.vanzonneveld.net</a>)</li>
+<li>input by: Marc Palau</li>
+<li>improved by: Kevin van Zonneveld (<a href="http://kevin.vanzonneveld.net">http://kevin.vanzonneveld.net</a>)</li>
+<li>input by: Brett Zamir (<a href="http://brett-zamir.me">http://brett-zamir.me</a>)</li>
+<li>bugfixed by: Kevin van Zonneveld (<a href="http://kevin.vanzonneveld.net">http://kevin.vanzonneveld.net</a>)</li>
+<li>bugfixed by: Eric Nagel</li>
+<li>input by: Bobby Drake</li>
+<li>bugfixed by: Kevin van Zonneveld (<a href="http://kevin.vanzonneveld.net">http://kevin.vanzonneveld.net</a>)</li>
+<li>bugfixed by: Tomasz Wesolowski</li>
+<li>input by: Evertjan Garretsen</li>
+<li>revised by: Rafał Kukawski (<a href="http://blog.kukawski.pl/">http://blog.kukawski.pl/</a>)</li>
+<li>example 1: strip_tags(‘<p>Kevin</p> <b>van</b> <i>Zonneveld</i>‘, ‘<i><b>‘);</li>
+<li>returns 1: ‘Kevin <b>van</b> <i>Zonneveld</i>‘</li>
+<li>example 2: strip_tags(‘<p>Kevin <img src="someimage.png" onmouseover="someFunction()">van <i>Zonneveld</i></p>‘, ‘<p>‘);</li>
+<li>returns 2: ‘<p>Kevin van Zonneveld</p>‘</li>
+<li>example 3: strip_tags(“<a href='http://kevin.vanzonneveld.net'>Kevin van Zonneveld</a>“, “<a>“);</li>
+<li>returns 3: ‘<a href='http://kevin.vanzonneveld.net'>Kevin van Zonneveld</a>‘</li>
+<li>example 4: strip_tags(‘1 &lt; 5 5 &gt; 1’);</li>
+<li>returns 4: ‘1 &lt; 5 5 &gt; 1’</li>
+<li>example 5: strip_tags(‘1 <br/> 1’);</li>
+<li>returns 5: ‘1 1’</li>
+<li>example 6: strip_tags(‘1 <br/> 1’, ‘<br>‘);</li>
+<li>returns 6: ‘1 1’</li>
+<li>example 7: strip_tags(‘1 <br/> 1’, ‘<br><br/>‘);</li>
+<li>returns 7: ‘1 <br/> 1’</li>
+</ul>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> allowed = (((allowed || <span class="hljs-string">""</span>) + <span class="hljs-string">""</span>).toLowerCase().match(<span class="hljs-regexp">/&lt;[a-z][a-z0-9]*&gt;/g</span>) || []).join(<span class="hljs-string">''</span>); <span class="hljs-comment">// making sure the allowed arg is a string containing only tags in lowercase (&lt;a&gt;&lt;b&gt;&lt;c&gt;)</span>
+ <span class="hljs-keyword">var</span> tags = <span class="hljs-regexp">/&lt;\/?([a-z][a-z0-9]*)\b[^&gt;]*&gt;/gi</span>,
+ commentsAndPhpTags = <span class="hljs-regexp">/&lt;!--[\s\S]*?--&gt;|&lt;\?(?:php)?[\s\S]*?\?&gt;/gi</span>;
+ <span class="hljs-keyword">return</span> input.replace(commentsAndPhpTags, <span class="hljs-string">''</span>).replace(tags, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$0, $1</span>) </span>{
+ <span class="hljs-keyword">return</span> allowed.indexOf(<span class="hljs-string">'&lt;'</span> + $<span class="hljs-number">1.</span>toLowerCase() + <span class="hljs-string">'&gt;'</span>) &gt; <span class="hljs-number">-1</span> ? $<span class="hljs-number">0</span> : <span class="hljs-string">''</span>;
+ });
+ }
+
+ Twig.lib.parseISO8601Date = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">s</span>)</span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-145">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-145">&#182;</a>
+ </div>
+ <p>Taken from <a href="http://n8v.enteuxis.org/2010/12/parsing-iso-8601-dates-in-javascript/">http://n8v.enteuxis.org/2010/12/parsing-iso-8601-dates-in-javascript/</a>
+parenthese matches:
+year month day hours minutes seconds<br>dotmilliseconds
+tzstring plusminus hours minutes</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> re = <span class="hljs-regexp">/(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)(\.\d+)?(Z|([+-])(\d\d):(\d\d))/</span>;
+
+ <span class="hljs-keyword">var</span> d = [];
+ d = s.match(re);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-146">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-146">&#182;</a>
+ </div>
+ <p>“2010-12-07T11:00:00.000-09:00” parses to:
+ [“2010-12-07T11:00:00.000-09:00”, “2010”, “12”, “07”, “11”,
+ “00”, “00”, “.000”, “-09:00”, “-“, “09”, “00”]
+“2010-12-07T11:00:00.000Z” parses to:
+ [“2010-12-07T11:00:00.000Z”, “2010”, “12”, “07”, “11”,
+ “00”, “00”, “.000”, “Z”, undefined, undefined, undefined]</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ <span class="hljs-keyword">if</span> (! d) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-string">"Couldn't parse ISO 8601 date string '"</span> + s + <span class="hljs-string">"'"</span>;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-147">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-147">&#182;</a>
+ </div>
+ <p>parse strings, leading zeros into proper ints</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> a = [<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>,<span class="hljs-number">6</span>,<span class="hljs-number">10</span>,<span class="hljs-number">11</span>];
+ <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i <span class="hljs-keyword">in</span> a) {
+ d[a[i]] = <span class="hljs-built_in">parseInt</span>(d[a[i]], <span class="hljs-number">10</span>);
+ }
+ d[<span class="hljs-number">7</span>] = <span class="hljs-built_in">parseFloat</span>(d[<span class="hljs-number">7</span>]);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-148">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-148">&#182;</a>
+ </div>
+ <p>Date.UTC(year, month[, date[, hrs[, min[, sec[, ms]]]]])
+note that month is 0-11, not 1-12
+see <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/UTC">https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/UTC</a></p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> ms = <span class="hljs-built_in">Date</span>.UTC(d[<span class="hljs-number">1</span>], d[<span class="hljs-number">2</span>] - <span class="hljs-number">1</span>, d[<span class="hljs-number">3</span>], d[<span class="hljs-number">4</span>], d[<span class="hljs-number">5</span>], d[<span class="hljs-number">6</span>]);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-149">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-149">&#182;</a>
+ </div>
+ <p>if there are milliseconds, add them</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (d[<span class="hljs-number">7</span>] &gt; <span class="hljs-number">0</span>) {
+ ms += <span class="hljs-built_in">Math</span>.round(d[<span class="hljs-number">7</span>] * <span class="hljs-number">1000</span>);
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-150">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-150">&#182;</a>
+ </div>
+ <p>if there’s a timezone, calculate it</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (d[<span class="hljs-number">8</span>] != <span class="hljs-string">"Z"</span> &amp;&amp; d[<span class="hljs-number">10</span>]) {
+ <span class="hljs-keyword">var</span> offset = d[<span class="hljs-number">10</span>] * <span class="hljs-number">60</span> * <span class="hljs-number">60</span> * <span class="hljs-number">1000</span>;
+ <span class="hljs-keyword">if</span> (d[<span class="hljs-number">11</span>]) {
+ offset += d[<span class="hljs-number">11</span>] * <span class="hljs-number">60</span> * <span class="hljs-number">1000</span>;
+ }
+ <span class="hljs-keyword">if</span> (d[<span class="hljs-number">9</span>] == <span class="hljs-string">"-"</span>) {
+ ms -= offset;
+ }
+ <span class="hljs-keyword">else</span> {
+ ms += offset;
+ }
+ }
+
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(ms);
+ };
+
+ Twig.lib.strtotime = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">text, now</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-151">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-151">&#182;</a>
+ </div>
+ <p> discuss at: <a href="http://phpjs.org/functions/strtotime/">http://phpjs.org/functions/strtotime/</a>
+ version: 1109.2016
+original by: Caio Ariede (<a href="http://caioariede.com">http://caioariede.com</a>)
+improved by: Kevin van Zonneveld (<a href="http://kevin.vanzonneveld.net">http://kevin.vanzonneveld.net</a>)
+improved by: Caio Ariede (<a href="http://caioariede.com">http://caioariede.com</a>)
+improved by: A. Matías Quezada (<a href="http://amatiasq.com">http://amatiasq.com</a>)
+improved by: preuter
+improved by: Brett Zamir (<a href="http://brett-zamir.me">http://brett-zamir.me</a>)
+improved by: Mirko Faber
+ input by: David
+bugfixed by: Wagner B. Soares
+bugfixed by: Artur Tchernychev
+bugfixed by: Stephan Bösch-Plepelits (<a href="http://github.com/plepe">http://github.com/plepe</a>)
+ note: Examples all have a fixed timestamp to prevent tests to fail because of variable time(zones)
+ example 1: strtotime(‘+1 day’, 1129633200);
+ returns 1: 1129719600
+ example 2: strtotime(‘+1 week 2 days 4 hours 2 seconds’, 1129633200);
+ returns 2: 1130425202
+ example 3: strtotime(‘last month’, 1129633200);
+ returns 3: 1127041200
+ example 4: strtotime(‘2009-05-04 08:30:00 GMT’);
+ returns 4: 1241425800
+ example 5: strtotime(‘2009-05-04 08:30:00+00’);
+ returns 5: 1241425800
+ example 6: strtotime(‘2009-05-04 08:30:00+02:00’);
+ returns 6: 1241418600
+ example 7: strtotime(‘2009-05-04T08:30:00Z’);
+ returns 7: 1241425800</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ <span class="hljs-keyword">var</span> parsed, match, today, year, date, days, ranges, len, times, regex, i, fail = <span class="hljs-literal">false</span>;
+
+ <span class="hljs-keyword">if</span> (!text) {
+ <span class="hljs-keyword">return</span> fail;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-152">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-152">&#182;</a>
+ </div>
+ <p>Unecessary spaces</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> text = text.replace(<span class="hljs-regexp">/^\s+|\s+$/g</span>, <span class="hljs-string">''</span>)
+ .replace(<span class="hljs-regexp">/\s{2,}/g</span>, <span class="hljs-string">' '</span>)
+ .replace(<span class="hljs-regexp">/[\t\r\n]/g</span>, <span class="hljs-string">''</span>)
+ .toLowerCase();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-153">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-153">&#182;</a>
+ </div>
+ <p>in contrast to php, js Date.parse function interprets:
+dates given as yyyy-mm-dd as in timezone: UTC,
+dates with “.” or “-“ as MDY instead of DMY
+dates with two-digit years differently
+etc…etc…
+…therefore we manually parse lots of common date formats</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> match = text.match(
+ <span class="hljs-regexp">/^(\d{1,4})([\-\.\/\:])(\d{1,2})([\-\.\/\:])(\d{1,4})(?:\s(\d{1,2}):(\d{2})?:?(\d{2})?)?(?:\s([A-Z]+)?)?$/</span>);
+
+ <span class="hljs-keyword">if</span> (match &amp;&amp; match[<span class="hljs-number">2</span>] === match[<span class="hljs-number">4</span>]) {
+ <span class="hljs-keyword">if</span> (match[<span class="hljs-number">1</span>] &gt; <span class="hljs-number">1901</span>) {
+ <span class="hljs-keyword">switch</span> (match[<span class="hljs-number">2</span>]) {
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'-'</span>:
+ {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-154">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-154">&#182;</a>
+ </div>
+ <p>YYYY-M-D</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">3</span>] &gt; <span class="hljs-number">12</span> || match[<span class="hljs-number">5</span>] &gt; <span class="hljs-number">31</span>) {
+ <span class="hljs-keyword">return</span> fail;
+ }
+
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(match[<span class="hljs-number">1</span>], <span class="hljs-built_in">parseInt</span>(match[<span class="hljs-number">3</span>], <span class="hljs-number">10</span>) - <span class="hljs-number">1</span>, match[<span class="hljs-number">5</span>],
+ match[<span class="hljs-number">6</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">7</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">8</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">9</span>] || <span class="hljs-number">0</span>) / <span class="hljs-number">1000</span>;
+ }
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'.'</span>:
+ {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-155">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-155">&#182;</a>
+ </div>
+ <p>YYYY.M.D is not parsed by strtotime()</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> fail;
+ }
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'/'</span>:
+ {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-156">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-156">&#182;</a>
+ </div>
+ <p>YYYY/M/D</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">3</span>] &gt; <span class="hljs-number">12</span> || match[<span class="hljs-number">5</span>] &gt; <span class="hljs-number">31</span>) {
+ <span class="hljs-keyword">return</span> fail;
+ }
+
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(match[<span class="hljs-number">1</span>], <span class="hljs-built_in">parseInt</span>(match[<span class="hljs-number">3</span>], <span class="hljs-number">10</span>) - <span class="hljs-number">1</span>, match[<span class="hljs-number">5</span>],
+ match[<span class="hljs-number">6</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">7</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">8</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">9</span>] || <span class="hljs-number">0</span>) / <span class="hljs-number">1000</span>;
+ }
+ }
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">5</span>] &gt; <span class="hljs-number">1901</span>) {
+ <span class="hljs-keyword">switch</span> (match[<span class="hljs-number">2</span>]) {
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'-'</span>:
+ {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-157">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-157">&#182;</a>
+ </div>
+ <p>D-M-YYYY</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">3</span>] &gt; <span class="hljs-number">12</span> || match[<span class="hljs-number">1</span>] &gt; <span class="hljs-number">31</span>) {
+ <span class="hljs-keyword">return</span> fail;
+ }
+
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(match[<span class="hljs-number">5</span>], <span class="hljs-built_in">parseInt</span>(match[<span class="hljs-number">3</span>], <span class="hljs-number">10</span>) - <span class="hljs-number">1</span>, match[<span class="hljs-number">1</span>],
+ match[<span class="hljs-number">6</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">7</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">8</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">9</span>] || <span class="hljs-number">0</span>) / <span class="hljs-number">1000</span>;
+ }
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'.'</span>:
+ {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-158">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-158">&#182;</a>
+ </div>
+ <p>D.M.YYYY</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">3</span>] &gt; <span class="hljs-number">12</span> || match[<span class="hljs-number">1</span>] &gt; <span class="hljs-number">31</span>) {
+ <span class="hljs-keyword">return</span> fail;
+ }
+
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(match[<span class="hljs-number">5</span>], <span class="hljs-built_in">parseInt</span>(match[<span class="hljs-number">3</span>], <span class="hljs-number">10</span>) - <span class="hljs-number">1</span>, match[<span class="hljs-number">1</span>],
+ match[<span class="hljs-number">6</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">7</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">8</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">9</span>] || <span class="hljs-number">0</span>) / <span class="hljs-number">1000</span>;
+ }
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'/'</span>:
+ {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-159">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-159">&#182;</a>
+ </div>
+ <p>M/D/YYYY</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">1</span>] &gt; <span class="hljs-number">12</span> || match[<span class="hljs-number">3</span>] &gt; <span class="hljs-number">31</span>) {
+ <span class="hljs-keyword">return</span> fail;
+ }
+
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(match[<span class="hljs-number">5</span>], <span class="hljs-built_in">parseInt</span>(match[<span class="hljs-number">1</span>], <span class="hljs-number">10</span>) - <span class="hljs-number">1</span>, match[<span class="hljs-number">3</span>],
+ match[<span class="hljs-number">6</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">7</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">8</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">9</span>] || <span class="hljs-number">0</span>) / <span class="hljs-number">1000</span>;
+ }
+ }
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">switch</span> (match[<span class="hljs-number">2</span>]) {
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'-'</span>:
+ {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-160">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-160">&#182;</a>
+ </div>
+ <p>YY-M-D</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">3</span>] &gt; <span class="hljs-number">12</span> || match[<span class="hljs-number">5</span>] &gt; <span class="hljs-number">31</span> || (match[<span class="hljs-number">1</span>] &lt; <span class="hljs-number">70</span> &amp;&amp; match[<span class="hljs-number">1</span>] &gt; <span class="hljs-number">38</span>)) {
+ <span class="hljs-keyword">return</span> fail;
+ }
+
+ year = match[<span class="hljs-number">1</span>] &gt;= <span class="hljs-number">0</span> &amp;&amp; match[<span class="hljs-number">1</span>] &lt;= <span class="hljs-number">38</span> ? +match[<span class="hljs-number">1</span>] + <span class="hljs-number">2000</span> : match[<span class="hljs-number">1</span>];
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(year, <span class="hljs-built_in">parseInt</span>(match[<span class="hljs-number">3</span>], <span class="hljs-number">10</span>) - <span class="hljs-number">1</span>, match[<span class="hljs-number">5</span>],
+ match[<span class="hljs-number">6</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">7</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">8</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">9</span>] || <span class="hljs-number">0</span>) / <span class="hljs-number">1000</span>;
+ }
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'.'</span>:
+ {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-161">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-161">&#182;</a>
+ </div>
+ <p>D.M.YY or H.MM.SS</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">5</span>] &gt;= <span class="hljs-number">70</span>) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-162">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-162">&#182;</a>
+ </div>
+ <p>D.M.YY</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">3</span>] &gt; <span class="hljs-number">12</span> || match[<span class="hljs-number">1</span>] &gt; <span class="hljs-number">31</span>) {
+ <span class="hljs-keyword">return</span> fail;
+ }
+
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(match[<span class="hljs-number">5</span>], <span class="hljs-built_in">parseInt</span>(match[<span class="hljs-number">3</span>], <span class="hljs-number">10</span>) - <span class="hljs-number">1</span>, match[<span class="hljs-number">1</span>],
+ match[<span class="hljs-number">6</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">7</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">8</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">9</span>] || <span class="hljs-number">0</span>) / <span class="hljs-number">1000</span>;
+ }
+ <span class="hljs-keyword">if</span> (match[<span class="hljs-number">5</span>] &lt; <span class="hljs-number">60</span> &amp;&amp; !match[<span class="hljs-number">6</span>]) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-163">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-163">&#182;</a>
+ </div>
+ <p>H.MM.SS</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">1</span>] &gt; <span class="hljs-number">23</span> || match[<span class="hljs-number">3</span>] &gt; <span class="hljs-number">59</span>) {
+ <span class="hljs-keyword">return</span> fail;
+ }
+
+ today = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(today.getFullYear(), today.getMonth(), today.getDate(),
+ match[<span class="hljs-number">1</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">3</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">5</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">9</span>] || <span class="hljs-number">0</span>) / <span class="hljs-number">1000</span>;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-164">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-164">&#182;</a>
+ </div>
+ <p>invalid format, cannot be parsed</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> fail;
+ }
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'/'</span>:
+ {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-165">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-165">&#182;</a>
+ </div>
+ <p>M/D/YY</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">1</span>] &gt; <span class="hljs-number">12</span> || match[<span class="hljs-number">3</span>] &gt; <span class="hljs-number">31</span> || (match[<span class="hljs-number">5</span>] &lt; <span class="hljs-number">70</span> &amp;&amp; match[<span class="hljs-number">5</span>] &gt; <span class="hljs-number">38</span>)) {
+ <span class="hljs-keyword">return</span> fail;
+ }
+
+ year = match[<span class="hljs-number">5</span>] &gt;= <span class="hljs-number">0</span> &amp;&amp; match[<span class="hljs-number">5</span>] &lt;= <span class="hljs-number">38</span> ? +match[<span class="hljs-number">5</span>] + <span class="hljs-number">2000</span> : match[<span class="hljs-number">5</span>];
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(year, <span class="hljs-built_in">parseInt</span>(match[<span class="hljs-number">1</span>], <span class="hljs-number">10</span>) - <span class="hljs-number">1</span>, match[<span class="hljs-number">3</span>],
+ match[<span class="hljs-number">6</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">7</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">8</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">9</span>] || <span class="hljs-number">0</span>) / <span class="hljs-number">1000</span>;
+ }
+ <span class="hljs-keyword">case</span> <span class="hljs-string">':'</span>:
+ {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-166">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-166">&#182;</a>
+ </div>
+ <p>HH:MM:SS</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">1</span>] &gt; <span class="hljs-number">23</span> || match[<span class="hljs-number">3</span>] &gt; <span class="hljs-number">59</span> || match[<span class="hljs-number">5</span>] &gt; <span class="hljs-number">59</span>) {
+ <span class="hljs-keyword">return</span> fail;
+ }
+
+ today = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(today.getFullYear(), today.getMonth(), today.getDate(),
+ match[<span class="hljs-number">1</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">3</span>] || <span class="hljs-number">0</span>, match[<span class="hljs-number">5</span>] || <span class="hljs-number">0</span>) / <span class="hljs-number">1000</span>;
+ }
+ }
+ }
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-167">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-167">&#182;</a>
+ </div>
+ <p>other formats and “now” should be parsed by Date.parse()</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (text === <span class="hljs-string">'now'</span>) {
+ <span class="hljs-keyword">return</span> now === <span class="hljs-literal">null</span> || <span class="hljs-built_in">isNaN</span>(now) ? <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>()
+ .getTime() / <span class="hljs-number">1000</span> | <span class="hljs-number">0</span> : now | <span class="hljs-number">0</span>;
+ }
+ <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">isNaN</span>(parsed = <span class="hljs-built_in">Date</span>.parse(text))) {
+ <span class="hljs-keyword">return</span> parsed / <span class="hljs-number">1000</span> | <span class="hljs-number">0</span>;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-168">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-168">&#182;</a>
+ </div>
+ <p>Browsers != Chrome have problems parsing ISO 8601 date strings, as they do
+not accept lower case characters, space, or shortened time zones.
+Therefore, fix these problems and try again.
+Examples:
+ 2015-04-15 20:33:59+02
+ 2015-04-15 20:33:59z
+ 2015-04-15t20:33:59+02:00</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match = text.match(<span class="hljs-regexp">/^([0-9]{4}-[0-9]{2}-[0-9]{2})[ t]([0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?)([\+-][0-9]{2}(:[0-9]{2})?|z)/</span>)) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-169">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-169">&#182;</a>
+ </div>
+ <p>fix time zone information</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">4</span>] == <span class="hljs-string">'z'</span>) {
+ match[<span class="hljs-number">4</span>] = <span class="hljs-string">'Z'</span>;
+ }
+ <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (match[<span class="hljs-number">4</span>].match(<span class="hljs-regexp">/^([\+-][0-9]{2})$/</span>)) {
+ match[<span class="hljs-number">4</span>] = match[<span class="hljs-number">4</span>] + <span class="hljs-string">':00'</span>;
+ }
+
+ <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">isNaN</span>(parsed = <span class="hljs-built_in">Date</span>.parse(match[<span class="hljs-number">1</span>] + <span class="hljs-string">'T'</span> + match[<span class="hljs-number">2</span>] + match[<span class="hljs-number">4</span>]))) {
+ <span class="hljs-keyword">return</span> parsed / <span class="hljs-number">1000</span> | <span class="hljs-number">0</span>;
+ }
+ }
+
+ date = now ? <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(now * <span class="hljs-number">1000</span>) : <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
+ days = {
+ <span class="hljs-string">'sun'</span>: <span class="hljs-number">0</span>,
+ <span class="hljs-string">'mon'</span>: <span class="hljs-number">1</span>,
+ <span class="hljs-string">'tue'</span>: <span class="hljs-number">2</span>,
+ <span class="hljs-string">'wed'</span>: <span class="hljs-number">3</span>,
+ <span class="hljs-string">'thu'</span>: <span class="hljs-number">4</span>,
+ <span class="hljs-string">'fri'</span>: <span class="hljs-number">5</span>,
+ <span class="hljs-string">'sat'</span>: <span class="hljs-number">6</span>
+ };
+ ranges = {
+ <span class="hljs-string">'yea'</span>: <span class="hljs-string">'FullYear'</span>,
+ <span class="hljs-string">'mon'</span>: <span class="hljs-string">'Month'</span>,
+ <span class="hljs-string">'day'</span>: <span class="hljs-string">'Date'</span>,
+ <span class="hljs-string">'hou'</span>: <span class="hljs-string">'Hours'</span>,
+ <span class="hljs-string">'min'</span>: <span class="hljs-string">'Minutes'</span>,
+ <span class="hljs-string">'sec'</span>: <span class="hljs-string">'Seconds'</span>
+ };
+
+ <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">lastNext</span>(<span class="hljs-params">type, range, modifier</span>) </span>{
+ <span class="hljs-keyword">var</span> diff, day = days[range];
+
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> day !== <span class="hljs-string">'undefined'</span>) {
+ diff = day - date.getDay();
+
+ <span class="hljs-keyword">if</span> (diff === <span class="hljs-number">0</span>) {
+ diff = <span class="hljs-number">7</span> * modifier;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (diff &gt; <span class="hljs-number">0</span> &amp;&amp; type === <span class="hljs-string">'last'</span>) {
+ diff -= <span class="hljs-number">7</span>;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (diff &lt; <span class="hljs-number">0</span> &amp;&amp; type === <span class="hljs-string">'next'</span>) {
+ diff += <span class="hljs-number">7</span>;
+ }
+
+ date.setDate(date.getDate() + diff);
+ }
+ }
+
+ <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">process</span>(<span class="hljs-params">val</span>) </span>{
+ <span class="hljs-keyword">var</span> splt = val.split(<span class="hljs-string">' '</span>), <span class="hljs-comment">// Todo: Reconcile this with regex using \s, taking into account browser issues with split and regexes</span>
+ type = splt[<span class="hljs-number">0</span>],
+ range = splt[<span class="hljs-number">1</span>].substring(<span class="hljs-number">0</span>, <span class="hljs-number">3</span>),
+ typeIsNumber = <span class="hljs-regexp">/\d+/</span>.test(type),
+ ago = splt[<span class="hljs-number">2</span>] === <span class="hljs-string">'ago'</span>,
+ num = (type === <span class="hljs-string">'last'</span> ? <span class="hljs-number">-1</span> : <span class="hljs-number">1</span>) * (ago ? <span class="hljs-number">-1</span> : <span class="hljs-number">1</span>);
+
+ <span class="hljs-keyword">if</span> (typeIsNumber) {
+ num *= <span class="hljs-built_in">parseInt</span>(type, <span class="hljs-number">10</span>);
+ }
+
+ <span class="hljs-keyword">if</span> (ranges.hasOwnProperty(range) &amp;&amp; !splt[<span class="hljs-number">1</span>].match(<span class="hljs-regexp">/^mon(day|\.)?$/i</span>)) {
+ <span class="hljs-keyword">return</span> date[<span class="hljs-string">'set'</span> + ranges[range]](date[<span class="hljs-string">'get'</span> + ranges[range]]() + num);
+ }
+
+ <span class="hljs-keyword">if</span> (range === <span class="hljs-string">'wee'</span>) {
+ <span class="hljs-keyword">return</span> date.setDate(date.getDate() + (num * <span class="hljs-number">7</span>));
+ }
+
+ <span class="hljs-keyword">if</span> (type === <span class="hljs-string">'next'</span> || type === <span class="hljs-string">'last'</span>) {
+ lastNext(type, range, num);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (!typeIsNumber) {
+ <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
+ }
+
+ <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
+ }
+
+ times = <span class="hljs-string">'(years?|months?|weeks?|days?|hours?|minutes?|min|seconds?|sec'</span> +
+ <span class="hljs-string">'|sunday|sun\\.?|monday|mon\\.?|tuesday|tue\\.?|wednesday|wed\\.?'</span> +
+ <span class="hljs-string">'|thursday|thu\\.?|friday|fri\\.?|saturday|sat\\.?)'</span>;
+ regex = <span class="hljs-string">'([+-]?\\d+\\s'</span> + times + <span class="hljs-string">'|'</span> + <span class="hljs-string">'(last|next)\\s'</span> + times + <span class="hljs-string">')(\\sago)?'</span>;
+
+ match = text.match(<span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(regex, <span class="hljs-string">'gi'</span>));
+ <span class="hljs-keyword">if</span> (!match) {
+ <span class="hljs-keyword">return</span> fail;
+ }
+
+ <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>, len = match.length; i &lt; len; i++) {
+ <span class="hljs-keyword">if</span> (!process(match[i])) {
+ <span class="hljs-keyword">return</span> fail;
+ }
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-170">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-170">&#182;</a>
+ </div>
+ <p>ECMAScript 5 only
+if (!match.every(process))
+ return false;</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ <span class="hljs-keyword">return</span> (date.getTime() / <span class="hljs-number">1000</span>);
+ };
+
+ Twig.lib.is = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">type, obj</span>) </span>{
+ <span class="hljs-keyword">var</span> clas = <span class="hljs-built_in">Object</span>.prototype.toString.call(obj).slice(<span class="hljs-number">8</span>, <span class="hljs-number">-1</span>);
+ <span class="hljs-keyword">return</span> obj !== <span class="hljs-literal">undefined</span> &amp;&amp; obj !== <span class="hljs-literal">null</span> &amp;&amp; clas === type;
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-171">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-171">&#182;</a>
+ </div>
+ <p>shallow-copy an object</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.lib.copy = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">src</span>) </span>{
+ <span class="hljs-keyword">var</span> target = {},
+ key;
+ <span class="hljs-keyword">for</span> (key <span class="hljs-keyword">in</span> src)
+ target[key] = src[key];
+
+ <span class="hljs-keyword">return</span> target;
+ };
+
+ Twig.lib.replaceAll = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">string, search, replace</span>) </span>{
+ <span class="hljs-keyword">return</span> string.split(search).join(replace);
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-172">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-172">&#182;</a>
+ </div>
+ <p>chunk an array (arr) into arrays of (size) items, returns an array of arrays, or an empty array on invalid input</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.lib.chunkArray = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">arr, size</span>) </span>{
+ <span class="hljs-keyword">var</span> returnVal = [],
+ x = <span class="hljs-number">0</span>,
+ len = arr.length;
+
+ <span class="hljs-keyword">if</span> (size &lt; <span class="hljs-number">1</span> || !Twig.lib.is(<span class="hljs-string">"Array"</span>, arr)) {
+ <span class="hljs-keyword">return</span> [];
+ }
+
+ <span class="hljs-keyword">while</span> (x &lt; len) {
+ returnVal.push(arr.slice(x, x += size));
+ }
+
+ <span class="hljs-keyword">return</span> returnVal;
+ };
+
+ Twig.lib.round = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">round</span>(<span class="hljs-params">value, precision, mode</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-173">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-173">&#182;</a>
+ </div>
+ <p> discuss at: <a href="http://phpjs.org/functions/round/">http://phpjs.org/functions/round/</a>
+original by: Philip Peterson
+ revised by: Onno Marsman
+ revised by: T.Wild
+ revised by: Rafał Kukawski (<a href="http://blog.kukawski.pl/">http://blog.kukawski.pl/</a>)
+ input by: Greenseed
+ input by: meo
+ input by: William
+ input by: Josep Sanz (<a href="http://www.ws3.es/">http://www.ws3.es/</a>)
+bugfixed by: Brett Zamir (<a href="http://brett-zamir.me">http://brett-zamir.me</a>)
+ note: Great work. Ideas for improvement:
+ note: - code more compliant with developer guidelines
+ note: - for implementing PHP constant arguments look at
+ note: the pathinfo() function, it offers the greatest
+ note: flexibility &amp; compatibility possible
+ example 1: round(1241757, -3);
+ returns 1: 1242000
+ example 2: round(3.6);
+ returns 2: 4
+ example 3: round(2.835, 2);
+ returns 3: 2.84
+ example 4: round(1.1749999999999, 2);
+ returns 4: 1.17
+ example 5: round(58551.799999999996, 2);
+ returns 5: 58551.8</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ <span class="hljs-keyword">var</span> m, f, isHalf, sgn; <span class="hljs-comment">// helper variables</span>
+ precision |= <span class="hljs-number">0</span>; <span class="hljs-comment">// making sure precision is integer</span>
+ m = <span class="hljs-built_in">Math</span>.pow(<span class="hljs-number">10</span>, precision);
+ value *= m;
+ sgn = (value &gt; <span class="hljs-number">0</span>) | -(value &lt; <span class="hljs-number">0</span>); <span class="hljs-comment">// sign of the number</span>
+ isHalf = value % <span class="hljs-number">1</span> === <span class="hljs-number">0.5</span> * sgn;
+ f = <span class="hljs-built_in">Math</span>.floor(value);
+
+ <span class="hljs-keyword">if</span> (isHalf) {
+ <span class="hljs-keyword">switch</span> (mode) {
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'PHP_ROUND_HALF_DOWN'</span>:
+ value = f + (sgn &lt; <span class="hljs-number">0</span>); <span class="hljs-comment">// rounds .5 toward zero</span>
+ <span class="hljs-keyword">break</span>;
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'PHP_ROUND_HALF_EVEN'</span>:
+ value = f + (f % <span class="hljs-number">2</span> * sgn); <span class="hljs-comment">// rouds .5 towards the next even integer</span>
+ <span class="hljs-keyword">break</span>;
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'PHP_ROUND_HALF_ODD'</span>:
+ value = f + !(f % <span class="hljs-number">2</span>); <span class="hljs-comment">// rounds .5 towards the next odd integer</span>
+ <span class="hljs-keyword">break</span>;
+ <span class="hljs-keyword">default</span>:
+ value = f + (sgn &gt; <span class="hljs-number">0</span>); <span class="hljs-comment">// rounds .5 away from zero</span>
+ }
+ }
+
+ <span class="hljs-keyword">return</span> (isHalf ? value : <span class="hljs-built_in">Math</span>.round(value)) / m;
+ };
+
+ Twig.lib.max = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">max</span>(<span class="hljs-params"></span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-174">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-174">&#182;</a>
+ </div>
+ <p> discuss at: <a href="http://phpjs.org/functions/max/">http://phpjs.org/functions/max/</a>
+original by: Onno Marsman
+ revised by: Onno Marsman
+improved by: Jack
+ note: Long code cause we’re aiming for maximum PHP compatibility
+ example 1: max(1, 3, 5, 6, 7);
+ returns 1: 7
+ example 2: max([2, 4, 5]);
+ returns 2: 5
+ example 3: max(0, ‘hello’);
+ returns 3: 0
+ example 4: max(‘hello’, 0);
+ returns 4: ‘hello’
+ example 5: max(-1, ‘hello’);
+ returns 5: ‘hello’
+ example 6: max([2, 4, 8], [2, 5, 7]);
+ returns 6: [2, 5, 7]</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ <span class="hljs-keyword">var</span> ar, retVal, i = <span class="hljs-number">0</span>,
+ n = <span class="hljs-number">0</span>,
+ argv = <span class="hljs-built_in">arguments</span>,
+ argc = argv.length,
+ _obj2Array = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">obj</span>) </span>{
+ <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Object</span>.prototype.toString.call(obj) === <span class="hljs-string">'[object Array]'</span>) {
+ <span class="hljs-keyword">return</span> obj;
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">var</span> ar = [];
+ <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i <span class="hljs-keyword">in</span> obj) {
+ <span class="hljs-keyword">if</span> (obj.hasOwnProperty(i)) {
+ ar.push(obj[i]);
+ }
+ }
+ <span class="hljs-keyword">return</span> ar;
+ }
+ }, <span class="hljs-comment">//function _obj2Array</span>
+ _compare = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">current, next</span>) </span>{
+ <span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>,
+ n = <span class="hljs-number">0</span>,
+ tmp = <span class="hljs-number">0</span>,
+ nl = <span class="hljs-number">0</span>,
+ cl = <span class="hljs-number">0</span>;
+
+ <span class="hljs-keyword">if</span> (current === next) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> current === <span class="hljs-string">'object'</span>) {
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> next === <span class="hljs-string">'object'</span>) {
+ current = _obj2Array(current);
+ next = _obj2Array(next);
+ cl = current.length;
+ nl = next.length;
+ <span class="hljs-keyword">if</span> (nl &gt; cl) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (nl &lt; cl) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
+ }
+ <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>, n = cl; i &lt; n; ++i) {
+ tmp = _compare(current[i], next[i]);
+ <span class="hljs-keyword">if</span> (tmp == <span class="hljs-number">1</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (tmp == <span class="hljs-number">-1</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
+ }
+ }
+ <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
+ }
+ <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> next === <span class="hljs-string">'object'</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">isNaN</span>(next) &amp;&amp; !<span class="hljs-built_in">isNaN</span>(current)) {
+ <span class="hljs-keyword">if</span> (current == <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
+ }
+ <span class="hljs-keyword">return</span> (current &lt; <span class="hljs-number">0</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">-1</span>);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">isNaN</span>(current) &amp;&amp; !<span class="hljs-built_in">isNaN</span>(next)) {
+ <span class="hljs-keyword">if</span> (next == <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
+ }
+ <span class="hljs-keyword">return</span> (next &gt; <span class="hljs-number">0</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">-1</span>);
+ }
+
+ <span class="hljs-keyword">if</span> (next == current) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
+ }
+ <span class="hljs-keyword">return</span> (next &gt; current ? <span class="hljs-number">1</span> : <span class="hljs-number">-1</span>);
+ }; <span class="hljs-comment">//function _compare</span>
+ <span class="hljs-keyword">if</span> (argc === <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'At least one value should be passed to max()'</span>);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (argc === <span class="hljs-number">1</span>) {
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> argv[<span class="hljs-number">0</span>] === <span class="hljs-string">'object'</span>) {
+ ar = _obj2Array(argv[<span class="hljs-number">0</span>]);
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Wrong parameter count for max()'</span>);
+ }
+ <span class="hljs-keyword">if</span> (ar.length === <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Array must contain at least one element for max()'</span>);
+ }
+ } <span class="hljs-keyword">else</span> {
+ ar = argv;
+ }
+
+ retVal = ar[<span class="hljs-number">0</span>];
+ <span class="hljs-keyword">for</span> (i = <span class="hljs-number">1</span>, n = ar.length; i &lt; n; ++i) {
+ <span class="hljs-keyword">if</span> (_compare(retVal, ar[i]) == <span class="hljs-number">1</span>) {
+ retVal = ar[i];
+ }
+ }
+
+ <span class="hljs-keyword">return</span> retVal;
+ };
+
+ Twig.lib.min = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">min</span>(<span class="hljs-params"></span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-175">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-175">&#182;</a>
+ </div>
+ <p> discuss at: <a href="http://phpjs.org/functions/min/">http://phpjs.org/functions/min/</a>
+original by: Onno Marsman
+ revised by: Onno Marsman
+improved by: Jack
+ note: Long code cause we’re aiming for maximum PHP compatibility
+ example 1: min(1, 3, 5, 6, 7);
+ returns 1: 1
+ example 2: min([2, 4, 5]);
+ returns 2: 2
+ example 3: min(0, ‘hello’);
+ returns 3: 0
+ example 4: min(‘hello’, 0);
+ returns 4: ‘hello’
+ example 5: min(-1, ‘hello’);
+ returns 5: -1
+ example 6: min([2, 4, 8], [2, 5, 7]);
+ returns 6: [2, 4, 8]</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ <span class="hljs-keyword">var</span> ar, retVal, i = <span class="hljs-number">0</span>,
+ n = <span class="hljs-number">0</span>,
+ argv = <span class="hljs-built_in">arguments</span>,
+ argc = argv.length,
+ _obj2Array = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">obj</span>) </span>{
+ <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Object</span>.prototype.toString.call(obj) === <span class="hljs-string">'[object Array]'</span>) {
+ <span class="hljs-keyword">return</span> obj;
+ }
+ <span class="hljs-keyword">var</span> ar = [];
+ <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i <span class="hljs-keyword">in</span> obj) {
+ <span class="hljs-keyword">if</span> (obj.hasOwnProperty(i)) {
+ ar.push(obj[i]);
+ }
+ }
+ <span class="hljs-keyword">return</span> ar;
+ }, <span class="hljs-comment">//function _obj2Array</span>
+ _compare = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">current, next</span>) </span>{
+ <span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>,
+ n = <span class="hljs-number">0</span>,
+ tmp = <span class="hljs-number">0</span>,
+ nl = <span class="hljs-number">0</span>,
+ cl = <span class="hljs-number">0</span>;
+
+ <span class="hljs-keyword">if</span> (current === next) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> current === <span class="hljs-string">'object'</span>) {
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> next === <span class="hljs-string">'object'</span>) {
+ current = _obj2Array(current);
+ next = _obj2Array(next);
+ cl = current.length;
+ nl = next.length;
+ <span class="hljs-keyword">if</span> (nl &gt; cl) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (nl &lt; cl) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
+ }
+ <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>, n = cl; i &lt; n; ++i) {
+ tmp = _compare(current[i], next[i]);
+ <span class="hljs-keyword">if</span> (tmp == <span class="hljs-number">1</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (tmp == <span class="hljs-number">-1</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
+ }
+ }
+ <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
+ }
+ <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> next === <span class="hljs-string">'object'</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">isNaN</span>(next) &amp;&amp; !<span class="hljs-built_in">isNaN</span>(current)) {
+ <span class="hljs-keyword">if</span> (current == <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
+ }
+ <span class="hljs-keyword">return</span> (current &lt; <span class="hljs-number">0</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">-1</span>);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">isNaN</span>(current) &amp;&amp; !<span class="hljs-built_in">isNaN</span>(next)) {
+ <span class="hljs-keyword">if</span> (next == <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
+ }
+ <span class="hljs-keyword">return</span> (next &gt; <span class="hljs-number">0</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">-1</span>);
+ }
+
+ <span class="hljs-keyword">if</span> (next == current) {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
+ }
+ <span class="hljs-keyword">return</span> (next &gt; current ? <span class="hljs-number">1</span> : <span class="hljs-number">-1</span>);
+ }; <span class="hljs-comment">//function _compare</span>
+
+ <span class="hljs-keyword">if</span> (argc === <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'At least one value should be passed to min()'</span>);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (argc === <span class="hljs-number">1</span>) {
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> argv[<span class="hljs-number">0</span>] === <span class="hljs-string">'object'</span>) {
+ ar = _obj2Array(argv[<span class="hljs-number">0</span>]);
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Wrong parameter count for min()'</span>);
+ }
+
+ <span class="hljs-keyword">if</span> (ar.length === <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Array must contain at least one element for min()'</span>);
+ }
+ } <span class="hljs-keyword">else</span> {
+ ar = argv;
+ }
+
+ retVal = ar[<span class="hljs-number">0</span>];
+
+ <span class="hljs-keyword">for</span> (i = <span class="hljs-number">1</span>, n = ar.length; i &lt; n; ++i) {
+ <span class="hljs-keyword">if</span> (_compare(retVal, ar[i]) == <span class="hljs-number">-1</span>) {
+ retVal = ar[i];
+ }
+ }
+
+ <span class="hljs-keyword">return</span> retVal;
+ };
+
+ <span class="hljs-keyword">return</span> Twig;
+
+})(Twig || { });</pre></div></div>
+
+ </li>
+
+
+ <li id="section-176">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-176">&#182;</a>
+ </div>
+ <pre><code>Twig.js
+Available under the BSD <span class="hljs-number">2</span>-Clause License
+https:<span class="hljs-comment">//github.com/justjohn/twig.js</span>
+</code></pre>
+ </div>
+
+ </li>
+
+
+ <li id="section-177">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-177">&#182;</a>
+ </div>
+ <h2 id="twig-logic-js">twig.logic.js</h2>
+<p>This file handles tokenizing, compiling and parsing logic tokens. {% … %}</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> Twig = (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Twig</span>) </span>{
+<span class="hljs-meta"> "use strict"</span>;
+
+ <span class="hljs-comment">/**
+ * Namespace for logic handling.
+ */</span>
+ Twig.logic = {};
+
+ <span class="hljs-comment">/**
+ * Logic token types.
+ */</span>
+ Twig.logic.type = {
+ if_: <span class="hljs-string">'Twig.logic.type.if'</span>,
+ endif: <span class="hljs-string">'Twig.logic.type.endif'</span>,
+ for_: <span class="hljs-string">'Twig.logic.type.for'</span>,
+ endfor: <span class="hljs-string">'Twig.logic.type.endfor'</span>,
+ else_: <span class="hljs-string">'Twig.logic.type.else'</span>,
+ elseif: <span class="hljs-string">'Twig.logic.type.elseif'</span>,
+ set: <span class="hljs-string">'Twig.logic.type.set'</span>,
+ setcapture:<span class="hljs-string">'Twig.logic.type.setcapture'</span>,
+ endset: <span class="hljs-string">'Twig.logic.type.endset'</span>,
+ filter: <span class="hljs-string">'Twig.logic.type.filter'</span>,
+ endfilter: <span class="hljs-string">'Twig.logic.type.endfilter'</span>,
+ shortblock: <span class="hljs-string">'Twig.logic.type.shortblock'</span>,
+ block: <span class="hljs-string">'Twig.logic.type.block'</span>,
+ endblock: <span class="hljs-string">'Twig.logic.type.endblock'</span>,
+ extends_: <span class="hljs-string">'Twig.logic.type.extends'</span>,
+ use: <span class="hljs-string">'Twig.logic.type.use'</span>,
+ include: <span class="hljs-string">'Twig.logic.type.include'</span>,
+ spaceless: <span class="hljs-string">'Twig.logic.type.spaceless'</span>,
+ endspaceless: <span class="hljs-string">'Twig.logic.type.endspaceless'</span>,
+ macro: <span class="hljs-string">'Twig.logic.type.macro'</span>,
+ endmacro: <span class="hljs-string">'Twig.logic.type.endmacro'</span>,
+ import_: <span class="hljs-string">'Twig.logic.type.import'</span>,
+ <span class="hljs-keyword">from</span>: <span class="hljs-string">'Twig.logic.type.from'</span>,
+ embed: <span class="hljs-string">'Twig.logic.type.embed'</span>,
+ endembed: <span class="hljs-string">'Twig.logic.type.endembed'</span>
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-178">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-178">&#182;</a>
+ </div>
+ <p>Regular expressions for handling logic tokens.</p>
+<p>Properties:</p>
+<pre><code> type: The type of expression this matches
+
+ regex: A regular expression that matches the format of the token
+
+ next: What logic tokens (if any) pop this token off the logic stack. If empty, the
+ logic token is assumed to not require an end tag and isn&#39;t push onto the stack.
+
+ open: Does this tag open a logic expression or is it standalone. For example,
+ {% endif %} cannot exist without an opening {% if ... %} tag, so open = false.
+</code></pre><p> Functions:</p>
+<pre><code> compile: A <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">that</span> <span class="hljs-title">handles</span> <span class="hljs-title">compiling</span> <span class="hljs-title">the</span> <span class="hljs-title">token</span> <span class="hljs-title">into</span> <span class="hljs-title">an</span> <span class="hljs-title">output</span> <span class="hljs-title">token</span> <span class="hljs-title">ready</span> <span class="hljs-title">for</span>
+ <span class="hljs-title">parsing</span> <span class="hljs-title">with</span> <span class="hljs-title">the</span> <span class="hljs-title">parse</span> <span class="hljs-title">function</span>.
+
+ <span class="hljs-title">parse</span>: <span class="hljs-title">A</span> <span class="hljs-title">function</span> <span class="hljs-title">that</span> <span class="hljs-title">parses</span> <span class="hljs-title">the</span> <span class="hljs-title">compiled</span> <span class="hljs-title">token</span> <span class="hljs-title">into</span> <span class="hljs-title">output</span> (<span class="hljs-params">HTML / whatever the
+ template represents</span>).</span>
+</code></pre>
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.logic.definitions = [
+ {
+ <span class="hljs-comment">/**
+ * If type logic tokens.
+ *
+ * Format: {% if expression %}
+ */</span>
+ type: Twig.logic.type.if_,
+ regex: <span class="hljs-regexp">/^if\s+([\s\S]+)$/</span>,
+ next: [
+ Twig.logic.type.else_,
+ Twig.logic.type.elseif,
+ Twig.logic.type.endif
+ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ <span class="hljs-keyword">var</span> expression = token.match[<span class="hljs-number">1</span>];</pre></div></div>
+
+ </li>
+
+
+ <li id="section-179">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-179">&#182;</a>
+ </div>
+ <p>Compile the expression.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> token.stack = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: expression
+ }]).stack;
+ <span class="hljs-keyword">delete</span> token.match;
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{
+ <span class="hljs-keyword">var</span> output = <span class="hljs-string">''</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-180">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-180">&#182;</a>
+ </div>
+ <p>Parse the expression</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> result = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.stack, context]);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-181">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-181">&#182;</a>
+ </div>
+ <p>Start a new logic chain</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> chain = <span class="hljs-literal">true</span>;
+
+ <span class="hljs-keyword">if</span> (result) {
+ chain = <span class="hljs-literal">false</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-182">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-182">&#182;</a>
+ </div>
+ <p>parse if output</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> output = Twig.parse.apply(<span class="hljs-keyword">this</span>, [token.output, context]);
+ }
+ <span class="hljs-keyword">return</span> {
+ chain: chain,
+ output: output
+ };
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * Else if type logic tokens.
+ *
+ * Format: {% elseif expression %}
+ */</span>
+ type: Twig.logic.type.elseif,
+ regex: <span class="hljs-regexp">/^elseif\s+([^\s].*)$/</span>,
+ next: [
+ Twig.logic.type.else_,
+ Twig.logic.type.elseif,
+ Twig.logic.type.endif
+ ],
+ open: <span class="hljs-literal">false</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ <span class="hljs-keyword">var</span> expression = token.match[<span class="hljs-number">1</span>];</pre></div></div>
+
+ </li>
+
+
+ <li id="section-183">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-183">&#182;</a>
+ </div>
+ <p>Compile the expression.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> token.stack = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: expression
+ }]).stack;
+ <span class="hljs-keyword">delete</span> token.match;
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{
+ <span class="hljs-keyword">var</span> output = <span class="hljs-string">''</span>;
+
+ <span class="hljs-keyword">if</span> (chain &amp;&amp; Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.stack, context]) === <span class="hljs-literal">true</span>) {
+ chain = <span class="hljs-literal">false</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-184">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-184">&#182;</a>
+ </div>
+ <p>parse if output</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> output = Twig.parse.apply(<span class="hljs-keyword">this</span>, [token.output, context]);
+ }
+
+ <span class="hljs-keyword">return</span> {
+ chain: chain,
+ output: output
+ };
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * Else if type logic tokens.
+ *
+ * Format: {% elseif expression %}
+ */</span>
+ type: Twig.logic.type.else_,
+ regex: <span class="hljs-regexp">/^else$/</span>,
+ next: [
+ Twig.logic.type.endif,
+ Twig.logic.type.endfor
+ ],
+ open: <span class="hljs-literal">false</span>,
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{
+ <span class="hljs-keyword">var</span> output = <span class="hljs-string">''</span>;
+ <span class="hljs-keyword">if</span> (chain) {
+ output = Twig.parse.apply(<span class="hljs-keyword">this</span>, [token.output, context]);
+ }
+ <span class="hljs-keyword">return</span> {
+ chain: chain,
+ output: output
+ };
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * End if type logic tokens.
+ *
+ * Format: {% endif %}
+ */</span>
+ type: Twig.logic.type.endif,
+ regex: <span class="hljs-regexp">/^endif$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">false</span>
+ },
+ {
+ <span class="hljs-comment">/**
+ * For type logic tokens.
+ *
+ * Format: {% for expression %}
+ */</span>
+ type: Twig.logic.type.for_,
+ regex: <span class="hljs-regexp">/^for\s+([a-zA-Z0-9_,\s]+)\s+in\s+([^\s].*?)(?:\s+if\s+([^\s].*))?$/</span>,
+ next: [
+ Twig.logic.type.else_,
+ Twig.logic.type.endfor
+ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ <span class="hljs-keyword">var</span> key_value = token.match[<span class="hljs-number">1</span>],
+ expression = token.match[<span class="hljs-number">2</span>],
+ conditional = token.match[<span class="hljs-number">3</span>],
+ kv_split = <span class="hljs-literal">null</span>;
+
+ token.key_var = <span class="hljs-literal">null</span>;
+ token.value_var = <span class="hljs-literal">null</span>;
+
+ <span class="hljs-keyword">if</span> (key_value.indexOf(<span class="hljs-string">","</span>) &gt;= <span class="hljs-number">0</span>) {
+ kv_split = key_value.split(<span class="hljs-string">','</span>);
+ <span class="hljs-keyword">if</span> (kv_split.length === <span class="hljs-number">2</span>) {
+ token.key_var = kv_split[<span class="hljs-number">0</span>].trim();
+ token.value_var = kv_split[<span class="hljs-number">1</span>].trim();
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Invalid expression in for loop: "</span> + key_value);
+ }
+ } <span class="hljs-keyword">else</span> {
+ token.value_var = key_value;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-185">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-185">&#182;</a>
+ </div>
+ <p>Valid expressions for a for loop
+ for item in expression
+ for key,item in expression</p>
+
+ </div>
+
+ </li>
+
+
+ <li id="section-186">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-186">&#182;</a>
+ </div>
+ <p>Compile the expression.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> token.expression = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: expression
+ }]).stack;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-187">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-187">&#182;</a>
+ </div>
+ <p>Compile the conditional (if available)</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (conditional) {
+ token.conditional = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: conditional
+ }]).stack;
+ }
+
+ <span class="hljs-keyword">delete</span> token.match;
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, continue_chain</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-188">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-188">&#182;</a>
+ </div>
+ <p>Parse expression</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> result = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.expression, context]),
+ output = [],
+ len,
+ index = <span class="hljs-number">0</span>,
+ keyset,
+ that = <span class="hljs-keyword">this</span>,
+ conditional = token.conditional,
+ buildLoop = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">index, len</span>) </span>{
+ <span class="hljs-keyword">var</span> isConditional = conditional !== <span class="hljs-literal">undefined</span>;
+ <span class="hljs-keyword">return</span> {
+ index: index+<span class="hljs-number">1</span>,
+ index0: index,
+ revindex: isConditional?<span class="hljs-literal">undefined</span>:len-index,
+ revindex0: isConditional?<span class="hljs-literal">undefined</span>:len-index<span class="hljs-number">-1</span>,
+ first: (index === <span class="hljs-number">0</span>),
+ last: isConditional?<span class="hljs-literal">undefined</span>:(index === len<span class="hljs-number">-1</span>),
+ length: isConditional?<span class="hljs-literal">undefined</span>:len,
+ parent: context
+ };
+ },</pre></div></div>
+
+ </li>
+
+
+ <li id="section-189">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-189">&#182;</a>
+ </div>
+ <p>run once for each iteration of the loop</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> loop = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">key, value</span>) </span>{
+ <span class="hljs-keyword">var</span> inner_context = Twig.ChildContext(context);
+
+ inner_context[token.value_var] = value;
+
+ <span class="hljs-keyword">if</span> (token.key_var) {
+ inner_context[token.key_var] = key;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-190">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-190">&#182;</a>
+ </div>
+ <p>Loop object</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> inner_context.loop = buildLoop(index, len);
+
+ <span class="hljs-keyword">if</span> (conditional === <span class="hljs-literal">undefined</span> ||
+ Twig.expression.parse.apply(that, [conditional, inner_context]))
+ {
+ output.push(Twig.parse.apply(that, [token.output, inner_context]));
+ index += <span class="hljs-number">1</span>;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-191">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-191">&#182;</a>
+ </div>
+ <p>Delete loop-related variables from the context</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">delete</span> inner_context[<span class="hljs-string">'loop'</span>];
+ <span class="hljs-keyword">delete</span> inner_context[token.value_var];
+ <span class="hljs-keyword">delete</span> inner_context[token.key_var];</pre></div></div>
+
+ </li>
+
+
+ <li id="section-192">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-192">&#182;</a>
+ </div>
+ <p>Merge in values that exist in context but have changed
+in inner_context.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.merge(context, inner_context, <span class="hljs-literal">true</span>);
+ };
+
+
+ <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">'Array'</span>, result)) {
+ len = result.length;
+ Twig.forEach(result, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">var</span> key = index;
+
+ loop(key, value);
+ });
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">'Object'</span>, result)) {
+ <span class="hljs-keyword">if</span> (result._keys !== <span class="hljs-literal">undefined</span>) {
+ keyset = result._keys;
+ } <span class="hljs-keyword">else</span> {
+ keyset = <span class="hljs-built_in">Object</span>.keys(result);
+ }
+ len = keyset.length;
+ Twig.forEach(keyset, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">key</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-193">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-193">&#182;</a>
+ </div>
+ <p>Ignore the _keys property, it’s internal to twig.js</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (key === <span class="hljs-string">"_keys"</span>) <span class="hljs-keyword">return</span>;
+
+ loop(key, result[key]);
+ });
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-194">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-194">&#182;</a>
+ </div>
+ <p>Only allow else statements if no output was generated</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> continue_chain = (output.length === <span class="hljs-number">0</span>);
+
+ <span class="hljs-keyword">return</span> {
+ chain: continue_chain,
+ output: Twig.output.apply(<span class="hljs-keyword">this</span>, [output])
+ };
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * End if type logic tokens.
+ *
+ * Format: {% endif %}
+ */</span>
+ type: Twig.logic.type.endfor,
+ regex: <span class="hljs-regexp">/^endfor$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">false</span>
+ },
+ {
+ <span class="hljs-comment">/**
+ * Set type logic tokens.
+ *
+ * Format: {% set key = expression %}
+ */</span>
+ type: Twig.logic.type.set,
+ regex: <span class="hljs-regexp">/^set\s+([a-zA-Z0-9_,\s]+)\s*=\s*([\s\S]+)$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ <span class="hljs-keyword">var</span> key = token.match[<span class="hljs-number">1</span>].trim(),
+ expression = token.match[<span class="hljs-number">2</span>],</pre></div></div>
+
+ </li>
+
+
+ <li id="section-195">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-195">&#182;</a>
+ </div>
+ <p>Compile the expression.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> expression_stack = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: expression
+ }]).stack;
+
+ token.key = key;
+ token.expression = expression_stack;
+
+ <span class="hljs-keyword">delete</span> token.match;
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, continue_chain</span>) </span>{
+ <span class="hljs-keyword">var</span> value = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.expression, context]),
+ key = token.key;
+
+ context[key] = value;
+
+ <span class="hljs-keyword">return</span> {
+ chain: continue_chain,
+ context: context
+ };
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * Set capture type logic tokens.
+ *
+ * Format: {% set key %}
+ */</span>
+ type: Twig.logic.type.setcapture,
+ regex: <span class="hljs-regexp">/^set\s+([a-zA-Z0-9_,\s]+)$/</span>,
+ next: [
+ Twig.logic.type.endset
+ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ <span class="hljs-keyword">var</span> key = token.match[<span class="hljs-number">1</span>].trim();
+
+ token.key = key;
+
+ <span class="hljs-keyword">delete</span> token.match;
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, continue_chain</span>) </span>{
+
+ <span class="hljs-keyword">var</span> value = Twig.parse.apply(<span class="hljs-keyword">this</span>, [token.output, context]),
+ key = token.key;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-196">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-196">&#182;</a>
+ </div>
+ <p>set on both the global and local context</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">this</span>.context[key] = value;
+ context[key] = value;
+
+ <span class="hljs-keyword">return</span> {
+ chain: continue_chain,
+ context: context
+ };
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * End set type block logic tokens.
+ *
+ * Format: {% endset %}
+ */</span>
+ type: Twig.logic.type.endset,
+ regex: <span class="hljs-regexp">/^endset$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">false</span>
+ },
+ {
+ <span class="hljs-comment">/**
+ * Filter logic tokens.
+ *
+ * Format: {% filter upper %} or {% filter lower|escape %}
+ */</span>
+ type: Twig.logic.type.filter,
+ regex: <span class="hljs-regexp">/^filter\s+(.+)$/</span>,
+ next: [
+ Twig.logic.type.endfilter
+ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ <span class="hljs-keyword">var</span> expression = <span class="hljs-string">"|"</span> + token.match[<span class="hljs-number">1</span>].trim();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-197">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-197">&#182;</a>
+ </div>
+ <p>Compile the expression.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> token.stack = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: expression
+ }]).stack;
+ <span class="hljs-keyword">delete</span> token.match;
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{
+ <span class="hljs-keyword">var</span> unfiltered = Twig.parse.apply(<span class="hljs-keyword">this</span>, [token.output, context]),
+ stack = [{
+ type: Twig.expression.type.string,
+ value: unfiltered
+ }].concat(token.stack);
+
+ <span class="hljs-keyword">var</span> output = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [stack, context]);
+
+ <span class="hljs-keyword">return</span> {
+ chain: chain,
+ output: output
+ };
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * End filter logic tokens.
+ *
+ * Format: {% endfilter %}
+ */</span>
+ type: Twig.logic.type.endfilter,
+ regex: <span class="hljs-regexp">/^endfilter$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">false</span>
+ },
+ {
+ <span class="hljs-comment">/**
+ * Block logic tokens.
+ *
+ * Format: {% block title %}
+ */</span>
+ type: Twig.logic.type.block,
+ regex: <span class="hljs-regexp">/^block\s+([a-zA-Z0-9_]+)$/</span>,
+ next: [
+ Twig.logic.type.endblock
+ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ token.block = token.match[<span class="hljs-number">1</span>].trim();
+ <span class="hljs-keyword">delete</span> token.match;
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{
+ <span class="hljs-keyword">var</span> block_output,
+ output,
+ isImported = Twig.indexOf(<span class="hljs-keyword">this</span>.importedBlocks, token.block) &gt; <span class="hljs-number">-1</span>,
+ hasParent = <span class="hljs-keyword">this</span>.blocks[token.block] &amp;&amp; Twig.indexOf(<span class="hljs-keyword">this</span>.blocks[token.block], Twig.placeholders.parent) &gt; <span class="hljs-number">-1</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-198">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-198">&#182;</a>
+ </div>
+ <p>Don’t override previous blocks unless they’re imported with “use”
+Loops should be exempted as well.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.blocks[token.block] === <span class="hljs-literal">undefined</span> || isImported || hasParent || context.loop || token.overwrite) {
+ <span class="hljs-keyword">if</span> (token.expression) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-199">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-199">&#182;</a>
+ </div>
+ <p>Short blocks have output as an expression on the open tag (no body)</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> block_output = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.string,
+ value: Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.output, context])
+ }, context]);
+ } <span class="hljs-keyword">else</span> {
+ block_output = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.string,
+ value: Twig.parse.apply(<span class="hljs-keyword">this</span>, [token.output, context])
+ }, context]);
+ }
+
+ <span class="hljs-keyword">if</span> (isImported) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-200">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-200">&#182;</a>
+ </div>
+ <p>once the block is overridden, remove it from the list of imported blocks</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">this</span>.importedBlocks.splice(<span class="hljs-keyword">this</span>.importedBlocks.indexOf(token.block), <span class="hljs-number">1</span>);
+ }
+
+ <span class="hljs-keyword">if</span> (hasParent) {
+ <span class="hljs-keyword">this</span>.blocks[token.block] = Twig.Markup(<span class="hljs-keyword">this</span>.blocks[token.block].replace(Twig.placeholders.parent, block_output));
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">this</span>.blocks[token.block] = block_output;
+ }
+
+ <span class="hljs-keyword">this</span>.originalBlockTokens[token.block] = {
+ type: token.type,
+ block: token.block,
+ output: token.output,
+ overwrite: <span class="hljs-literal">true</span>
+ };
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-201">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-201">&#182;</a>
+ </div>
+ <p>Check if a child block has been set from a template extending this one.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.child.blocks[token.block]) {
+ output = <span class="hljs-keyword">this</span>.child.blocks[token.block];
+ } <span class="hljs-keyword">else</span> {
+ output = <span class="hljs-keyword">this</span>.blocks[token.block];
+ }
+
+ <span class="hljs-keyword">return</span> {
+ chain: chain,
+ output: output
+ };
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * Block shorthand logic tokens.
+ *
+ * Format: {% block title expression %}
+ */</span>
+ type: Twig.logic.type.shortblock,
+ regex: <span class="hljs-regexp">/^block\s+([a-zA-Z0-9_]+)\s+(.+)$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ token.expression = token.match[<span class="hljs-number">2</span>].trim();
+
+ token.output = Twig.expression.compile({
+ type: Twig.expression.type.expression,
+ value: token.expression
+ }).stack;
+
+ token.block = token.match[<span class="hljs-number">1</span>].trim();
+ <span class="hljs-keyword">delete</span> token.match;
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{
+ <span class="hljs-keyword">return</span> Twig.logic.handler[Twig.logic.type.block].parse.apply(<span class="hljs-keyword">this</span>, <span class="hljs-built_in">arguments</span>);
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * End block logic tokens.
+ *
+ * Format: {% endblock %}
+ */</span>
+ type: Twig.logic.type.endblock,
+ regex: <span class="hljs-regexp">/^endblock(?:\s+([a-zA-Z0-9_]+))?$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">false</span>
+ },
+ {
+ <span class="hljs-comment">/**
+ * Block logic tokens.
+ *
+ * Format: {% extends "template.twig" %}
+ */</span>
+ type: Twig.logic.type.extends_,
+ regex: <span class="hljs-regexp">/^extends\s+(.+)$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ <span class="hljs-keyword">var</span> expression = token.match[<span class="hljs-number">1</span>].trim();
+ <span class="hljs-keyword">delete</span> token.match;
+
+ token.stack = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: expression
+ }]).stack;
+
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-202">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-202">&#182;</a>
+ </div>
+ <p>Resolve filename</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> file = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.stack, context]);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-203">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-203">&#182;</a>
+ </div>
+ <p>Set parent template</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">this</span>.extend = file;
+
+ <span class="hljs-keyword">return</span> {
+ chain: chain,
+ output: <span class="hljs-string">''</span>
+ };
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * Block logic tokens.
+ *
+ * Format: {% use "template.twig" %}
+ */</span>
+ type: Twig.logic.type.use,
+ regex: <span class="hljs-regexp">/^use\s+(.+)$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ <span class="hljs-keyword">var</span> expression = token.match[<span class="hljs-number">1</span>].trim();
+ <span class="hljs-keyword">delete</span> token.match;
+
+ token.stack = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: expression
+ }]).stack;
+
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-204">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-204">&#182;</a>
+ </div>
+ <p>Resolve filename</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> file = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.stack, context]);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-205">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-205">&#182;</a>
+ </div>
+ <p>Import blocks</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">this</span>.importBlocks(file);
+
+ <span class="hljs-keyword">return</span> {
+ chain: chain,
+ output: <span class="hljs-string">''</span>
+ };
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * Block logic tokens.
+ *
+ * Format: {% includes "template.twig" [with {some: 'values'} only] %}
+ */</span>
+ type: Twig.logic.type.include,
+ regex: <span class="hljs-regexp">/^include\s+(ignore missing\s+)?(.+?)\s*(?:with\s+([\S\s]+?))?\s*(only)?$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ <span class="hljs-keyword">var</span> match = token.match,
+ includeMissing = match[<span class="hljs-number">1</span>] !== <span class="hljs-literal">undefined</span>,
+ expression = match[<span class="hljs-number">2</span>].trim(),
+ withContext = match[<span class="hljs-number">3</span>],
+ only = ((match[<span class="hljs-number">4</span>] !== <span class="hljs-literal">undefined</span>) &amp;&amp; match[<span class="hljs-number">4</span>].length);
+
+ <span class="hljs-keyword">delete</span> token.match;
+
+ token.only = only;
+ token.includeMissing = includeMissing;
+
+ token.stack = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: expression
+ }]).stack;
+
+ <span class="hljs-keyword">if</span> (withContext !== <span class="hljs-literal">undefined</span>) {
+ token.withStack = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: withContext.trim()
+ }]).stack;
+ }
+
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-206">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-206">&#182;</a>
+ </div>
+ <p>Resolve filename</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> innerContext = {},
+ withContext,
+ i,
+ template;
+
+ <span class="hljs-keyword">if</span> (!token.only) {
+ innerContext = Twig.ChildContext(context);
+ }
+
+ <span class="hljs-keyword">if</span> (token.withStack !== <span class="hljs-literal">undefined</span>) {
+ withContext = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.withStack, context]);
+
+ <span class="hljs-keyword">for</span> (i <span class="hljs-keyword">in</span> withContext) {
+ <span class="hljs-keyword">if</span> (withContext.hasOwnProperty(i))
+ innerContext[i] = withContext[i];
+ }
+ }
+
+ <span class="hljs-keyword">var</span> file = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.stack, innerContext]);
+
+ <span class="hljs-keyword">if</span> (file <span class="hljs-keyword">instanceof</span> Twig.Template) {
+ template = file;
+ } <span class="hljs-keyword">else</span> {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-207">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-207">&#182;</a>
+ </div>
+ <p>Import file</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> template = <span class="hljs-keyword">this</span>.importFile(file);
+ }
+
+ <span class="hljs-keyword">return</span> {
+ chain: chain,
+ output: template.render(innerContext)
+ };
+ }
+ },
+ {
+ type: Twig.logic.type.spaceless,
+ regex: <span class="hljs-regexp">/^spaceless$/</span>,
+ next: [
+ Twig.logic.type.endspaceless
+ ],
+ open: <span class="hljs-literal">true</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-208">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-208">&#182;</a>
+ </div>
+ <p>Parse the html and return it without any spaces between tags</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{
+ <span class="hljs-keyword">var</span> <span class="hljs-comment">// Parse the output without any filter</span>
+ unfiltered = Twig.parse.apply(<span class="hljs-keyword">this</span>, [token.output, context]),</pre></div></div>
+
+ </li>
+
+
+ <li id="section-209">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-209">&#182;</a>
+ </div>
+ <p>A regular expression to find closing and opening tags with spaces between them</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> rBetweenTagSpaces = <span class="hljs-regexp">/&gt;\s+&lt;/g</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-210">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-210">&#182;</a>
+ </div>
+ <p>Replace all space between closing and opening html tags</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> output = unfiltered.replace(rBetweenTagSpaces,<span class="hljs-string">'&gt;&lt;'</span>).trim();
+
+ <span class="hljs-keyword">return</span> {
+ chain: chain,
+ output: output
+ };
+ }
+ },</pre></div></div>
+
+ </li>
+
+
+ <li id="section-211">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-211">&#182;</a>
+ </div>
+ <p>Add the {% endspaceless %} token</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> {
+ type: Twig.logic.type.endspaceless,
+ regex: <span class="hljs-regexp">/^endspaceless$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">false</span>
+ },
+ {
+ <span class="hljs-comment">/**
+ * Macro logic tokens.
+ *
+ * Format: {% maro input(name, value, type, size) %}
+ *
+ */</span>
+ type: Twig.logic.type.macro,
+ regex: <span class="hljs-regexp">/^macro\s+([a-zA-Z0-9_]+)\s*\(\s*((?:[a-zA-Z0-9_]+(?:,\s*)?)*)\s*\)$/</span>,
+ next: [
+ Twig.logic.type.endmacro
+ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ <span class="hljs-keyword">var</span> macroName = token.match[<span class="hljs-number">1</span>],
+ parameters = token.match[<span class="hljs-number">2</span>].split(<span class="hljs-regexp">/[\s,]+/</span>);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-212">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-212">&#182;</a>
+ </div>
+ <p>TODO: Clean up duplicate check</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i=<span class="hljs-number">0</span>; i&lt;parameters.length; i++) {
+ <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> j=<span class="hljs-number">0</span>; j&lt;parameters.length; j++){
+ <span class="hljs-keyword">if</span> (parameters[i] === parameters[j] &amp;&amp; i !== j) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Duplicate arguments for parameter: "</span>+ parameters[i]);
+ }
+ }
+ }
+
+ token.macroName = macroName;
+ token.parameters = parameters;
+
+ <span class="hljs-keyword">delete</span> token.match;
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{
+ <span class="hljs-keyword">var</span> template = <span class="hljs-keyword">this</span>;
+ <span class="hljs-keyword">this</span>.macros[token.macroName] = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-213">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-213">&#182;</a>
+ </div>
+ <p>Pass global context and other macros</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> macroContext = {
+ _self: template.macros
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-214">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-214">&#182;</a>
+ </div>
+ <p>Add parameters from context to macroContext</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i=<span class="hljs-number">0</span>; i&lt;token.parameters.length; i++) {
+ <span class="hljs-keyword">var</span> prop = token.parameters[i];
+ <span class="hljs-keyword">if</span>(<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">arguments</span>[i] !== <span class="hljs-string">'undefined'</span>) {
+ macroContext[prop] = <span class="hljs-built_in">arguments</span>[i];
+ } <span class="hljs-keyword">else</span> {
+ macroContext[prop] = <span class="hljs-literal">undefined</span>;
+ }
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-215">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-215">&#182;</a>
+ </div>
+ <p>Render</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> Twig.parse.apply(template, [token.output, macroContext])
+ };
+
+ <span class="hljs-keyword">return</span> {
+ chain: chain,
+ output: <span class="hljs-string">''</span>
+ };
+
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * End macro logic tokens.
+ *
+ * Format: {% endmacro %}
+ */</span>
+ type: Twig.logic.type.endmacro,
+ regex: <span class="hljs-regexp">/^endmacro$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">false</span>
+ },
+ {
+ <span class="hljs-comment">/*
+ * import logic tokens.
+ *
+ * Format: {% import "template.twig" as form %}
+ */</span>
+ type: Twig.logic.type.import_,
+ regex: <span class="hljs-regexp">/^import\s+(.+)\s+as\s+([a-zA-Z0-9_]+)$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ <span class="hljs-keyword">var</span> expression = token.match[<span class="hljs-number">1</span>].trim(),
+ contextName = token.match[<span class="hljs-number">2</span>].trim();
+ <span class="hljs-keyword">delete</span> token.match;
+
+ token.expression = expression;
+ token.contextName = contextName;
+
+ token.stack = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: expression
+ }]).stack;
+
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{
+ <span class="hljs-keyword">if</span> (token.expression !== <span class="hljs-string">"_self"</span>) {
+ <span class="hljs-keyword">var</span> file = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.stack, context]);
+ <span class="hljs-keyword">var</span> template = <span class="hljs-keyword">this</span>.importFile(file || token.expression);
+ context[token.contextName] = template.render({}, {output: <span class="hljs-string">'macros'</span>});
+ }
+ <span class="hljs-keyword">else</span> {
+ context[token.contextName] = <span class="hljs-keyword">this</span>.macros;
+ }
+
+ <span class="hljs-keyword">return</span> {
+ chain: chain,
+ output: <span class="hljs-string">''</span>
+ }
+
+ }
+ },
+ {
+ <span class="hljs-comment">/*
+ * from logic tokens.
+ *
+ * Format: {% from "template.twig" import func as form %}
+ */</span>
+ type: Twig.logic.type.from,
+ regex: <span class="hljs-regexp">/^from\s+(.+)\s+import\s+([a-zA-Z0-9_, ]+)$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ <span class="hljs-keyword">var</span> expression = token.match[<span class="hljs-number">1</span>].trim(),
+ macroExpressions = token.match[<span class="hljs-number">2</span>].trim().split(<span class="hljs-regexp">/[ ,]+/</span>),
+ macroNames = {};
+
+ <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i=<span class="hljs-number">0</span>; i&lt;macroExpressions.length; i++) {
+ <span class="hljs-keyword">var</span> res = macroExpressions[i];</pre></div></div>
+
+ </li>
+
+
+ <li id="section-216">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-216">&#182;</a>
+ </div>
+ <p>match function as variable</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> macroMatch = res.match(<span class="hljs-regexp">/^([a-zA-Z0-9_]+)\s+(.+)\s+as\s+([a-zA-Z0-9_]+)$/</span>);
+ <span class="hljs-keyword">if</span> (macroMatch) {
+ macroNames[macroMatch[<span class="hljs-number">1</span>].trim()] = macroMatch[<span class="hljs-number">2</span>].trim();
+ }
+ <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (res.match(<span class="hljs-regexp">/^([a-zA-Z0-9_]+)$/</span>)) {
+ macroNames[res] = res;
+ }
+ <span class="hljs-keyword">else</span> {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-217">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-217">&#182;</a>
+ </div>
+ <p>ignore import</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> }
+
+ }
+
+ <span class="hljs-keyword">delete</span> token.match;
+
+ token.expression = expression;
+ token.macroNames = macroNames;
+
+ token.stack = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: expression
+ }]).stack;
+
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{
+ <span class="hljs-keyword">var</span> macros;
+
+ <span class="hljs-keyword">if</span> (token.expression !== <span class="hljs-string">"_self"</span>) {
+ <span class="hljs-keyword">var</span> file = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.stack, context]);
+ <span class="hljs-keyword">var</span> template = <span class="hljs-keyword">this</span>.importFile(file || token.expression);
+ macros = template.render({}, {output: <span class="hljs-string">'macros'</span>});
+ }
+ <span class="hljs-keyword">else</span> {
+ macros = <span class="hljs-keyword">this</span>.macros;
+ }
+
+ <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> macroName <span class="hljs-keyword">in</span> token.macroNames) {
+ <span class="hljs-keyword">if</span> (macros.hasOwnProperty(macroName)) {
+ context[token.macroNames[macroName]] = macros[macroName];
+ }
+ }
+
+ <span class="hljs-keyword">return</span> {
+ chain: chain,
+ output: <span class="hljs-string">''</span>
+ }
+
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * The embed tag combines the behaviour of include and extends.
+ * It allows you to include another template's contents, just like include does.
+ *
+ * Format: {% embed "template.twig" [with {some: 'values'} only] %}
+ */</span>
+ type: Twig.logic.type.embed,
+ regex: <span class="hljs-regexp">/^embed\s+(ignore missing\s+)?(.+?)\s*(?:with\s+(.+?))?\s*(only)?$/</span>,
+ next: [
+ Twig.logic.type.endembed
+ ],
+ open: <span class="hljs-literal">true</span>,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ <span class="hljs-keyword">var</span> match = token.match,
+ includeMissing = match[<span class="hljs-number">1</span>] !== <span class="hljs-literal">undefined</span>,
+ expression = match[<span class="hljs-number">2</span>].trim(),
+ withContext = match[<span class="hljs-number">3</span>],
+ only = ((match[<span class="hljs-number">4</span>] !== <span class="hljs-literal">undefined</span>) &amp;&amp; match[<span class="hljs-number">4</span>].length);
+
+ <span class="hljs-keyword">delete</span> token.match;
+
+ token.only = only;
+ token.includeMissing = includeMissing;
+
+ token.stack = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: expression
+ }]).stack;
+
+ <span class="hljs-keyword">if</span> (withContext !== <span class="hljs-literal">undefined</span>) {
+ token.withStack = Twig.expression.compile.apply(<span class="hljs-keyword">this</span>, [{
+ type: Twig.expression.type.expression,
+ value: withContext.trim()
+ }]).stack;
+ }
+
+ <span class="hljs-keyword">return</span> token;
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-218">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-218">&#182;</a>
+ </div>
+ <p>Resolve filename</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> innerContext = {},
+ withContext,
+ i,
+ template;
+
+ <span class="hljs-keyword">if</span> (!token.only) {
+ <span class="hljs-keyword">for</span> (i <span class="hljs-keyword">in</span> context) {
+ <span class="hljs-keyword">if</span> (context.hasOwnProperty(i))
+ innerContext[i] = context[i];
+ }
+ }
+
+ <span class="hljs-keyword">if</span> (token.withStack !== <span class="hljs-literal">undefined</span>) {
+ withContext = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.withStack, context]);
+
+ <span class="hljs-keyword">for</span> (i <span class="hljs-keyword">in</span> withContext) {
+ <span class="hljs-keyword">if</span> (withContext.hasOwnProperty(i))
+ innerContext[i] = withContext[i];
+ }
+ }
+
+ <span class="hljs-keyword">var</span> file = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.stack, innerContext]);
+
+ <span class="hljs-keyword">if</span> (file <span class="hljs-keyword">instanceof</span> Twig.Template) {
+ template = file;
+ } <span class="hljs-keyword">else</span> {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-219">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-219">&#182;</a>
+ </div>
+ <p>Import file</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> template = <span class="hljs-keyword">this</span>.importFile(file);
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-220">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-220">&#182;</a>
+ </div>
+ <p>reset previous blocks</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">this</span>.blocks = {};</pre></div></div>
+
+ </li>
+
+
+ <li id="section-221">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-221">&#182;</a>
+ </div>
+ <p>parse tokens. output will be not used</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> output = Twig.parse.apply(<span class="hljs-keyword">this</span>, [token.output, innerContext]);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-222">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-222">&#182;</a>
+ </div>
+ <p>render tempalte with blocks defined in embed block</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> {
+ chain: chain,
+ output: template.render(innerContext, {<span class="hljs-string">'blocks'</span>:<span class="hljs-keyword">this</span>.blocks})
+ };
+ }
+ },
+ <span class="hljs-comment">/* Add the {% endembed %} token
+ *
+ */</span>
+ {
+ type: Twig.logic.type.endembed,
+ regex: <span class="hljs-regexp">/^endembed$/</span>,
+ next: [ ],
+ open: <span class="hljs-literal">false</span>
+ }
+
+ ];
+
+
+ <span class="hljs-comment">/**
+ * Registry for logic handlers.
+ */</span>
+ Twig.logic.handler = {};
+
+ <span class="hljs-comment">/**
+ * Define a new token type, available at Twig.logic.type.{type}
+ */</span>
+ Twig.logic.extendType = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">type, value</span>) </span>{
+ value = value || (<span class="hljs-string">"Twig.logic.type"</span> + type);
+ Twig.logic.type[type] = value;
+ };
+
+ <span class="hljs-comment">/**
+ * Extend the logic parsing functionality with a new token definition.
+ *
+ * // Define a new tag
+ * Twig.logic.extend({
+ * type: Twig.logic.type.{type},
+ * // The pattern to match for this token
+ * regex: ...,
+ * // What token types can follow this token, leave blank if any.
+ * next: [ ... ]
+ * // Create and return compiled version of the token
+ * compile: function(token) { ... }
+ * // Parse the compiled token with the context provided by the render call
+ * // and whether this token chain is complete.
+ * parse: function(token, context, chain) { ... }
+ * });
+ *
+ * @param {Object} definition The new logic expression.
+ */</span>
+ Twig.logic.extend = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">definition</span>) </span>{
+
+ <span class="hljs-keyword">if</span> (!definition.type) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Unable to extend logic definition. No type provided for "</span> + definition);
+ } <span class="hljs-keyword">else</span> {
+ Twig.logic.extendType(definition.type);
+ }
+ Twig.logic.handler[definition.type] = definition;
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-223">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-223">&#182;</a>
+ </div>
+ <p>Extend with built-in expressions</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">while</span> (Twig.logic.definitions.length &gt; <span class="hljs-number">0</span>) {
+ Twig.logic.extend(Twig.logic.definitions.shift());
+ }
+
+ <span class="hljs-comment">/**
+ * Compile a logic token into an object ready for parsing.
+ *
+ * @param {Object} raw_token An uncompiled logic token.
+ *
+ * @return {Object} A compiled logic token, ready for parsing.
+ */</span>
+ Twig.logic.compile = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">raw_token</span>) </span>{
+ <span class="hljs-keyword">var</span> expression = raw_token.value.trim(),
+ token = Twig.logic.tokenize.apply(<span class="hljs-keyword">this</span>, [expression]),
+ token_template = Twig.logic.handler[token.type];</pre></div></div>
+
+ </li>
+
+
+ <li id="section-224">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-224">&#182;</a>
+ </div>
+ <p>Check if the token needs compiling</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (token_template.compile) {
+ token = token_template.compile.apply(<span class="hljs-keyword">this</span>, [token]);
+ Twig.log.trace(<span class="hljs-string">"Twig.logic.compile: "</span>, <span class="hljs-string">"Compiled logic token to "</span>, token);
+ }
+
+ <span class="hljs-keyword">return</span> token;
+ };
+
+ <span class="hljs-comment">/**
+ * Tokenize logic expressions. This function matches token expressions against regular
+ * expressions provided in token definitions provided with Twig.logic.extend.
+ *
+ * @param {string} expression the logic token expression to tokenize
+ * (i.e. what's between {% and %})
+ *
+ * @return {Object} The matched token with type set to the token type and match to the regex match.
+ */</span>
+ Twig.logic.tokenize = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">expression</span>) </span>{
+ <span class="hljs-keyword">var</span> token = {},
+ token_template_type = <span class="hljs-literal">null</span>,
+ token_type = <span class="hljs-literal">null</span>,
+ token_regex = <span class="hljs-literal">null</span>,
+ regex_array = <span class="hljs-literal">null</span>,
+ regex = <span class="hljs-literal">null</span>,
+ match = <span class="hljs-literal">null</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-225">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-225">&#182;</a>
+ </div>
+ <p>Ignore whitespace around expressions.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> expression = expression.trim();
+
+ <span class="hljs-keyword">for</span> (token_template_type <span class="hljs-keyword">in</span> Twig.logic.handler) {
+ <span class="hljs-keyword">if</span> (Twig.logic.handler.hasOwnProperty(token_template_type)) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-226">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-226">&#182;</a>
+ </div>
+ <p>Get the type and regex for this template type</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> token_type = Twig.logic.handler[token_template_type].type;
+ token_regex = Twig.logic.handler[token_template_type].regex;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-227">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-227">&#182;</a>
+ </div>
+ <p>Handle multiple regular expressions per type.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> regex_array = [];
+ <span class="hljs-keyword">if</span> (token_regex <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Array</span>) {
+ regex_array = token_regex;
+ } <span class="hljs-keyword">else</span> {
+ regex_array.push(token_regex);
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-228">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-228">&#182;</a>
+ </div>
+ <p>Check regular expressions in the order they were specified in the definition.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">while</span> (regex_array.length &gt; <span class="hljs-number">0</span>) {
+ regex = regex_array.shift();
+ match = regex.exec(expression.trim());
+ <span class="hljs-keyword">if</span> (match !== <span class="hljs-literal">null</span>) {
+ token.type = token_type;
+ token.match = match;
+ Twig.log.trace(<span class="hljs-string">"Twig.logic.tokenize: "</span>, <span class="hljs-string">"Matched a "</span>, token_type, <span class="hljs-string">" regular expression of "</span>, match);
+ <span class="hljs-keyword">return</span> token;
+ }
+ }
+ }
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-229">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-229">&#182;</a>
+ </div>
+ <p>No regex matches</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Unable to parse '"</span> + expression.trim() + <span class="hljs-string">"'"</span>);
+ };
+
+ <span class="hljs-comment">/**
+ * Parse a logic token within a given context.
+ *
+ * What are logic chains?
+ * Logic chains represent a series of tokens that are connected,
+ * for example:
+ * {% if ... %} {% else %} {% endif %}
+ *
+ * The chain parameter is used to signify if a chain is open of closed.
+ * open:
+ * More tokens in this chain should be parsed.
+ * closed:
+ * This token chain has completed parsing and any additional
+ * tokens (else, elseif, etc...) should be ignored.
+ *
+ * @param {Object} token The compiled token.
+ * @param {Object} context The render context.
+ * @param {boolean} chain Is this an open logic chain. If false, that means a
+ * chain is closed and no further cases should be parsed.
+ */</span>
+ Twig.logic.parse = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token, context, chain</span>) </span>{
+ <span class="hljs-keyword">var</span> output = <span class="hljs-string">''</span>,
+ token_template;
+
+ context = context || { };
+
+ Twig.log.debug(<span class="hljs-string">"Twig.logic.parse: "</span>, <span class="hljs-string">"Parsing logic token "</span>, token);
+
+ token_template = Twig.logic.handler[token.type];
+
+ <span class="hljs-keyword">if</span> (token_template.parse) {
+ output = token_template.parse.apply(<span class="hljs-keyword">this</span>, [token, context, chain]);
+ }
+ <span class="hljs-keyword">return</span> output;
+ };
+
+ <span class="hljs-keyword">return</span> Twig;
+
+})(Twig || { });</pre></div></div>
+
+ </li>
+
+
+ <li id="section-230">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-230">&#182;</a>
+ </div>
+ <pre><code>Twig.js
+Available under the BSD <span class="hljs-number">2</span>-Clause License
+https:<span class="hljs-comment">//github.com/justjohn/twig.js</span>
+</code></pre>
+ </div>
+
+ </li>
+
+
+ <li id="section-231">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-231">&#182;</a>
+ </div>
+ <h2 id="twig-expression-js">twig.expression.js</h2>
+<p>This file handles tokenizing, compiling and parsing expressions.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> Twig = (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Twig</span>) </span>{
+<span class="hljs-meta"> "use strict"</span>;
+
+ <span class="hljs-comment">/**
+ * Namespace for expression handling.
+ */</span>
+ Twig.expression = { };
+
+ <span class="hljs-comment">/**
+ * Reserved word that can't be used as variable names.
+ */</span>
+ Twig.expression.reservedWords = [
+ <span class="hljs-string">"true"</span>, <span class="hljs-string">"false"</span>, <span class="hljs-string">"null"</span>, <span class="hljs-string">"TRUE"</span>, <span class="hljs-string">"FALSE"</span>, <span class="hljs-string">"NULL"</span>, <span class="hljs-string">"_context"</span>
+ ];
+
+ <span class="hljs-comment">/**
+ * The type of tokens used in expressions.
+ */</span>
+ Twig.expression.type = {
+ comma: <span class="hljs-string">'Twig.expression.type.comma'</span>,
+ operator: {
+ unary: <span class="hljs-string">'Twig.expression.type.operator.unary'</span>,
+ binary: <span class="hljs-string">'Twig.expression.type.operator.binary'</span>
+ },
+ string: <span class="hljs-string">'Twig.expression.type.string'</span>,
+ bool: <span class="hljs-string">'Twig.expression.type.bool'</span>,
+ array: {
+ start: <span class="hljs-string">'Twig.expression.type.array.start'</span>,
+ end: <span class="hljs-string">'Twig.expression.type.array.end'</span>
+ },
+ object: {
+ start: <span class="hljs-string">'Twig.expression.type.object.start'</span>,
+ end: <span class="hljs-string">'Twig.expression.type.object.end'</span>
+ },
+ parameter: {
+ start: <span class="hljs-string">'Twig.expression.type.parameter.start'</span>,
+ end: <span class="hljs-string">'Twig.expression.type.parameter.end'</span>
+ },
+ key: {
+ period: <span class="hljs-string">'Twig.expression.type.key.period'</span>,
+ brackets: <span class="hljs-string">'Twig.expression.type.key.brackets'</span>
+ },
+ filter: <span class="hljs-string">'Twig.expression.type.filter'</span>,
+ _function: <span class="hljs-string">'Twig.expression.type._function'</span>,
+ variable: <span class="hljs-string">'Twig.expression.type.variable'</span>,
+ number: <span class="hljs-string">'Twig.expression.type.number'</span>,
+ _null: <span class="hljs-string">'Twig.expression.type.null'</span>,
+ context: <span class="hljs-string">'Twig.expression.type.context'</span>,
+ test: <span class="hljs-string">'Twig.expression.type.test'</span>
+ };
+
+ Twig.expression.set = {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-232">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-232">&#182;</a>
+ </div>
+ <p>What can follow an expression (in general)</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> operations: [
+ Twig.expression.type.filter,
+ Twig.expression.type.operator.unary,
+ Twig.expression.type.operator.binary,
+ Twig.expression.type.array.end,
+ Twig.expression.type.object.end,
+ Twig.expression.type.parameter.end,
+ Twig.expression.type.comma,
+ Twig.expression.type.test
+ ],
+ expressions: [
+ Twig.expression.type._function,
+ Twig.expression.type.bool,
+ Twig.expression.type.string,
+ Twig.expression.type.variable,
+ Twig.expression.type.number,
+ Twig.expression.type._null,
+ Twig.expression.type.context,
+ Twig.expression.type.parameter.start,
+ Twig.expression.type.array.start,
+ Twig.expression.type.object.start
+ ]
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-233">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-233">&#182;</a>
+ </div>
+ <p>Most expressions allow a ‘.’ or ‘[‘ after them, so we provide a convenience set</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.expression.set.operations_extended = Twig.expression.set.operations.concat([
+ Twig.expression.type.key.period,
+ Twig.expression.type.key.brackets]);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-234">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-234">&#182;</a>
+ </div>
+ <p>Some commonly used compile and parse functions.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.expression.fn = {
+ compile: {
+ push: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ output.push(token);
+ },
+ push_both: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ output.push(token);
+ stack.push(token);
+ }
+ },
+ parse: {
+ push: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, context</span>) </span>{
+ stack.push(token);
+ },
+ push_value: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, context</span>) </span>{
+ stack.push(token.value);
+ }
+ }
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-235">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-235">&#182;</a>
+ </div>
+ <p>The regular expressions and compile/parse logic used to match tokens in expressions.</p>
+<p>Properties:</p>
+<pre><code> type: The type <span class="hljs-keyword">of</span> expression <span class="hljs-keyword">this</span> matches
+
+ regex: One or more regular expressions that matche the format <span class="hljs-keyword">of</span> the token.
+
+ next: Valid tokens that can occur next <span class="hljs-keyword">in</span> the expression.
+</code></pre><p>Functions:</p>
+<pre><code> compile: A <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">that</span> <span class="hljs-title">compiles</span> <span class="hljs-title">the</span> <span class="hljs-title">raw</span> <span class="hljs-title">regular</span> <span class="hljs-title">expression</span> <span class="hljs-title">match</span> <span class="hljs-title">into</span> <span class="hljs-title">a</span> <span class="hljs-title">token</span>.
+
+ <span class="hljs-title">parse</span>: <span class="hljs-title">A</span> <span class="hljs-title">function</span> <span class="hljs-title">that</span> <span class="hljs-title">parses</span> <span class="hljs-title">the</span> <span class="hljs-title">compiled</span> <span class="hljs-title">token</span> <span class="hljs-title">into</span> <span class="hljs-title">output</span>.</span>
+</code></pre>
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.expression.definitions = [
+ {
+ type: Twig.expression.type.test,
+ regex: <span class="hljs-regexp">/^is\s+(not)?\s*([a-zA-Z_][a-zA-Z0-9_]*)/</span>,
+ next: Twig.expression.set.operations.concat([Twig.expression.type.parameter.start]),
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ token.filter = token.match[<span class="hljs-number">2</span>];
+ token.modifier = token.match[<span class="hljs-number">1</span>];
+ <span class="hljs-keyword">delete</span> token.match;
+ <span class="hljs-keyword">delete</span> token.value;
+ output.push(token);
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, context</span>) </span>{
+ <span class="hljs-keyword">var</span> value = stack.pop(),
+ params = token.params &amp;&amp; Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.params, context]),
+ result = Twig.test(token.filter, value, params);
+
+ <span class="hljs-keyword">if</span> (token.modifier == <span class="hljs-string">'not'</span>) {
+ stack.push(!result);
+ } <span class="hljs-keyword">else</span> {
+ stack.push(result);
+ }
+ }
+ },
+ {
+ type: Twig.expression.type.comma,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-236">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-236">&#182;</a>
+ </div>
+ <p>Match a comma</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> regex: <span class="hljs-regexp">/^,/</span>,
+ next: Twig.expression.set.expressions.concat([Twig.expression.type.array.end, Twig.expression.type.object.end]),
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ <span class="hljs-keyword">var</span> i = stack.length - <span class="hljs-number">1</span>,
+ stack_token;
+
+ <span class="hljs-keyword">delete</span> token.match;
+ <span class="hljs-keyword">delete</span> token.value;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-237">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-237">&#182;</a>
+ </div>
+ <p>pop tokens off the stack until the start of the object</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span>(;i &gt;= <span class="hljs-number">0</span>; i--) {
+ stack_token = stack.pop();
+ <span class="hljs-keyword">if</span> (stack_token.type === Twig.expression.type.object.start
+ || stack_token.type === Twig.expression.type.parameter.start
+ || stack_token.type === Twig.expression.type.array.start) {
+ stack.push(stack_token);
+ <span class="hljs-keyword">break</span>;
+ }
+ output.push(stack_token);
+ }
+ output.push(token);
+ }
+ },
+ {
+ type: Twig.expression.type.operator.binary,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-238">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-238">&#182;</a>
+ </div>
+ <p>Match any of +, <em>, /, -, %, ~, &lt;, &lt;=, &gt;, &gt;=, !=, ==, *</em>, ?, :, and, or, not</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> regex: <span class="hljs-regexp">/(^[\+\-~%\?\:]|^[!=]==?|^[!&lt;&gt;]=?|^\*\*?|^\/\/?|^and\s+|^or\s+|^in\s+|^not in\s+|^\.\.)/</span>,
+ next: Twig.expression.set.expressions.concat([Twig.expression.type.operator.unary]),
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ <span class="hljs-keyword">delete</span> token.match;
+
+ token.value = token.value.trim();
+ <span class="hljs-keyword">var</span> value = token.value,
+ operator = Twig.expression.operator.lookup(value, token);
+
+ Twig.log.trace(<span class="hljs-string">"Twig.expression.compile: "</span>, <span class="hljs-string">"Operator: "</span>, operator, <span class="hljs-string">" from "</span>, value);
+
+ <span class="hljs-keyword">while</span> (stack.length &gt; <span class="hljs-number">0</span> &amp;&amp;
+ (stack[stack.length<span class="hljs-number">-1</span>].type == Twig.expression.type.operator.unary || stack[stack.length<span class="hljs-number">-1</span>].type == Twig.expression.type.operator.binary) &amp;&amp;
+ (
+ (operator.associativity === Twig.expression.operator.leftToRight &amp;&amp;
+ operator.precidence &gt;= stack[stack.length<span class="hljs-number">-1</span>].precidence) ||
+
+ (operator.associativity === Twig.expression.operator.rightToLeft &amp;&amp;
+ operator.precidence &gt; stack[stack.length<span class="hljs-number">-1</span>].precidence)
+ )
+ ) {
+ <span class="hljs-keyword">var</span> temp = stack.pop();
+ output.push(temp);
+ }
+
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-string">":"</span>) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-239">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-239">&#182;</a>
+ </div>
+ <p>Check if this is a ternary or object key being set</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (stack[stack.length - <span class="hljs-number">1</span>] &amp;&amp; stack[stack.length<span class="hljs-number">-1</span>].value === <span class="hljs-string">"?"</span>) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-240">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-240">&#182;</a>
+ </div>
+ <p>Continue as normal for a ternary</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> } <span class="hljs-keyword">else</span> {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-241">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-241">&#182;</a>
+ </div>
+ <p>This is not a ternary so we push the token to the output where it can be handled
+ when the assocated object is closed.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> key_token = output.pop();
+
+ <span class="hljs-keyword">if</span> (key_token.type === Twig.expression.type.string ||
+ key_token.type === Twig.expression.type.variable) {
+ token.key = key_token.value;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (key_token.type === Twig.expression.type.number) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-242">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-242">&#182;</a>
+ </div>
+ <p>Convert integer keys into string keys</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> token.key = key_token.value.toString();
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (key_token.type === Twig.expression.type.parameter.end &amp;&amp;
+ key_token.expression) {
+ token.params = key_token.params;
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Unexpected value before ':' of "</span> + key_token.type + <span class="hljs-string">" = "</span> + key_token.value);
+ }
+
+ output.push(token);
+ <span class="hljs-keyword">return</span>;
+ }
+ } <span class="hljs-keyword">else</span> {
+ stack.push(operator);
+ }
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, context</span>) </span>{
+ <span class="hljs-keyword">if</span> (token.key) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-243">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-243">&#182;</a>
+ </div>
+ <p>handle ternary ‘:’ operator</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> stack.push(token);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (token.params) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-244">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-244">&#182;</a>
+ </div>
+ <p>handle “{(expression):value}”</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> token.key = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.params, context]);
+ stack.push(token);
+ <span class="hljs-keyword">delete</span>(token.params);
+ } <span class="hljs-keyword">else</span> {
+ Twig.expression.operator.parse(token.value, stack);
+ }
+ }
+ },
+ {
+ type: Twig.expression.type.operator.unary,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-245">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-245">&#182;</a>
+ </div>
+ <p>Match any of not</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> regex: <span class="hljs-regexp">/(^not\s+)/</span>,
+ next: Twig.expression.set.expressions,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ <span class="hljs-keyword">delete</span> token.match;
+
+ token.value = token.value.trim();
+ <span class="hljs-keyword">var</span> value = token.value,
+ operator = Twig.expression.operator.lookup(value, token);
+
+ Twig.log.trace(<span class="hljs-string">"Twig.expression.compile: "</span>, <span class="hljs-string">"Operator: "</span>, operator, <span class="hljs-string">" from "</span>, value);
+
+ <span class="hljs-keyword">while</span> (stack.length &gt; <span class="hljs-number">0</span> &amp;&amp;
+ (stack[stack.length<span class="hljs-number">-1</span>].type == Twig.expression.type.operator.unary || stack[stack.length<span class="hljs-number">-1</span>].type == Twig.expression.type.operator.binary) &amp;&amp;
+ (
+ (operator.associativity === Twig.expression.operator.leftToRight &amp;&amp;
+ operator.precidence &gt;= stack[stack.length<span class="hljs-number">-1</span>].precidence) ||
+
+ (operator.associativity === Twig.expression.operator.rightToLeft &amp;&amp;
+ operator.precidence &gt; stack[stack.length<span class="hljs-number">-1</span>].precidence)
+ )
+ ) {
+ <span class="hljs-keyword">var</span> temp = stack.pop();
+ output.push(temp);
+ }
+
+ stack.push(operator);
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, context</span>) </span>{
+ Twig.expression.operator.parse(token.value, stack);
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * Match a string. This is anything between a pair of single or double quotes.
+ */</span>
+ type: Twig.expression.type.string,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-246">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-246">&#182;</a>
+ </div>
+ <p>See: <a href="http://blog.stevenlevithan.com/archives/match-quoted-string">http://blog.stevenlevithan.com/archives/match-quoted-string</a></p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> regex: <span class="hljs-regexp">/^(["'])(?:(?=(\\?))\2[\s\S])*?\1/</span>,
+ next: Twig.expression.set.operations,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ <span class="hljs-keyword">var</span> value = token.value;
+ <span class="hljs-keyword">delete</span> token.match</pre></div></div>
+
+ </li>
+
+
+ <li id="section-247">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-247">&#182;</a>
+ </div>
+ <p>Remove the quotes from the string</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (value.substring(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>) === <span class="hljs-string">'"'</span>) {
+ value = value.replace(<span class="hljs-string">'\\"'</span>, <span class="hljs-string">'"'</span>);
+ } <span class="hljs-keyword">else</span> {
+ value = value.replace(<span class="hljs-string">"\\'"</span>, <span class="hljs-string">"'"</span>);
+ }
+ token.value = value.substring(<span class="hljs-number">1</span>, value.length<span class="hljs-number">-1</span>).replace( <span class="hljs-regexp">/\\n/g</span>, <span class="hljs-string">"\n"</span> ).replace( <span class="hljs-regexp">/\\r/g</span>, <span class="hljs-string">"\r"</span> );
+ Twig.log.trace(<span class="hljs-string">"Twig.expression.compile: "</span>, <span class="hljs-string">"String value: "</span>, token.value);
+ output.push(token);
+ },
+ parse: Twig.expression.fn.parse.push_value
+ },
+ {
+ <span class="hljs-comment">/**
+ * Match a parameter set start.
+ */</span>
+ type: Twig.expression.type.parameter.start,
+ regex: <span class="hljs-regexp">/^\(/</span>,
+ next: Twig.expression.set.expressions.concat([Twig.expression.type.parameter.end]),
+ compile: Twig.expression.fn.compile.push_both,
+ parse: Twig.expression.fn.parse.push
+ },
+ {
+ <span class="hljs-comment">/**
+ * Match a parameter set end.
+ */</span>
+ type: Twig.expression.type.parameter.end,
+ regex: <span class="hljs-regexp">/^\)/</span>,
+ next: Twig.expression.set.operations_extended,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ <span class="hljs-keyword">var</span> stack_token,
+ end_token = token;
+
+ stack_token = stack.pop();
+ <span class="hljs-keyword">while</span>(stack.length &gt; <span class="hljs-number">0</span> &amp;&amp; stack_token.type != Twig.expression.type.parameter.start) {
+ output.push(stack_token);
+ stack_token = stack.pop();
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-248">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-248">&#182;</a>
+ </div>
+ <p>Move contents of parens into preceding filter</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> param_stack = [];
+ <span class="hljs-keyword">while</span>(token.type !== Twig.expression.type.parameter.start) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-249">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-249">&#182;</a>
+ </div>
+ <p>Add token to arguments stack</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> param_stack.unshift(token);
+ token = output.pop();
+ }
+ param_stack.unshift(token);
+
+ <span class="hljs-keyword">var</span> is_expression = <span class="hljs-literal">false</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-250">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-250">&#182;</a>
+ </div>
+ <p>Get the token preceding the parameters</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> token = output[output.length<span class="hljs-number">-1</span>];
+
+ <span class="hljs-keyword">if</span> (token === <span class="hljs-literal">undefined</span> ||
+ (token.type !== Twig.expression.type._function &amp;&amp;
+ token.type !== Twig.expression.type.filter &amp;&amp;
+ token.type !== Twig.expression.type.test &amp;&amp;
+ token.type !== Twig.expression.type.key.brackets &amp;&amp;
+ token.type !== Twig.expression.type.key.period)) {
+
+ end_token.expression = <span class="hljs-literal">true</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-251">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-251">&#182;</a>
+ </div>
+ <p>remove start and end token from stack</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> param_stack.pop();
+ param_stack.shift();
+
+ end_token.params = param_stack;
+
+ output.push(end_token);
+
+ } <span class="hljs-keyword">else</span> {
+ end_token.expression = <span class="hljs-literal">false</span>;
+ token.params = param_stack;
+ }
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, context</span>) </span>{
+ <span class="hljs-keyword">var</span> new_array = [],
+ array_ended = <span class="hljs-literal">false</span>,
+ value = <span class="hljs-literal">null</span>;
+
+ <span class="hljs-keyword">if</span> (token.expression) {
+ value = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.params, context])
+ stack.push(value);
+
+ } <span class="hljs-keyword">else</span> {
+
+ <span class="hljs-keyword">while</span> (stack.length &gt; <span class="hljs-number">0</span>) {
+ value = stack.pop();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-252">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-252">&#182;</a>
+ </div>
+ <p>Push values into the array until the start of the array</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (value &amp;&amp; value.type &amp;&amp; value.type == Twig.expression.type.parameter.start) {
+ array_ended = <span class="hljs-literal">true</span>;
+ <span class="hljs-keyword">break</span>;
+ }
+ new_array.unshift(value);
+ }
+
+ <span class="hljs-keyword">if</span> (!array_ended) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Expected end of parameter set."</span>);
+ }
+
+ stack.push(new_array);
+ }
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * Match an array start.
+ */</span>
+ type: Twig.expression.type.array.start,
+ regex: <span class="hljs-regexp">/^\[/</span>,
+ next: Twig.expression.set.expressions.concat([Twig.expression.type.array.end]),
+ compile: Twig.expression.fn.compile.push_both,
+ parse: Twig.expression.fn.parse.push
+ },
+ {
+ <span class="hljs-comment">/**
+ * Match an array end.
+ */</span>
+ type: Twig.expression.type.array.end,
+ regex: <span class="hljs-regexp">/^\]/</span>,
+ next: Twig.expression.set.operations_extended,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ <span class="hljs-keyword">var</span> i = stack.length - <span class="hljs-number">1</span>,
+ stack_token;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-253">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-253">&#182;</a>
+ </div>
+ <p>pop tokens off the stack until the start of the object</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span>(;i &gt;= <span class="hljs-number">0</span>; i--) {
+ stack_token = stack.pop();
+ <span class="hljs-keyword">if</span> (stack_token.type === Twig.expression.type.array.start) {
+ <span class="hljs-keyword">break</span>;
+ }
+ output.push(stack_token);
+ }
+ output.push(token);
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, context</span>) </span>{
+ <span class="hljs-keyword">var</span> new_array = [],
+ array_ended = <span class="hljs-literal">false</span>,
+ value = <span class="hljs-literal">null</span>;
+
+ <span class="hljs-keyword">while</span> (stack.length &gt; <span class="hljs-number">0</span>) {
+ value = stack.pop();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-254">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-254">&#182;</a>
+ </div>
+ <p>Push values into the array until the start of the array</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (value.type &amp;&amp; value.type == Twig.expression.type.array.start) {
+ array_ended = <span class="hljs-literal">true</span>;
+ <span class="hljs-keyword">break</span>;
+ }
+ new_array.unshift(value);
+ }
+ <span class="hljs-keyword">if</span> (!array_ended) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Expected end of array."</span>);
+ }
+
+ stack.push(new_array);
+ }
+ },</pre></div></div>
+
+ </li>
+
+
+ <li id="section-255">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-255">&#182;</a>
+ </div>
+ <p>Token that represents the start of a hash map ‘}’</p>
+<p>Hash maps take the form:
+ { “key”: ‘value’, “another_key”: item }</p>
+<p>Keys must be quoted (either single or double) and values can be any expression.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> {
+ type: Twig.expression.type.object.start,
+ regex: <span class="hljs-regexp">/^\{/</span>,
+ next: Twig.expression.set.expressions.concat([Twig.expression.type.object.end]),
+ compile: Twig.expression.fn.compile.push_both,
+ parse: Twig.expression.fn.parse.push
+ },</pre></div></div>
+
+ </li>
+
+
+ <li id="section-256">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-256">&#182;</a>
+ </div>
+ <p>Token that represents the end of a Hash Map ‘}’</p>
+<p>This is where the logic for building the internal
+representation of a hash map is defined.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> {
+ type: Twig.expression.type.object.end,
+ regex: <span class="hljs-regexp">/^\}/</span>,
+ next: Twig.expression.set.operations_extended,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ <span class="hljs-keyword">var</span> i = stack.length<span class="hljs-number">-1</span>,
+ stack_token;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-257">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-257">&#182;</a>
+ </div>
+ <p>pop tokens off the stack until the start of the object</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span>(;i &gt;= <span class="hljs-number">0</span>; i--) {
+ stack_token = stack.pop();
+ <span class="hljs-keyword">if</span> (stack_token &amp;&amp; stack_token.type === Twig.expression.type.object.start) {
+ <span class="hljs-keyword">break</span>;
+ }
+ output.push(stack_token);
+ }
+ output.push(token);
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">end_token, stack, context</span>) </span>{
+ <span class="hljs-keyword">var</span> new_object = {},
+ object_ended = <span class="hljs-literal">false</span>,
+ token = <span class="hljs-literal">null</span>,
+ token_key = <span class="hljs-literal">null</span>,
+ has_value = <span class="hljs-literal">false</span>,
+ value = <span class="hljs-literal">null</span>;
+
+ <span class="hljs-keyword">while</span> (stack.length &gt; <span class="hljs-number">0</span>) {
+ token = stack.pop();</pre></div></div>
+
+ </li>
+
+
+ <li id="section-258">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-258">&#182;</a>
+ </div>
+ <p>Push values into the array until the start of the object</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (token &amp;&amp; token.type &amp;&amp; token.type === Twig.expression.type.object.start) {
+ object_ended = <span class="hljs-literal">true</span>;
+ <span class="hljs-keyword">break</span>;
+ }
+ <span class="hljs-keyword">if</span> (token &amp;&amp; token.type &amp;&amp; (token.type === Twig.expression.type.operator.binary || token.type === Twig.expression.type.operator.unary) &amp;&amp; token.key) {
+ <span class="hljs-keyword">if</span> (!has_value) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Missing value for key '"</span> + token.key + <span class="hljs-string">"' in object definition."</span>);
+ }
+ new_object[token.key] = value;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-259">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-259">&#182;</a>
+ </div>
+ <p>Preserve the order that elements are added to the map
+This is necessary since JavaScript objects don’t
+guarantee the order of keys</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (new_object._keys === <span class="hljs-literal">undefined</span>) new_object._keys = [];
+ new_object._keys.unshift(token.key);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-260">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-260">&#182;</a>
+ </div>
+ <p>reset value check</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> value = <span class="hljs-literal">null</span>;
+ has_value = <span class="hljs-literal">false</span>;
+
+ } <span class="hljs-keyword">else</span> {
+ has_value = <span class="hljs-literal">true</span>;
+ value = token;
+ }
+ }
+ <span class="hljs-keyword">if</span> (!object_ended) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Unexpected end of object."</span>);
+ }
+
+ stack.push(new_object);
+ }
+ },</pre></div></div>
+
+ </li>
+
+
+ <li id="section-261">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-261">&#182;</a>
+ </div>
+ <p>Token representing a filter</p>
+<p>Filters can follow any expression and take the form:
+ expression|filter(optional, args)</p>
+<p>Filter parsing is done in the Twig.filters namespace.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> {
+ type: Twig.expression.type.filter,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-262">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-262">&#182;</a>
+ </div>
+ <p>match a | then a letter or <em>, then any number of letters, numbers, </em> or -</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> regex: <span class="hljs-regexp">/^\|\s?([a-zA-Z_][a-zA-Z0-9_\-]*)/</span>,
+ next: Twig.expression.set.operations_extended.concat([
+ Twig.expression.type.parameter.start]),
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ token.value = token.match[<span class="hljs-number">1</span>];
+ output.push(token);
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, context</span>) </span>{
+ <span class="hljs-keyword">var</span> input = stack.pop(),
+ params = token.params &amp;&amp; Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.params, context]);
+
+ stack.push(Twig.filter.apply(<span class="hljs-keyword">this</span>, [token.value, input, params]));
+ }
+ },
+ {
+ type: Twig.expression.type._function,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-263">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-263">&#182;</a>
+ </div>
+ <p>match any letter or <em>, then any number of letters, numbers, </em> or - followed by (</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> regex: <span class="hljs-regexp">/^([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/</span>,
+ next: Twig.expression.type.parameter.start,
+ transform: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">match, tokens</span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-string">'('</span>;
+ },
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ <span class="hljs-keyword">var</span> fn = token.match[<span class="hljs-number">1</span>];
+ token.fn = fn;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-264">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-264">&#182;</a>
+ </div>
+ <p>cleanup token</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">delete</span> token.match;
+ <span class="hljs-keyword">delete</span> token.value;
+
+ output.push(token);
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, context</span>) </span>{
+ <span class="hljs-keyword">var</span> params = token.params &amp;&amp; Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.params, context]),
+ fn = token.fn,
+ value;
+
+ <span class="hljs-keyword">if</span> (Twig.functions[fn]) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-265">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-265">&#182;</a>
+ </div>
+ <p>Get the function from the built-in functions</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> value = Twig.functions[fn].apply(<span class="hljs-keyword">this</span>, params);
+
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> context[fn] == <span class="hljs-string">'function'</span>) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-266">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-266">&#182;</a>
+ </div>
+ <p>Get the function from the user/context defined functions</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> value = context[fn].apply(context, params);
+
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(fn + <span class="hljs-string">' function does not exist and is not defined in the context'</span>);
+ }
+
+ stack.push(value);
+ }
+ },</pre></div></div>
+
+ </li>
+
+
+ <li id="section-267">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-267">&#182;</a>
+ </div>
+ <p>Token representing a variable.</p>
+<p>Variables can contain letters, numbers, underscores and
+dashes, but must start with a letter or underscore.</p>
+<p>Variables are retrieved from the render context and take
+the value of ‘undefined’ if the given variable doesn’t
+exist in the context.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> {
+ type: Twig.expression.type.variable,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-268">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-268">&#182;</a>
+ </div>
+ <p>match any letter or <em>, then any number of letters, numbers, </em> or -</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> regex: <span class="hljs-regexp">/^[a-zA-Z_][a-zA-Z0-9_]*/</span>,
+ next: Twig.expression.set.operations_extended.concat([
+ Twig.expression.type.parameter.start]),
+ compile: Twig.expression.fn.compile.push,
+ validate: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">match, tokens</span>) </span>{
+ <span class="hljs-keyword">return</span> (Twig.indexOf(Twig.expression.reservedWords, match[<span class="hljs-number">0</span>]) &lt; <span class="hljs-number">0</span>);
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, context</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-269">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-269">&#182;</a>
+ </div>
+ <p>Get the variable from the context</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> value = Twig.expression.resolve(context[token.value], context);
+ stack.push(value);
+ }
+ },
+ {
+ type: Twig.expression.type.key.period,
+ regex: <span class="hljs-regexp">/^\.([a-zA-Z0-9_]+)/</span>,
+ next: Twig.expression.set.operations_extended.concat([
+ Twig.expression.type.parameter.start]),
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ token.key = token.match[<span class="hljs-number">1</span>];
+ <span class="hljs-keyword">delete</span> token.match;
+ <span class="hljs-keyword">delete</span> token.value;
+
+ output.push(token);
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, context</span>) </span>{
+ <span class="hljs-keyword">var</span> params = token.params &amp;&amp; Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.params, context]),
+ key = token.key,
+ object = stack.pop(),
+ value;
+
+ <span class="hljs-keyword">if</span> (object === <span class="hljs-literal">null</span> || object === <span class="hljs-literal">undefined</span>) {
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.options.strict_variables) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Can't access a key "</span> + key + <span class="hljs-string">" on an null or undefined object."</span>);
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
+ }
+ }
+
+ <span class="hljs-keyword">var</span> capitalize = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{<span class="hljs-keyword">return</span> value.substr(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>).toUpperCase() + value.substr(<span class="hljs-number">1</span>);};</pre></div></div>
+
+ </li>
+
+
+ <li id="section-270">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-270">&#182;</a>
+ </div>
+ <p>Get the variable from the context</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object === <span class="hljs-string">'object'</span> &amp;&amp; key <span class="hljs-keyword">in</span> object) {
+ value = object[key];
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (object[<span class="hljs-string">"get"</span>+capitalize(key)] !== <span class="hljs-literal">undefined</span>) {
+ value = object[<span class="hljs-string">"get"</span>+capitalize(key)];
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (object[<span class="hljs-string">"is"</span>+capitalize(key)] !== <span class="hljs-literal">undefined</span>) {
+ value = object[<span class="hljs-string">"is"</span>+capitalize(key)];
+ } <span class="hljs-keyword">else</span> {
+ value = <span class="hljs-literal">undefined</span>;
+ }
+ stack.push(Twig.expression.resolve(value, object, params));
+ }
+ },
+ {
+ type: Twig.expression.type.key.brackets,
+ regex: <span class="hljs-regexp">/^\[([^\]]*)\]/</span>,
+ next: Twig.expression.set.operations_extended.concat([
+ Twig.expression.type.parameter.start]),
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ <span class="hljs-keyword">var</span> match = token.match[<span class="hljs-number">1</span>];
+ <span class="hljs-keyword">delete</span> token.value;
+ <span class="hljs-keyword">delete</span> token.match;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-271">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-271">&#182;</a>
+ </div>
+ <p>The expression stack for the key</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> token.stack = Twig.expression.compile({
+ value: match
+ }).stack;
+
+ output.push(token);
+ },
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, context</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-272">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-272">&#182;</a>
+ </div>
+ <p>Evaluate key</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> params = token.params &amp;&amp; Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.params, context]),
+ key = Twig.expression.parse.apply(<span class="hljs-keyword">this</span>, [token.stack, context]),
+ object = stack.pop(),
+ value;
+
+ <span class="hljs-keyword">if</span> (object === <span class="hljs-literal">null</span> || object === <span class="hljs-literal">undefined</span>) {
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.options.strict_variables) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Can't access a key "</span> + key + <span class="hljs-string">" on an null or undefined object."</span>);
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
+ }
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-273">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-273">&#182;</a>
+ </div>
+ <p>Get the variable from the context</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object === <span class="hljs-string">'object'</span> &amp;&amp; key <span class="hljs-keyword">in</span> object) {
+ value = object[key];
+ } <span class="hljs-keyword">else</span> {
+ value = <span class="hljs-literal">null</span>;
+ }
+ stack.push(Twig.expression.resolve(value, object, params));
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * Match a null value.
+ */</span>
+ type: Twig.expression.type._null,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-274">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-274">&#182;</a>
+ </div>
+ <p>match a number</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> regex: <span class="hljs-regexp">/^(null|NULL|none|NONE)/</span>,
+ next: Twig.expression.set.operations,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ <span class="hljs-keyword">delete</span> token.match;
+ token.value = <span class="hljs-literal">null</span>;
+ output.push(token);
+ },
+ parse: Twig.expression.fn.parse.push_value
+ },
+ {
+ <span class="hljs-comment">/**
+ * Match the context
+ */</span>
+ type: Twig.expression.type.context,
+ regex: <span class="hljs-regexp">/^_context/</span>,
+ next: Twig.expression.set.operations_extended.concat([
+ Twig.expression.type.parameter.start]),
+ compile: Twig.expression.fn.compile.push,
+ parse: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, context</span>) </span>{
+ stack.push(context);
+ }
+ },
+ {
+ <span class="hljs-comment">/**
+ * Match a number (integer or decimal)
+ */</span>
+ type: Twig.expression.type.number,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-275">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-275">&#182;</a>
+ </div>
+ <p>match a number</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> regex: <span class="hljs-regexp">/^\-?\d+(\.\d+)?/</span>,
+ next: Twig.expression.set.operations,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ token.value = <span class="hljs-built_in">Number</span>(token.value);
+ output.push(token);
+ },
+ parse: Twig.expression.fn.parse.push_value
+ },
+ {
+ <span class="hljs-comment">/**
+ * Match a boolean
+ */</span>
+ type: Twig.expression.type.bool,
+ regex: <span class="hljs-regexp">/^(true|TRUE|false|FALSE)/</span>,
+ next: Twig.expression.set.operations,
+ compile: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token, stack, output</span>) </span>{
+ token.value = (token.match[<span class="hljs-number">0</span>].toLowerCase( ) === <span class="hljs-string">"true"</span>);
+ <span class="hljs-keyword">delete</span> token.match;
+ output.push(token);
+ },
+ parse: Twig.expression.fn.parse.push_value
+ }
+ ];
+
+ <span class="hljs-comment">/**
+ * Resolve a context value.
+ *
+ * If the value is a function, it is executed with a context parameter.
+ *
+ * @param {string} key The context object key.
+ * @param {Object} context The render context.
+ */</span>
+ Twig.expression.resolve = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, context, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> value == <span class="hljs-string">'function'</span>) {
+ <span class="hljs-keyword">return</span> value.apply(context, params || []);
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">return</span> value;
+ }
+ };
+
+ <span class="hljs-comment">/**
+ * Registry for logic handlers.
+ */</span>
+ Twig.expression.handler = {};
+
+ <span class="hljs-comment">/**
+ * Define a new expression type, available at Twig.logic.type.{type}
+ *
+ * @param {string} type The name of the new type.
+ */</span>
+ Twig.expression.extendType = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">type</span>) </span>{
+ Twig.expression.type[type] = <span class="hljs-string">"Twig.expression.type."</span> + type;
+ };
+
+ <span class="hljs-comment">/**
+ * Extend the expression parsing functionality with a new definition.
+ *
+ * Token definitions follow this format:
+ * {
+ * type: One of Twig.expression.type.[type], either pre-defined or added using
+ * Twig.expression.extendType
+ *
+ * next: Array of types from Twig.expression.type that can follow this token,
+ *
+ * regex: A regex or array of regex's that should match the token.
+ *
+ * compile: function(token, stack, output) called when this token is being compiled.
+ * Should return an object with stack and output set.
+ *
+ * parse: function(token, stack, context) called when this token is being parsed.
+ * Should return an object with stack and context set.
+ * }
+ *
+ * @param {Object} definition A token definition.
+ */</span>
+ Twig.expression.extend = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">definition</span>) </span>{
+ <span class="hljs-keyword">if</span> (!definition.type) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Unable to extend logic definition. No type provided for "</span> + definition);
+ }
+ Twig.expression.handler[definition.type] = definition;
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-276">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-276">&#182;</a>
+ </div>
+ <p>Extend with built-in expressions</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">while</span> (Twig.expression.definitions.length &gt; <span class="hljs-number">0</span>) {
+ Twig.expression.extend(Twig.expression.definitions.shift());
+ }
+
+ <span class="hljs-comment">/**
+ * Break an expression into tokens defined in Twig.expression.definitions.
+ *
+ * @param {string} expression The string to tokenize.
+ *
+ * @return {Array} An array of tokens.
+ */</span>
+ Twig.expression.tokenize = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">expression</span>) </span>{
+ <span class="hljs-keyword">var</span> tokens = [],</pre></div></div>
+
+ </li>
+
+
+ <li id="section-277">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-277">&#182;</a>
+ </div>
+ <p>Keep an offset of the location in the expression for error messages.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> exp_offset = <span class="hljs-number">0</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-278">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-278">&#182;</a>
+ </div>
+ <p>The valid next tokens of the previous token</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> next = <span class="hljs-literal">null</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-279">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-279">&#182;</a>
+ </div>
+ <p>Match information</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> type, regex, regex_array,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-280">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-280">&#182;</a>
+ </div>
+ <p>The possible next token for the match</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> token_next,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-281">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-281">&#182;</a>
+ </div>
+ <p>Has a match been found from the definitions</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> match_found, invalid_matches = [], match_function;
+
+ match_function = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
+ <span class="hljs-keyword">var</span> match = <span class="hljs-built_in">Array</span>.prototype.slice.apply(<span class="hljs-built_in">arguments</span>),
+ string = match.pop(),
+ offset = match.pop();
+
+ Twig.log.trace(<span class="hljs-string">"Twig.expression.tokenize"</span>,
+ <span class="hljs-string">"Matched a "</span>, type, <span class="hljs-string">" regular expression of "</span>, match);
+
+ <span class="hljs-keyword">if</span> (next &amp;&amp; Twig.indexOf(next, type) &lt; <span class="hljs-number">0</span>) {
+ invalid_matches.push(
+ type + <span class="hljs-string">" cannot follow a "</span> + tokens[tokens.length - <span class="hljs-number">1</span>].type +
+ <span class="hljs-string">" at template:"</span> + exp_offset + <span class="hljs-string">" near '"</span> + match[<span class="hljs-number">0</span>].substring(<span class="hljs-number">0</span>, <span class="hljs-number">20</span>) +
+ <span class="hljs-string">"...'"</span>
+ );</pre></div></div>
+
+ </li>
+
+
+ <li id="section-282">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-282">&#182;</a>
+ </div>
+ <p>Not a match, don’t change the expression</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> match[<span class="hljs-number">0</span>];
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-283">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-283">&#182;</a>
+ </div>
+ <p>Validate the token if a validation function is provided</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (Twig.expression.handler[type].validate &amp;&amp;
+ !Twig.expression.handler[type].validate(match, tokens)) {
+ <span class="hljs-keyword">return</span> match[<span class="hljs-number">0</span>];
+ }
+
+ invalid_matches = [];
+
+ tokens.push({
+ type: type,
+ value: match[<span class="hljs-number">0</span>],
+ match: match
+ });
+
+ match_found = <span class="hljs-literal">true</span>;
+ next = token_next;
+ exp_offset += match[<span class="hljs-number">0</span>].length;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-284">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-284">&#182;</a>
+ </div>
+ <p>Does the token need to return output back to the expression string
+e.g. a function match of cycle( might return the ‘(‘ back to the expression
+This allows look-ahead to differentiate between token types (e.g. functions and variable names)</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (Twig.expression.handler[type].transform) {
+ <span class="hljs-keyword">return</span> Twig.expression.handler[type].transform(match, tokens);
+ }
+ <span class="hljs-keyword">return</span> <span class="hljs-string">''</span>;
+ };
+
+ Twig.log.debug(<span class="hljs-string">"Twig.expression.tokenize"</span>, <span class="hljs-string">"Tokenizing expression "</span>, expression);
+
+ <span class="hljs-keyword">while</span> (expression.length &gt; <span class="hljs-number">0</span>) {
+ expression = expression.trim();
+ <span class="hljs-keyword">for</span> (type <span class="hljs-keyword">in</span> Twig.expression.handler) {
+ <span class="hljs-keyword">if</span> (Twig.expression.handler.hasOwnProperty(type)) {
+ token_next = Twig.expression.handler[type].next;
+ regex = Twig.expression.handler[type].regex;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-285">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-285">&#182;</a>
+ </div>
+ <p>Twig.log.trace(“Checking type “, type, “ on “, expression);</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (regex <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Array</span>) {
+ regex_array = regex;
+ } <span class="hljs-keyword">else</span> {
+ regex_array = [regex];
+ }
+
+ match_found = <span class="hljs-literal">false</span>;
+ <span class="hljs-keyword">while</span> (regex_array.length &gt; <span class="hljs-number">0</span>) {
+ regex = regex_array.pop();
+ expression = expression.replace(regex, match_function);
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-286">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-286">&#182;</a>
+ </div>
+ <p>An expression token has been matched. Break the for loop and start trying to
+ match the next template (if expression isn’t empty.)</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (match_found) {
+ <span class="hljs-keyword">break</span>;
+ }
+ }
+ }
+ <span class="hljs-keyword">if</span> (!match_found) {
+ <span class="hljs-keyword">if</span> (invalid_matches.length &gt; <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(invalid_matches.join(<span class="hljs-string">" OR "</span>));
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Unable to parse '"</span> + expression + <span class="hljs-string">"' at template position"</span> + exp_offset);
+ }
+ }
+ }
+
+ Twig.log.trace(<span class="hljs-string">"Twig.expression.tokenize"</span>, <span class="hljs-string">"Tokenized to "</span>, tokens);
+ <span class="hljs-keyword">return</span> tokens;
+ };
+
+ <span class="hljs-comment">/**
+ * Compile an expression token.
+ *
+ * @param {Object} raw_token The uncompiled token.
+ *
+ * @return {Object} The compiled token.
+ */</span>
+ Twig.expression.compile = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">raw_token</span>) </span>{
+ <span class="hljs-keyword">var</span> expression = raw_token.value,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-287">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-287">&#182;</a>
+ </div>
+ <p>Tokenize expression</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> tokens = Twig.expression.tokenize(expression),
+ token = <span class="hljs-literal">null</span>,
+ output = [],
+ stack = [],
+ token_template = <span class="hljs-literal">null</span>;
+
+ Twig.log.trace(<span class="hljs-string">"Twig.expression.compile: "</span>, <span class="hljs-string">"Compiling "</span>, expression);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-288">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-288">&#182;</a>
+ </div>
+ <p>Push tokens into RPN stack using the Sunting-yard algorithm
+See <a href="http://en.wikipedia.org/wiki/Shunting_yard_algorithm">http://en.wikipedia.org/wiki/Shunting_yard_algorithm</a></p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ <span class="hljs-keyword">while</span> (tokens.length &gt; <span class="hljs-number">0</span>) {
+ token = tokens.shift();
+ token_template = Twig.expression.handler[token.type];
+
+ Twig.log.trace(<span class="hljs-string">"Twig.expression.compile: "</span>, <span class="hljs-string">"Compiling "</span>, token);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-289">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-289">&#182;</a>
+ </div>
+ <p>Compile the template</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> token_template.compile &amp;&amp; token_template.compile(token, stack, output);
+
+ Twig.log.trace(<span class="hljs-string">"Twig.expression.compile: "</span>, <span class="hljs-string">"Stack is"</span>, stack);
+ Twig.log.trace(<span class="hljs-string">"Twig.expression.compile: "</span>, <span class="hljs-string">"Output is"</span>, output);
+ }
+
+ <span class="hljs-keyword">while</span>(stack.length &gt; <span class="hljs-number">0</span>) {
+ output.push(stack.pop());
+ }
+
+ Twig.log.trace(<span class="hljs-string">"Twig.expression.compile: "</span>, <span class="hljs-string">"Final output is"</span>, output);
+
+ raw_token.stack = output;
+ <span class="hljs-keyword">delete</span> raw_token.value;
+
+ <span class="hljs-keyword">return</span> raw_token;
+ };
+
+
+ <span class="hljs-comment">/**
+ * Parse an RPN expression stack within a context.
+ *
+ * @param {Array} tokens An array of compiled expression tokens.
+ * @param {Object} context The render context to parse the tokens with.
+ *
+ * @return {Object} The result of parsing all the tokens. The result
+ * can be anything, String, Array, Object, etc... based on
+ * the given expression.
+ */</span>
+ Twig.expression.parse = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">tokens, context</span>) </span>{
+ <span class="hljs-keyword">var</span> that = <span class="hljs-keyword">this</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-290">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-290">&#182;</a>
+ </div>
+ <p>If the token isn’t an array, make it one.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (!(tokens <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Array</span>)) {
+ tokens = [tokens];
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-291">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-291">&#182;</a>
+ </div>
+ <p>The output stack</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> stack = [],
+ token_template = <span class="hljs-literal">null</span>;
+
+ Twig.forEach(tokens, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">token</span>) </span>{
+ token_template = Twig.expression.handler[token.type];
+
+ token_template.parse &amp;&amp; token_template.parse.apply(that, [token, stack, context]);
+ });</pre></div></div>
+
+ </li>
+
+
+ <li id="section-292">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-292">&#182;</a>
+ </div>
+ <p>Pop the final value off the stack</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> stack.pop();
+ };
+
+ <span class="hljs-keyword">return</span> Twig;
+
+})( Twig || { } );</pre></div></div>
+
+ </li>
+
+
+ <li id="section-293">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-293">&#182;</a>
+ </div>
+ <pre><code>Twig.js
+Available under the BSD <span class="hljs-number">2</span>-Clause License
+https:<span class="hljs-comment">//github.com/justjohn/twig.js</span>
+</code></pre>
+ </div>
+
+ </li>
+
+
+ <li id="section-294">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-294">&#182;</a>
+ </div>
+ <h2 id="twig-expression-operator-js">twig.expression.operator.js</h2>
+<p>This file handles operator lookups and parsing.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> Twig = (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Twig</span>) </span>{
+<span class="hljs-meta"> "use strict"</span>;
+
+ <span class="hljs-comment">/**
+ * Operator associativity constants.
+ */</span>
+ Twig.expression.operator = {
+ leftToRight: <span class="hljs-string">'leftToRight'</span>,
+ rightToLeft: <span class="hljs-string">'rightToLeft'</span>
+ };
+
+ <span class="hljs-keyword">var</span> containment = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">a, b</span>) </span>{
+ <span class="hljs-keyword">if</span> (b === <span class="hljs-literal">undefined</span> || b === <span class="hljs-literal">null</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (b.indexOf !== <span class="hljs-literal">undefined</span>) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-295">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-295">&#182;</a>
+ </div>
+ <p>String</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> a === b || a !== <span class="hljs-string">''</span> &amp;&amp; b.indexOf(a) &gt; <span class="hljs-number">-1</span>;
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">var</span> el;
+ <span class="hljs-keyword">for</span> (el <span class="hljs-keyword">in</span> b) {
+ <span class="hljs-keyword">if</span> (b.hasOwnProperty(el) &amp;&amp; b[el] === a) {
+ <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
+ }
+ }
+ <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
+ }
+ };
+
+ <span class="hljs-comment">/**
+ * Get the precidence and associativity of an operator. These follow the order that C/C++ use.
+ * See http://en.wikipedia.org/wiki/Operators_in_C_and_C++ for the table of values.
+ */</span>
+ Twig.expression.operator.lookup = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">operator, token</span>) </span>{
+ <span class="hljs-keyword">switch</span> (operator) {
+ <span class="hljs-keyword">case</span> <span class="hljs-string">".."</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'not in'</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'in'</span>:
+ token.precidence = <span class="hljs-number">20</span>;
+ token.associativity = Twig.expression.operator.leftToRight;
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">','</span>:
+ token.precidence = <span class="hljs-number">18</span>;
+ token.associativity = Twig.expression.operator.leftToRight;
+ <span class="hljs-keyword">break</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-296">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-296">&#182;</a>
+ </div>
+ <p>Ternary</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">case</span> <span class="hljs-string">'?'</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">':'</span>:
+ token.precidence = <span class="hljs-number">16</span>;
+ token.associativity = Twig.expression.operator.rightToLeft;
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'or'</span>:
+ token.precidence = <span class="hljs-number">14</span>;
+ token.associativity = Twig.expression.operator.leftToRight;
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'and'</span>:
+ token.precidence = <span class="hljs-number">13</span>;
+ token.associativity = Twig.expression.operator.leftToRight;
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'=='</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'!='</span>:
+ token.precidence = <span class="hljs-number">9</span>;
+ token.associativity = Twig.expression.operator.leftToRight;
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'&lt;'</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'&lt;='</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'&gt;'</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'&gt;='</span>:
+ token.precidence = <span class="hljs-number">8</span>;
+ token.associativity = Twig.expression.operator.leftToRight;
+ <span class="hljs-keyword">break</span>;
+
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'~'</span>: <span class="hljs-comment">// String concatination</span>
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'+'</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'-'</span>:
+ token.precidence = <span class="hljs-number">6</span>;
+ token.associativity = Twig.expression.operator.leftToRight;
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'//'</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'**'</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'*'</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'/'</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'%'</span>:
+ token.precidence = <span class="hljs-number">5</span>;
+ token.associativity = Twig.expression.operator.leftToRight;
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'not'</span>:
+ token.precidence = <span class="hljs-number">3</span>;
+ token.associativity = Twig.expression.operator.rightToLeft;
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">default</span>:
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(operator + <span class="hljs-string">" is an unknown operator."</span>);
+ }
+ token.operator = operator;
+ <span class="hljs-keyword">return</span> token;
+ };
+
+ <span class="hljs-comment">/**
+ * Handle operations on the RPN stack.
+ *
+ * Returns the updated stack.
+ */</span>
+ Twig.expression.operator.parse = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">operator, stack</span>) </span>{
+ Twig.log.trace(<span class="hljs-string">"Twig.expression.operator.parse: "</span>, <span class="hljs-string">"Handling "</span>, operator);
+ <span class="hljs-keyword">var</span> a, b, c;
+ <span class="hljs-keyword">switch</span> (operator) {
+ <span class="hljs-keyword">case</span> <span class="hljs-string">':'</span>:</pre></div></div>
+
+ </li>
+
+
+ <li id="section-297">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-297">&#182;</a>
+ </div>
+ <p>Ignore</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'?'</span>:
+ c = stack.pop(); <span class="hljs-comment">// false expr</span>
+ b = stack.pop(); <span class="hljs-comment">// true expr</span>
+ a = stack.pop(); <span class="hljs-comment">// conditional</span>
+ <span class="hljs-keyword">if</span> (a) {
+ stack.push(b);
+ } <span class="hljs-keyword">else</span> {
+ stack.push(c);
+ }
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'+'</span>:
+ b = <span class="hljs-built_in">parseFloat</span>(stack.pop());
+ a = <span class="hljs-built_in">parseFloat</span>(stack.pop());
+ stack.push(a + b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'-'</span>:
+ b = <span class="hljs-built_in">parseFloat</span>(stack.pop());
+ a = <span class="hljs-built_in">parseFloat</span>(stack.pop());
+ stack.push(a - b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'*'</span>:
+ b = <span class="hljs-built_in">parseFloat</span>(stack.pop());
+ a = <span class="hljs-built_in">parseFloat</span>(stack.pop());
+ stack.push(a * b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'/'</span>:
+ b = <span class="hljs-built_in">parseFloat</span>(stack.pop());
+ a = <span class="hljs-built_in">parseFloat</span>(stack.pop());
+ stack.push(a / b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'//'</span>:
+ b = <span class="hljs-built_in">parseFloat</span>(stack.pop());
+ a = <span class="hljs-built_in">parseFloat</span>(stack.pop());
+ stack.push(<span class="hljs-built_in">parseInt</span>(a / b));
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'%'</span>:
+ b = <span class="hljs-built_in">parseFloat</span>(stack.pop());
+ a = <span class="hljs-built_in">parseFloat</span>(stack.pop());
+ stack.push(a % b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'~'</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push( (a != <span class="hljs-literal">null</span> ? a.toString() : <span class="hljs-string">""</span>)
+ + (b != <span class="hljs-literal">null</span> ? b.toString() : <span class="hljs-string">""</span>) );
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'not'</span>:
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'!'</span>:
+ stack.push(!stack.pop());
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'&lt;'</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a &lt; b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'&lt;='</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a &lt;= b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'&gt;'</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a &gt; b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'&gt;='</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a &gt;= b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'==='</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a === b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'=='</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a == b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'!=='</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a !== b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'!='</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a != b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'or'</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a || b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'and'</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a &amp;&amp; b);
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'**'</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(<span class="hljs-built_in">Math</span>.pow(a, b));
+ <span class="hljs-keyword">break</span>;
+
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'not in'</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push( !containment(a, b) );
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'in'</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push( containment(a, b) );
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">case</span> <span class="hljs-string">'..'</span>:
+ b = stack.pop();
+ a = stack.pop();
+ stack.push( Twig.functions.range(a, b) );
+ <span class="hljs-keyword">break</span>;
+
+ <span class="hljs-keyword">default</span>:
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(operator + <span class="hljs-string">" is an unknown operator."</span>);
+ }
+ };
+
+ <span class="hljs-keyword">return</span> Twig;
+
+})( Twig || { } );</pre></div></div>
+
+ </li>
+
+
+ <li id="section-298">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-298">&#182;</a>
+ </div>
+ <pre><code>Twig.js
+Available under the BSD <span class="hljs-number">2</span>-Clause License
+https:<span class="hljs-comment">//github.com/justjohn/twig.js</span>
+</code></pre>
+ </div>
+
+ </li>
+
+
+ <li id="section-299">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-299">&#182;</a>
+ </div>
+ <h2 id="twig-filters-js">twig.filters.js</h2>
+<p>This file handles parsing filters.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> Twig = (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Twig</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-300">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-300">&#182;</a>
+ </div>
+ <p>Determine object type</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">is</span>(<span class="hljs-params">type, obj</span>) </span>{
+ <span class="hljs-keyword">var</span> clas = <span class="hljs-built_in">Object</span>.prototype.toString.call(obj).slice(<span class="hljs-number">8</span>, <span class="hljs-number">-1</span>);
+ <span class="hljs-keyword">return</span> obj !== <span class="hljs-literal">undefined</span> &amp;&amp; obj !== <span class="hljs-literal">null</span> &amp;&amp; clas === type;
+ }
+
+ Twig.filters = {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-301">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-301">&#182;</a>
+ </div>
+ <p>String Filters</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> upper: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> ( <span class="hljs-keyword">typeof</span> value !== <span class="hljs-string">"string"</span> ) {
+ <span class="hljs-keyword">return</span> value;
+ }
+
+ <span class="hljs-keyword">return</span> value.toUpperCase();
+ },
+ lower: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> ( <span class="hljs-keyword">typeof</span> value !== <span class="hljs-string">"string"</span> ) {
+ <span class="hljs-keyword">return</span> value;
+ }
+
+ <span class="hljs-keyword">return</span> value.toLowerCase();
+ },
+ capitalize: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> ( <span class="hljs-keyword">typeof</span> value !== <span class="hljs-string">"string"</span> ) {
+ <span class="hljs-keyword">return</span> value;
+ }
+
+ <span class="hljs-keyword">return</span> value.substr(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>).toUpperCase() + value.toLowerCase().substr(<span class="hljs-number">1</span>);
+ },
+ title: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> ( <span class="hljs-keyword">typeof</span> value !== <span class="hljs-string">"string"</span> ) {
+ <span class="hljs-keyword">return</span> value;
+ }
+
+ <span class="hljs-keyword">return</span> value.toLowerCase().replace( <span class="hljs-regexp">/(^|\s)([a-z])/g</span> , <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">m, p1, p2</span>)</span>{
+ <span class="hljs-keyword">return</span> p1 + p2.toUpperCase();
+ });
+ },
+ length: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">"Array"</span>, value) || <span class="hljs-keyword">typeof</span> value === <span class="hljs-string">"string"</span>) {
+ <span class="hljs-keyword">return</span> value.length;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">"Object"</span>, value)) {
+ <span class="hljs-keyword">if</span> (value._keys === <span class="hljs-literal">undefined</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-built_in">Object</span>.keys(value).length;
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">return</span> value._keys.length;
+ }
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
+ }
+ },</pre></div></div>
+
+ </li>
+
+
+ <li id="section-302">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-302">&#182;</a>
+ </div>
+ <p>Array/Object Filters</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> reverse: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> (is(<span class="hljs-string">"Array"</span>, value)) {
+ <span class="hljs-keyword">return</span> value.reverse();
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (is(<span class="hljs-string">"String"</span>, value)) {
+ <span class="hljs-keyword">return</span> value.split(<span class="hljs-string">""</span>).reverse().join(<span class="hljs-string">""</span>);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (is(<span class="hljs-string">"Object"</span>, value)) {
+ <span class="hljs-keyword">var</span> keys = value._keys || <span class="hljs-built_in">Object</span>.keys(value).reverse();
+ value._keys = keys;
+ <span class="hljs-keyword">return</span> value;
+ }
+ },
+ sort: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> (is(<span class="hljs-string">"Array"</span>, value)) {
+ <span class="hljs-keyword">return</span> value.sort();
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (is(<span class="hljs-string">'Object'</span>, value)) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-303">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-303">&#182;</a>
+ </div>
+ <p>Sorting objects isn’t obvious since the order of
+returned keys isn’t guaranteed in JavaScript.
+Because of this we use a “hidden” key called _keys to
+store the keys in the order we want to return them.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ <span class="hljs-keyword">delete</span> value._keys;
+ <span class="hljs-keyword">var</span> keys = <span class="hljs-built_in">Object</span>.keys(value),
+ sorted_keys = keys.sort(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">a, b</span>) </span>{
+ <span class="hljs-keyword">var</span> a1, a2;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-304">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-304">&#182;</a>
+ </div>
+ <p>if a and b are comparable, we’re fine :-)</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span>((value[a] &gt; value[b]) == !(value[a] &lt;= value[b])) {
+ <span class="hljs-keyword">return</span> value[a] &gt; value[b] ? <span class="hljs-number">1</span> :
+ value[a] &lt; value[b] ? <span class="hljs-number">-1</span> :
+ <span class="hljs-number">0</span>;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-305">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-305">&#182;</a>
+ </div>
+ <p>if a and b can be parsed as numbers, we can compare
+their numeric value</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(!<span class="hljs-built_in">isNaN</span>(a1 = <span class="hljs-built_in">parseFloat</span>(value[a])) &amp;&amp;
+ !<span class="hljs-built_in">isNaN</span>(b1 = <span class="hljs-built_in">parseFloat</span>(value[b]))) {
+ <span class="hljs-keyword">return</span> a1 &gt; b1 ? <span class="hljs-number">1</span> :
+ a1 &lt; b1 ? <span class="hljs-number">-1</span> :
+ <span class="hljs-number">0</span>;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-306">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-306">&#182;</a>
+ </div>
+ <p>if one of the values is a string, we convert the
+other value to string as well</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(<span class="hljs-keyword">typeof</span> value[a] == <span class="hljs-string">'string'</span>) {
+ <span class="hljs-keyword">return</span> value[a] &gt; value[b].toString() ? <span class="hljs-number">1</span> :
+ value[a] &lt; value[b].toString() ? <span class="hljs-number">-1</span> :
+ <span class="hljs-number">0</span>;
+ }
+ <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(<span class="hljs-keyword">typeof</span> value[b] == <span class="hljs-string">'string'</span>) {
+ <span class="hljs-keyword">return</span> value[a].toString() &gt; value[b] ? <span class="hljs-number">1</span> :
+ value[a].toString() &lt; value[b] ? <span class="hljs-number">-1</span> :
+ <span class="hljs-number">0</span>;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-307">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-307">&#182;</a>
+ </div>
+ <p>everything failed - return ‘null’ as sign, that
+the values are not comparable</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
+ }
+ });
+ value._keys = sorted_keys;
+ <span class="hljs-keyword">return</span> value;
+ }
+ },
+ keys: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span> || value === <span class="hljs-literal">null</span>){
+ <span class="hljs-keyword">return</span>;
+ }
+
+ <span class="hljs-keyword">var</span> keyset = value._keys || <span class="hljs-built_in">Object</span>.keys(value),
+ output = [];
+
+ Twig.forEach(keyset, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">key</span>) </span>{
+ <span class="hljs-keyword">if</span> (key === <span class="hljs-string">"_keys"</span>) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Ignore the _keys property</span>
+ <span class="hljs-keyword">if</span> (value.hasOwnProperty(key)) {
+ output.push(key);
+ }
+ });
+ <span class="hljs-keyword">return</span> output;
+ },
+ url_encode: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span> || value === <span class="hljs-literal">null</span>){
+ <span class="hljs-keyword">return</span>;
+ }
+
+ <span class="hljs-keyword">var</span> result = <span class="hljs-built_in">encodeURIComponent</span>(value);
+ result = result.replace(<span class="hljs-string">"'"</span>, <span class="hljs-string">"%27"</span>);
+ <span class="hljs-keyword">return</span> result;
+ },
+ join: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span> || value === <span class="hljs-literal">null</span>){
+ <span class="hljs-keyword">return</span>;
+ }
+
+ <span class="hljs-keyword">var</span> join_str = <span class="hljs-string">""</span>,
+ output = [],
+ keyset = <span class="hljs-literal">null</span>;
+
+ <span class="hljs-keyword">if</span> (params &amp;&amp; params[<span class="hljs-number">0</span>]) {
+ join_str = params[<span class="hljs-number">0</span>];
+ }
+ <span class="hljs-keyword">if</span> (is(<span class="hljs-string">"Array"</span>, value)) {
+ output = value;
+ } <span class="hljs-keyword">else</span> {
+ keyset = value._keys || <span class="hljs-built_in">Object</span>.keys(value);
+ Twig.forEach(keyset, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">key</span>) </span>{
+ <span class="hljs-keyword">if</span> (key === <span class="hljs-string">"_keys"</span>) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Ignore the _keys property</span>
+ <span class="hljs-keyword">if</span> (value.hasOwnProperty(key)) {
+ output.push(value[key]);
+ }
+ });
+ }
+ <span class="hljs-keyword">return</span> output.join(join_str);
+ },
+ <span class="hljs-string">"default"</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (params !== <span class="hljs-literal">undefined</span> &amp;&amp; params.length &gt; <span class="hljs-number">1</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"default filter expects one argument"</span>);
+ }
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span> || value === <span class="hljs-literal">null</span> || value === <span class="hljs-string">''</span> ) {
+ <span class="hljs-keyword">if</span> (params === <span class="hljs-literal">undefined</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-string">''</span>;
+ }
+
+ <span class="hljs-keyword">return</span> params[<span class="hljs-number">0</span>];
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">return</span> value;
+ }
+ },
+ json_encode: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span>(value === <span class="hljs-literal">undefined</span> || value === <span class="hljs-literal">null</span>) {
+ <span class="hljs-keyword">return</span> <span class="hljs-string">"null"</span>;
+ }
+ <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ((<span class="hljs-keyword">typeof</span> value == <span class="hljs-string">'object'</span>) &amp;&amp; (is(<span class="hljs-string">"Array"</span>, value))) {
+ output = [];
+
+ Twig.forEach(value, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">v</span>) </span>{
+ output.push(Twig.filters.json_encode(v));
+ });
+
+ <span class="hljs-keyword">return</span> <span class="hljs-string">"["</span> + output.join(<span class="hljs-string">","</span>) + <span class="hljs-string">"]"</span>;
+ }
+ <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> value == <span class="hljs-string">'object'</span>) {
+ <span class="hljs-keyword">var</span> keyset = value._keys || <span class="hljs-built_in">Object</span>.keys(value),
+ output = [];
+
+ Twig.forEach(keyset, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">key</span>) </span>{
+ output.push(<span class="hljs-built_in">JSON</span>.stringify(key) + <span class="hljs-string">":"</span> + Twig.filters.json_encode(value[key]));
+ });
+
+ <span class="hljs-keyword">return</span> <span class="hljs-string">"{"</span> + output.join(<span class="hljs-string">","</span>) + <span class="hljs-string">"}"</span>;
+ }
+ <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">return</span> <span class="hljs-built_in">JSON</span>.stringify(value);
+ }
+ },
+ merge: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">var</span> obj = [],
+ arr_index = <span class="hljs-number">0</span>,
+ keyset = [];</pre></div></div>
+
+ </li>
+
+
+ <li id="section-308">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-308">&#182;</a>
+ </div>
+ <p>Check to see if all the objects being merged are arrays</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (!is(<span class="hljs-string">"Array"</span>, value)) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-309">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-309">&#182;</a>
+ </div>
+ <p>Create obj as an Object</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> obj = { };
+ } <span class="hljs-keyword">else</span> {
+ Twig.forEach(params, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">param</span>) </span>{
+ <span class="hljs-keyword">if</span> (!is(<span class="hljs-string">"Array"</span>, param)) {
+ obj = { };
+ }
+ });
+ }
+ <span class="hljs-keyword">if</span> (!is(<span class="hljs-string">"Array"</span>, obj)) {
+ obj._keys = [];
+ }
+
+ <span class="hljs-keyword">if</span> (is(<span class="hljs-string">"Array"</span>, value)) {
+ Twig.forEach(value, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">val</span>) </span>{
+ <span class="hljs-keyword">if</span> (obj._keys) obj._keys.push(arr_index);
+ obj[arr_index] = val;
+ arr_index++;
+ });
+ } <span class="hljs-keyword">else</span> {
+ keyset = value._keys || <span class="hljs-built_in">Object</span>.keys(value);
+ Twig.forEach(keyset, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">key</span>) </span>{
+ obj[key] = value[key];
+ obj._keys.push(key);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-310">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-310">&#182;</a>
+ </div>
+ <p>Handle edge case where a number index in an object is greater than
+ the array counter. In such a case, the array counter is increased
+ one past the index.</p>
+<p>Example {{ [“a”, “b”]|merge({“4”:”value”}, [“c”, “d”])
+Without this, d would have an index of “4” and overwrite the value
+ of “value”</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> int_key = <span class="hljs-built_in">parseInt</span>(key, <span class="hljs-number">10</span>);
+ <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">isNaN</span>(int_key) &amp;&amp; int_key &gt;= arr_index) {
+ arr_index = int_key + <span class="hljs-number">1</span>;
+ }
+ });
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-311">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-311">&#182;</a>
+ </div>
+ <p>mixin the merge arrays</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.forEach(params, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">param</span>) </span>{
+ <span class="hljs-keyword">if</span> (is(<span class="hljs-string">"Array"</span>, param)) {
+ Twig.forEach(param, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">val</span>) </span>{
+ <span class="hljs-keyword">if</span> (obj._keys) obj._keys.push(arr_index);
+ obj[arr_index] = val;
+ arr_index++;
+ });
+ } <span class="hljs-keyword">else</span> {
+ keyset = param._keys || <span class="hljs-built_in">Object</span>.keys(param);
+ Twig.forEach(keyset, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">key</span>) </span>{
+ <span class="hljs-keyword">if</span> (!obj[key]) obj._keys.push(key);
+ obj[key] = param[key];
+
+ <span class="hljs-keyword">var</span> int_key = <span class="hljs-built_in">parseInt</span>(key, <span class="hljs-number">10</span>);
+ <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">isNaN</span>(int_key) &amp;&amp; int_key &gt;= arr_index) {
+ arr_index = int_key + <span class="hljs-number">1</span>;
+ }
+ });
+ }
+ });
+ <span class="hljs-keyword">if</span> (params.length === <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Filter merge expects at least one parameter"</span>);
+ }
+
+ <span class="hljs-keyword">return</span> obj;
+ },
+ date: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">var</span> date = Twig.functions.date(value);
+ <span class="hljs-keyword">var</span> format = params &amp;&amp; params.length ? params[<span class="hljs-number">0</span>] : <span class="hljs-string">'F j, Y H:i'</span>;
+ <span class="hljs-keyword">return</span> Twig.lib.formatDate(date, format);
+ },
+
+ date_modify: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span> || value === <span class="hljs-literal">null</span>) {
+ <span class="hljs-keyword">return</span>;
+ }
+ <span class="hljs-keyword">if</span> (params === <span class="hljs-literal">undefined</span> || params.length !== <span class="hljs-number">1</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"date_modify filter expects 1 argument"</span>);
+ }
+
+ <span class="hljs-keyword">var</span> modifyText = params[<span class="hljs-number">0</span>], time;
+
+ <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">"Date"</span>, value)) {
+ time = Twig.lib.strtotime(modifyText, value.getTime() / <span class="hljs-number">1000</span>);
+ }
+ <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">"String"</span>, value)) {
+ time = Twig.lib.strtotime(modifyText, Twig.lib.strtotime(value));
+ }
+ <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">"Number"</span>, value)) {
+ time = Twig.lib.strtotime(modifyText, value);
+ }
+
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(time * <span class="hljs-number">1000</span>);
+ },
+
+ replace: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span>||value === <span class="hljs-literal">null</span>){
+ <span class="hljs-keyword">return</span>;
+ }
+
+ <span class="hljs-keyword">var</span> pairs = params[<span class="hljs-number">0</span>],
+ tag;
+ <span class="hljs-keyword">for</span> (tag <span class="hljs-keyword">in</span> pairs) {
+ <span class="hljs-keyword">if</span> (pairs.hasOwnProperty(tag) &amp;&amp; tag !== <span class="hljs-string">"_keys"</span>) {
+ value = Twig.lib.replaceAll(value, tag, pairs[tag]);
+ }
+ }
+ <span class="hljs-keyword">return</span> value;
+ },
+
+ format: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span> || value === <span class="hljs-literal">null</span>){
+ <span class="hljs-keyword">return</span>;
+ }
+
+ <span class="hljs-keyword">return</span> Twig.lib.vsprintf(value, params);
+ },
+
+ striptags: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span> || value === <span class="hljs-literal">null</span>){
+ <span class="hljs-keyword">return</span>;
+ }
+
+ <span class="hljs-keyword">return</span> Twig.lib.strip_tags(value);
+ },
+
+ <span class="hljs-built_in">escape</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span>|| value === <span class="hljs-literal">null</span>){
+ <span class="hljs-keyword">return</span>;
+ }
+
+ <span class="hljs-keyword">var</span> strategy = <span class="hljs-string">"html"</span>;
+ <span class="hljs-keyword">if</span>(params &amp;&amp; params.length &amp;&amp; params[<span class="hljs-number">0</span>] !== <span class="hljs-literal">true</span>)
+ strategy = params[<span class="hljs-number">0</span>];
+
+ <span class="hljs-keyword">if</span>(strategy == <span class="hljs-string">"html"</span>) {
+ <span class="hljs-keyword">var</span> raw_value = value.toString().replace(<span class="hljs-regexp">/&amp;/g</span>, <span class="hljs-string">"&amp;amp;"</span>)
+ .replace(<span class="hljs-regexp">/&lt;/g</span>, <span class="hljs-string">"&amp;lt;"</span>)
+ .replace(<span class="hljs-regexp">/&gt;/g</span>, <span class="hljs-string">"&amp;gt;"</span>)
+ .replace(<span class="hljs-regexp">/"/g</span>, <span class="hljs-string">"&amp;quot;"</span>)
+ .replace(<span class="hljs-regexp">/'/g</span>, <span class="hljs-string">"&amp;#039;"</span>);
+ <span class="hljs-keyword">return</span> Twig.Markup(raw_value, <span class="hljs-string">'html'</span>);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(strategy == <span class="hljs-string">"js"</span>) {
+ <span class="hljs-keyword">var</span> raw_value = value.toString();
+ <span class="hljs-keyword">var</span> result = <span class="hljs-string">""</span>;
+
+ <span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; raw_value.length; i++) {
+ <span class="hljs-keyword">if</span>(raw_value[i].match(<span class="hljs-regexp">/^[a-zA-Z0-9,\._]$/</span>))
+ result += raw_value[i];
+ <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">var</span> char_code = raw_value.charCodeAt(i);
+
+ <span class="hljs-keyword">if</span>(char_code &lt; <span class="hljs-number">0x80</span>)
+ result += <span class="hljs-string">"\\x"</span> + char_code.toString(<span class="hljs-number">16</span>).toUpperCase();
+ <span class="hljs-keyword">else</span>
+ result += Twig.lib.sprintf(<span class="hljs-string">"\\u%04s"</span>, char_code.toString(<span class="hljs-number">16</span>).toUpperCase());
+ }
+ }
+
+ <span class="hljs-keyword">return</span> Twig.Markup(result, <span class="hljs-string">'js'</span>);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(strategy == <span class="hljs-string">"css"</span>) {
+ <span class="hljs-keyword">var</span> raw_value = value.toString();
+ <span class="hljs-keyword">var</span> result = <span class="hljs-string">""</span>;
+
+ <span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; raw_value.length; i++) {
+ <span class="hljs-keyword">if</span>(raw_value[i].match(<span class="hljs-regexp">/^[a-zA-Z0-9]$/</span>))
+ result += raw_value[i];
+ <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">var</span> char_code = raw_value.charCodeAt(i);
+ result += <span class="hljs-string">"\\"</span> + char_code.toString(<span class="hljs-number">16</span>).toUpperCase() + <span class="hljs-string">" "</span>;
+ }
+ }
+
+ <span class="hljs-keyword">return</span> Twig.Markup(result, <span class="hljs-string">'css'</span>);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(strategy == <span class="hljs-string">"url"</span>) {
+ <span class="hljs-keyword">var</span> result = Twig.filters.url_encode(value);
+ <span class="hljs-keyword">return</span> Twig.Markup(result, <span class="hljs-string">'url'</span>);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(strategy == <span class="hljs-string">"html_attr"</span>) {
+ <span class="hljs-keyword">var</span> raw_value = value.toString();
+ <span class="hljs-keyword">var</span> result = <span class="hljs-string">""</span>;
+
+ <span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; raw_value.length; i++) {
+ <span class="hljs-keyword">if</span>(raw_value[i].match(<span class="hljs-regexp">/^[a-zA-Z0-9,\.\-_]$/</span>))
+ result += raw_value[i];
+ <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(raw_value[i].match(<span class="hljs-regexp">/^[&amp;&lt;&gt;"]$/</span>))
+ result += raw_value[i].replace(<span class="hljs-regexp">/&amp;/g</span>, <span class="hljs-string">"&amp;amp;"</span>)
+ .replace(<span class="hljs-regexp">/&lt;/g</span>, <span class="hljs-string">"&amp;lt;"</span>)
+ .replace(<span class="hljs-regexp">/&gt;/g</span>, <span class="hljs-string">"&amp;gt;"</span>)
+ .replace(<span class="hljs-regexp">/"/g</span>, <span class="hljs-string">"&amp;quot;"</span>);
+ <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">var</span> char_code = raw_value.charCodeAt(i);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-312">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-312">&#182;</a>
+ </div>
+ <p>The following replaces characters undefined in HTML with
+the hex entity for the Unicode replacement character.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span>(char_code &lt;= <span class="hljs-number">0x1f</span> &amp;&amp; char_code != <span class="hljs-number">0x09</span> &amp;&amp; char_code != <span class="hljs-number">0x0a</span> &amp;&amp; char_code != <span class="hljs-number">0x0d</span>)
+ result += <span class="hljs-string">"&amp;#xFFFD;"</span>;
+ <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(char_code &lt; <span class="hljs-number">0x80</span>)
+ result += Twig.lib.sprintf(<span class="hljs-string">"&amp;#x%02s;"</span>, char_code.toString(<span class="hljs-number">16</span>).toUpperCase());
+ <span class="hljs-keyword">else</span>
+ result += Twig.lib.sprintf(<span class="hljs-string">"&amp;#x%04s;"</span>, char_code.toString(<span class="hljs-number">16</span>).toUpperCase());
+ }
+ }
+
+ <span class="hljs-keyword">return</span> Twig.Markup(result, <span class="hljs-string">'html_attr'</span>);
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"escape strategy unsupported"</span>);
+ }
+ },
+
+ <span class="hljs-comment">/* Alias of escape */</span>
+ <span class="hljs-string">"e"</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">return</span> Twig.filters.escape(value, params);
+ },
+
+ nl2br: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span> || value === <span class="hljs-literal">null</span>){
+ <span class="hljs-keyword">return</span>;
+ }
+ <span class="hljs-keyword">var</span> linebreak_tag = <span class="hljs-string">"BACKSLASH_n_replace"</span>,
+ br = <span class="hljs-string">"&lt;br /&gt;"</span> + linebreak_tag;
+
+ value = Twig.filters.escape(value)
+ .replace(<span class="hljs-regexp">/\r\n/g</span>, br)
+ .replace(<span class="hljs-regexp">/\r/g</span>, br)
+ .replace(<span class="hljs-regexp">/\n/g</span>, br);
+
+ value = Twig.lib.replaceAll(value, linebreak_tag, <span class="hljs-string">"\n"</span>);
+
+ <span class="hljs-keyword">return</span> Twig.Markup(value);
+ },
+
+ <span class="hljs-comment">/**
+ * Adapted from: http://phpjs.org/functions/number_format:481
+ */</span>
+ number_format: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">var</span> number = value,
+ decimals = (params &amp;&amp; params[<span class="hljs-number">0</span>]) ? params[<span class="hljs-number">0</span>] : <span class="hljs-literal">undefined</span>,
+ dec = (params &amp;&amp; params[<span class="hljs-number">1</span>] !== <span class="hljs-literal">undefined</span>) ? params[<span class="hljs-number">1</span>] : <span class="hljs-string">"."</span>,
+ sep = (params &amp;&amp; params[<span class="hljs-number">2</span>] !== <span class="hljs-literal">undefined</span>) ? params[<span class="hljs-number">2</span>] : <span class="hljs-string">","</span>;
+
+ number = (number + <span class="hljs-string">''</span>).replace(<span class="hljs-regexp">/[^0-9+\-Ee.]/g</span>, <span class="hljs-string">''</span>);
+ <span class="hljs-keyword">var</span> n = !<span class="hljs-built_in">isFinite</span>(+number) ? <span class="hljs-number">0</span> : +number,
+ prec = !<span class="hljs-built_in">isFinite</span>(+decimals) ? <span class="hljs-number">0</span> : <span class="hljs-built_in">Math</span>.abs(decimals),
+ s = <span class="hljs-string">''</span>,
+ toFixedFix = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">n, prec</span>) </span>{
+ <span class="hljs-keyword">var</span> k = <span class="hljs-built_in">Math</span>.pow(<span class="hljs-number">10</span>, prec);
+ <span class="hljs-keyword">return</span> <span class="hljs-string">''</span> + <span class="hljs-built_in">Math</span>.round(n * k) / k;
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-313">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-313">&#182;</a>
+ </div>
+ <p>Fix for IE parseFloat(0.55).toFixed(0) = 0;</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> s = (prec ? toFixedFix(n, prec) : <span class="hljs-string">''</span> + <span class="hljs-built_in">Math</span>.round(n)).split(<span class="hljs-string">'.'</span>);
+ <span class="hljs-keyword">if</span> (s[<span class="hljs-number">0</span>].length &gt; <span class="hljs-number">3</span>) {
+ s[<span class="hljs-number">0</span>] = s[<span class="hljs-number">0</span>].replace(<span class="hljs-regexp">/\B(?=(?:\d{3})+(?!\d))/g</span>, sep);
+ }
+ <span class="hljs-keyword">if</span> ((s[<span class="hljs-number">1</span>] || <span class="hljs-string">''</span>).length &lt; prec) {
+ s[<span class="hljs-number">1</span>] = s[<span class="hljs-number">1</span>] || <span class="hljs-string">''</span>;
+ s[<span class="hljs-number">1</span>] += <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(prec - s[<span class="hljs-number">1</span>].length + <span class="hljs-number">1</span>).join(<span class="hljs-string">'0'</span>);
+ }
+ <span class="hljs-keyword">return</span> s.join(dec);
+ },
+
+ trim: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span>|| value === <span class="hljs-literal">null</span>){
+ <span class="hljs-keyword">return</span>;
+ }
+
+ <span class="hljs-keyword">var</span> str = Twig.filters.escape( <span class="hljs-string">''</span> + value ),
+ whitespace;
+ <span class="hljs-keyword">if</span> ( params &amp;&amp; params[<span class="hljs-number">0</span>] ) {
+ whitespace = <span class="hljs-string">''</span> + params[<span class="hljs-number">0</span>];
+ } <span class="hljs-keyword">else</span> {
+ whitespace = <span class="hljs-string">' \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000'</span>;
+ }
+ <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; str.length; i++) {
+ <span class="hljs-keyword">if</span> (whitespace.indexOf(str.charAt(i)) === <span class="hljs-number">-1</span>) {
+ str = str.substring(i);
+ <span class="hljs-keyword">break</span>;
+ }
+ }
+ <span class="hljs-keyword">for</span> (i = str.length - <span class="hljs-number">1</span>; i &gt;= <span class="hljs-number">0</span>; i--) {
+ <span class="hljs-keyword">if</span> (whitespace.indexOf(str.charAt(i)) === <span class="hljs-number">-1</span>) {
+ str = str.substring(<span class="hljs-number">0</span>, i + <span class="hljs-number">1</span>);
+ <span class="hljs-keyword">break</span>;
+ }
+ }
+ <span class="hljs-keyword">return</span> whitespace.indexOf(str.charAt(<span class="hljs-number">0</span>)) === <span class="hljs-number">-1</span> ? str : <span class="hljs-string">''</span>;
+ },
+
+ truncate: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">var</span> length = <span class="hljs-number">30</span>,
+ preserve = <span class="hljs-literal">false</span>,
+ separator = <span class="hljs-string">'...'</span>;
+
+ value = value + <span class="hljs-string">''</span>;
+ <span class="hljs-keyword">if</span> (params) {
+ <span class="hljs-keyword">if</span> (params[<span class="hljs-number">0</span>]) {
+ length = params[<span class="hljs-number">0</span>];
+ }
+ <span class="hljs-keyword">if</span> (params[<span class="hljs-number">1</span>]) {
+ preserve = params[<span class="hljs-number">1</span>];
+ }
+ <span class="hljs-keyword">if</span> (params[<span class="hljs-number">2</span>]) {
+ separator = params[<span class="hljs-number">2</span>];
+ }
+ }
+
+ <span class="hljs-keyword">if</span> (value.length &gt; length) {
+
+ <span class="hljs-keyword">if</span> (preserve) {
+ length = value.indexOf(<span class="hljs-string">' '</span>, length);
+ <span class="hljs-keyword">if</span> (length === <span class="hljs-number">-1</span>) {
+ <span class="hljs-keyword">return</span> value;
+ }
+ }
+
+ value = value.substr(<span class="hljs-number">0</span>, length) + separator;
+ }
+
+ <span class="hljs-keyword">return</span> value;
+ },
+
+ slice: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span> || value === <span class="hljs-literal">null</span>) {
+ <span class="hljs-keyword">return</span>;
+ }
+ <span class="hljs-keyword">if</span> (params === <span class="hljs-literal">undefined</span> || params.length &lt; <span class="hljs-number">1</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"slice filter expects at least 1 argument"</span>);
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-314">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-314">&#182;</a>
+ </div>
+ <p>default to start of string</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> start = params[<span class="hljs-number">0</span>] || <span class="hljs-number">0</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-315">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-315">&#182;</a>
+ </div>
+ <p>default to length of string</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> length = params.length &gt; <span class="hljs-number">1</span> ? params[<span class="hljs-number">1</span>] : value.length;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-316">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-316">&#182;</a>
+ </div>
+ <p>handle negative start values</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> startIndex = start &gt;= <span class="hljs-number">0</span> ? start : <span class="hljs-built_in">Math</span>.max( value.length + start, <span class="hljs-number">0</span> );
+
+ <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">"Array"</span>, value)) {
+ <span class="hljs-keyword">var</span> output = [];
+ <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = startIndex; i &lt; startIndex + length &amp;&amp; i &lt; value.length; i++) {
+ output.push(value[i]);
+ }
+ <span class="hljs-keyword">return</span> output;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">"String"</span>, value)) {
+ <span class="hljs-keyword">return</span> value.substr(startIndex, length);
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"slice filter expects value to be an array or string"</span>);
+ }
+ },
+
+ abs: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span> || value === <span class="hljs-literal">null</span>) {
+ <span class="hljs-keyword">return</span>;
+ }
+
+ <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.abs(value);
+ },
+
+ first: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> (is(<span class="hljs-string">"Array"</span>, value)) {
+ <span class="hljs-keyword">return</span> value[<span class="hljs-number">0</span>];
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (is(<span class="hljs-string">"Object"</span>, value)) {
+ <span class="hljs-keyword">if</span> (<span class="hljs-string">'_keys'</span> <span class="hljs-keyword">in</span> value) {
+ <span class="hljs-keyword">return</span> value[value._keys[<span class="hljs-number">0</span>]];
+ }
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ( <span class="hljs-keyword">typeof</span> value === <span class="hljs-string">"string"</span> ) {
+ <span class="hljs-keyword">return</span> value.substr(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>);
+ }
+
+ <span class="hljs-keyword">return</span>;
+ },
+
+ split: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">undefined</span> || value === <span class="hljs-literal">null</span>) {
+ <span class="hljs-keyword">return</span>;
+ }
+ <span class="hljs-keyword">if</span> (params === <span class="hljs-literal">undefined</span> || params.length &lt; <span class="hljs-number">1</span> || params.length &gt; <span class="hljs-number">2</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"split filter expects 1 or 2 argument"</span>);
+ }
+ <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">"String"</span>, value)) {
+ <span class="hljs-keyword">var</span> delimiter = params[<span class="hljs-number">0</span>],
+ limit = params[<span class="hljs-number">1</span>],
+ split = value.split(delimiter);
+
+ <span class="hljs-keyword">if</span> (limit === <span class="hljs-literal">undefined</span>) {
+
+ <span class="hljs-keyword">return</span> split;
+
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (limit &lt; <span class="hljs-number">0</span>) {
+
+ <span class="hljs-keyword">return</span> value.split(delimiter, split.length + limit);
+
+ } <span class="hljs-keyword">else</span> {
+
+ <span class="hljs-keyword">var</span> limitedSplit = [];
+
+ <span class="hljs-keyword">if</span> (delimiter == <span class="hljs-string">''</span>) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-317">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-317">&#182;</a>
+ </div>
+ <p>empty delimiter
+“aabbcc”|split(‘’, 2)
+ -&gt; [‘aa’, ‘bb’, ‘cc’]</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ <span class="hljs-keyword">while</span>(split.length &gt; <span class="hljs-number">0</span>) {
+ <span class="hljs-keyword">var</span> temp = <span class="hljs-string">""</span>;
+ <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i=<span class="hljs-number">0</span>; i&lt;limit &amp;&amp; split.length &gt; <span class="hljs-number">0</span>; i++) {
+ temp += split.shift();
+ }
+ limitedSplit.push(temp);
+ }
+
+ } <span class="hljs-keyword">else</span> {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-318">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-318">&#182;</a>
+ </div>
+ <p>non-empty delimiter
+“one,two,three,four,five”|split(‘,’, 3)
+ -&gt; [‘one’, ‘two’, ‘three,four,five’]</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i=<span class="hljs-number">0</span>; i&lt;limit<span class="hljs-number">-1</span> &amp;&amp; split.length &gt; <span class="hljs-number">0</span>; i++) {
+ limitedSplit.push(split.shift());
+ }
+
+ <span class="hljs-keyword">if</span> (split.length &gt; <span class="hljs-number">0</span>) {
+ limitedSplit.push(split.join(delimiter));
+ }
+ }
+
+ <span class="hljs-keyword">return</span> limitedSplit;
+ }
+
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"split filter expects value to be a string"</span>);
+ }
+ },
+ last: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">'Object'</span>, value)) {
+ <span class="hljs-keyword">var</span> keys;
+
+ <span class="hljs-keyword">if</span> (value._keys === <span class="hljs-literal">undefined</span>) {
+ keys = <span class="hljs-built_in">Object</span>.keys(value);
+ } <span class="hljs-keyword">else</span> {
+ keys = value._keys;
+ }
+
+ <span class="hljs-keyword">return</span> value[keys[keys.length - <span class="hljs-number">1</span>]];
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-319">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-319">&#182;</a>
+ </div>
+ <p>string|array</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> value[value.length - <span class="hljs-number">1</span>];
+ },
+ raw: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">return</span> Twig.Markup(value);
+ },
+ batch: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">items, params</span>) </span>{
+ <span class="hljs-keyword">var</span> size = params.shift(),
+ fill = params.shift(),
+ result,
+ last,
+ missing;
+
+ <span class="hljs-keyword">if</span> (!Twig.lib.is(<span class="hljs-string">"Array"</span>, items)) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"batch filter expects items to be an array"</span>);
+ }
+
+ <span class="hljs-keyword">if</span> (!Twig.lib.is(<span class="hljs-string">"Number"</span>, size)) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"batch filter expects size to be a number"</span>);
+ }
+
+ size = <span class="hljs-built_in">Math</span>.ceil(size);
+
+ result = Twig.lib.chunkArray(items, size);
+
+ <span class="hljs-keyword">if</span> (fill &amp;&amp; items.length % size != <span class="hljs-number">0</span>) {
+ last = result.pop();
+ missing = size - last.length;
+
+ <span class="hljs-keyword">while</span> (missing--) {
+ last.push(fill);
+ }
+
+ result.push(last);
+ }
+
+ <span class="hljs-keyword">return</span> result;
+ },
+ round: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ params = params || [];
+
+ <span class="hljs-keyword">var</span> precision = params.length &gt; <span class="hljs-number">0</span> ? params[<span class="hljs-number">0</span>] : <span class="hljs-number">0</span>,
+ method = params.length &gt; <span class="hljs-number">1</span> ? params[<span class="hljs-number">1</span>] : <span class="hljs-string">"common"</span>;
+
+ value = <span class="hljs-built_in">parseFloat</span>(value);
+
+ <span class="hljs-keyword">if</span>(precision &amp;&amp; !Twig.lib.is(<span class="hljs-string">"Number"</span>, precision)) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"round filter expects precision to be a number"</span>);
+ }
+
+ <span class="hljs-keyword">if</span> (method === <span class="hljs-string">"common"</span>) {
+ <span class="hljs-keyword">return</span> Twig.lib.round(value, precision);
+ }
+
+ <span class="hljs-keyword">if</span>(!Twig.lib.is(<span class="hljs-string">"Function"</span>, <span class="hljs-built_in">Math</span>[method])) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"round filter expects method to be 'floor', 'ceil', or 'common'"</span>);
+ }
+
+ <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>[method](value * <span class="hljs-built_in">Math</span>.pow(<span class="hljs-number">10</span>, precision)) / <span class="hljs-built_in">Math</span>.pow(<span class="hljs-number">10</span>, precision);
+ }
+ };
+
+ Twig.filter = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">filter, value, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (!Twig.filters[filter]) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-string">"Unable to find filter "</span> + filter;
+ }
+ <span class="hljs-keyword">return</span> Twig.filters[filter].apply(<span class="hljs-keyword">this</span>, [value, params]);
+ };
+
+ Twig.filter.extend = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">filter, definition</span>) </span>{
+ Twig.filters[filter] = definition;
+ };
+
+ <span class="hljs-keyword">return</span> Twig;
+
+})(Twig || { });</pre></div></div>
+
+ </li>
+
+
+ <li id="section-320">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-320">&#182;</a>
+ </div>
+ <pre><code>Twig.js
+ <span class="hljs-number">2012</span> Hadrien Lanneau
+Available under the BSD <span class="hljs-number">2</span>-Clause License
+https:<span class="hljs-comment">//github.com/justjohn/twig.js</span>
+</code></pre>
+ </div>
+
+ </li>
+
+
+ <li id="section-321">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-321">&#182;</a>
+ </div>
+ <h2 id="twig-functions-js">twig.functions.js</h2>
+<p>This file handles parsing filters.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> Twig = (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Twig</span>) </span>{
+ <span class="hljs-comment">/**
+ * @constant
+ * @type {string}
+ */</span>
+ <span class="hljs-keyword">var</span> TEMPLATE_NOT_FOUND_MESSAGE = <span class="hljs-string">'Template "{name}" is not defined.'</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-322">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-322">&#182;</a>
+ </div>
+ <p>Determine object type</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">is</span>(<span class="hljs-params">type, obj</span>) </span>{
+ <span class="hljs-keyword">var</span> clas = <span class="hljs-built_in">Object</span>.prototype.toString.call(obj).slice(<span class="hljs-number">8</span>, <span class="hljs-number">-1</span>);
+ <span class="hljs-keyword">return</span> obj !== <span class="hljs-literal">undefined</span> &amp;&amp; obj !== <span class="hljs-literal">null</span> &amp;&amp; clas === type;
+ }
+
+ Twig.functions = {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-323">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-323">&#182;</a>
+ </div>
+ <p> attribute, block, constant, date, dump, parent, random,.</p>
+
+ </div>
+
+ </li>
+
+
+ <li id="section-324">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-324">&#182;</a>
+ </div>
+ <p>Range function from <a href="http://phpjs.org/functions/range:499">http://phpjs.org/functions/range:499</a>
+Used under an MIT License</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> range: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">low, high, step</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-325">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-325">&#182;</a>
+ </div>
+ <p><a href="http://kevin.vanzonneveld.net">http://kevin.vanzonneveld.net</a></p>
+<ul>
+<li>original by: Waldo Malqui Silva</li>
+<li>example 1: range ( 0, 12 );</li>
+<li>returns 1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]</li>
+<li>example 2: range( 0, 100, 10 );</li>
+<li>returns 2: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]</li>
+<li>example 3: range( ‘a’, ‘i’ );</li>
+<li>returns 3: [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’, ‘i’]</li>
+<li>example 4: range( ‘c’, ‘a’ );</li>
+<li>returns 4: [‘c’, ‘b’, ‘a’]</li>
+</ul>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> matrix = [];
+ <span class="hljs-keyword">var</span> inival, endval, plus;
+ <span class="hljs-keyword">var</span> walker = step || <span class="hljs-number">1</span>;
+ <span class="hljs-keyword">var</span> chars = <span class="hljs-literal">false</span>;
+
+ <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">isNaN</span>(low) &amp;&amp; !<span class="hljs-built_in">isNaN</span>(high)) {
+ inival = <span class="hljs-built_in">parseInt</span>(low, <span class="hljs-number">10</span>);
+ endval = <span class="hljs-built_in">parseInt</span>(high, <span class="hljs-number">10</span>);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">isNaN</span>(low) &amp;&amp; <span class="hljs-built_in">isNaN</span>(high)) {
+ chars = <span class="hljs-literal">true</span>;
+ inival = low.charCodeAt(<span class="hljs-number">0</span>);
+ endval = high.charCodeAt(<span class="hljs-number">0</span>);
+ } <span class="hljs-keyword">else</span> {
+ inival = (<span class="hljs-built_in">isNaN</span>(low) ? <span class="hljs-number">0</span> : low);
+ endval = (<span class="hljs-built_in">isNaN</span>(high) ? <span class="hljs-number">0</span> : high);
+ }
+
+ plus = ((inival &gt; endval) ? <span class="hljs-literal">false</span> : <span class="hljs-literal">true</span>);
+ <span class="hljs-keyword">if</span> (plus) {
+ <span class="hljs-keyword">while</span> (inival &lt;= endval) {
+ matrix.push(((chars) ? <span class="hljs-built_in">String</span>.fromCharCode(inival) : inival));
+ inival += walker;
+ }
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">while</span> (inival &gt;= endval) {
+ matrix.push(((chars) ? <span class="hljs-built_in">String</span>.fromCharCode(inival) : inival));
+ inival -= walker;
+ }
+ }
+
+ <span class="hljs-keyword">return</span> matrix;
+ },
+ cycle: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">arr, i</span>) </span>{
+ <span class="hljs-keyword">var</span> pos = i % arr.length;
+ <span class="hljs-keyword">return</span> arr[pos];
+ },
+ dump: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
+ <span class="hljs-keyword">var</span> EOL = <span class="hljs-string">'\n'</span>,
+ indentChar = <span class="hljs-string">' '</span>,
+ indentTimes = <span class="hljs-number">0</span>,
+ out = <span class="hljs-string">''</span>,
+ args = <span class="hljs-built_in">Array</span>.prototype.slice.call(<span class="hljs-built_in">arguments</span>),
+ indent = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">times</span>) </span>{
+ <span class="hljs-keyword">var</span> ind = <span class="hljs-string">''</span>;
+ <span class="hljs-keyword">while</span> (times &gt; <span class="hljs-number">0</span>) {
+ times--;
+ ind += indentChar;
+ }
+ <span class="hljs-keyword">return</span> ind;
+ },
+ displayVar = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">variable</span>) </span>{
+ out += indent(indentTimes);
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span>(variable) === <span class="hljs-string">'object'</span>) {
+ dumpVar(variable);
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span>(variable) === <span class="hljs-string">'function'</span>) {
+ out += <span class="hljs-string">'function()'</span> + EOL;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span>(variable) === <span class="hljs-string">'string'</span>) {
+ out += <span class="hljs-string">'string('</span> + variable.length + <span class="hljs-string">') "'</span> + variable + <span class="hljs-string">'"'</span> + EOL;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span>(variable) === <span class="hljs-string">'number'</span>) {
+ out += <span class="hljs-string">'number('</span> + variable + <span class="hljs-string">')'</span> + EOL;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span>(variable) === <span class="hljs-string">'boolean'</span>) {
+ out += <span class="hljs-string">'bool('</span> + variable + <span class="hljs-string">')'</span> + EOL;
+ }
+ },
+ dumpVar = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">variable</span>) </span>{
+ <span class="hljs-keyword">var</span> i;
+ <span class="hljs-keyword">if</span> (variable === <span class="hljs-literal">null</span>) {
+ out += <span class="hljs-string">'NULL'</span> + EOL;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (variable === <span class="hljs-literal">undefined</span>) {
+ out += <span class="hljs-string">'undefined'</span> + EOL;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> variable === <span class="hljs-string">'object'</span>) {
+ out += indent(indentTimes) + <span class="hljs-keyword">typeof</span>(variable);
+ indentTimes++;
+ out += <span class="hljs-string">'('</span> + (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">obj</span>) </span>{
+ <span class="hljs-keyword">var</span> size = <span class="hljs-number">0</span>, key;
+ <span class="hljs-keyword">for</span> (key <span class="hljs-keyword">in</span> obj) {
+ <span class="hljs-keyword">if</span> (obj.hasOwnProperty(key)) {
+ size++;
+ }
+ }
+ <span class="hljs-keyword">return</span> size;
+ })(variable) + <span class="hljs-string">') {'</span> + EOL;
+ <span class="hljs-keyword">for</span> (i <span class="hljs-keyword">in</span> variable) {
+ out += indent(indentTimes) + <span class="hljs-string">'['</span> + i + <span class="hljs-string">']=&gt; '</span> + EOL;
+ displayVar(variable[i]);
+ }
+ indentTimes--;
+ out += indent(indentTimes) + <span class="hljs-string">'}'</span> + EOL;
+ } <span class="hljs-keyword">else</span> {
+ displayVar(variable);
+ }
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-326">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-326">&#182;</a>
+ </div>
+ <p>handle no argument case by dumping the entire render context</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (args.length == <span class="hljs-number">0</span>) args.push(<span class="hljs-keyword">this</span>.context);
+
+ Twig.forEach(args, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">variable</span>) </span>{
+ dumpVar(variable);
+ });
+
+ <span class="hljs-keyword">return</span> out;
+ },
+ date: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">date, time</span>) </span>{
+ <span class="hljs-keyword">var</span> dateObj;
+ <span class="hljs-keyword">if</span> (date === <span class="hljs-literal">undefined</span>) {
+ dateObj = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">"Date"</span>, date)) {
+ dateObj = date;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">"String"</span>, date)) {
+ <span class="hljs-keyword">if</span> (date.match(<span class="hljs-regexp">/^[0-9]+$/</span>)) {
+ dateObj = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(date * <span class="hljs-number">1000</span>);
+ }
+ <span class="hljs-keyword">else</span> {
+ dateObj = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(Twig.lib.strtotime(date) * <span class="hljs-number">1000</span>);
+ }
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">"Number"</span>, date)) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-327">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-327">&#182;</a>
+ </div>
+ <p>timestamp</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> dateObj = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(date * <span class="hljs-number">1000</span>);
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Unable to parse date "</span> + date);
+ }
+ <span class="hljs-keyword">return</span> dateObj;
+ },
+ block: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">block</span>) </span>{
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.originalBlockTokens[block]) {
+ <span class="hljs-keyword">return</span> Twig.logic.parse.apply(<span class="hljs-keyword">this</span>, [<span class="hljs-keyword">this</span>.originalBlockTokens[block], <span class="hljs-keyword">this</span>.context]).output;
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.blocks[block];
+ }
+ },
+ parent: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-328">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-328">&#182;</a>
+ </div>
+ <p>Add a placeholder</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> Twig.placeholders.parent;
+ },
+ attribute: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">object, method, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (Twig.lib.is(<span class="hljs-string">'Object'</span>, object)) {
+ <span class="hljs-keyword">if</span> (object.hasOwnProperty(method)) {
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object[method] === <span class="hljs-string">"function"</span>) {
+ <span class="hljs-keyword">return</span> object[method].apply(<span class="hljs-literal">undefined</span>, params);
+ }
+ <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">return</span> object[method];
+ }
+ }
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-329">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-329">&#182;</a>
+ </div>
+ <p>Array will return element 0-index</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> object[method] || <span class="hljs-literal">undefined</span>;
+ },
+ max: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">values</span>) </span>{
+ <span class="hljs-keyword">if</span>(Twig.lib.is(<span class="hljs-string">"Object"</span>, values)) {
+ <span class="hljs-keyword">delete</span> values[<span class="hljs-string">"_keys"</span>];
+ <span class="hljs-keyword">return</span> Twig.lib.max(values);
+ }
+
+ <span class="hljs-keyword">return</span> Twig.lib.max.apply(<span class="hljs-literal">null</span>, <span class="hljs-built_in">arguments</span>);
+ },
+ min: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">values</span>) </span>{
+ <span class="hljs-keyword">if</span>(Twig.lib.is(<span class="hljs-string">"Object"</span>, values)) {
+ <span class="hljs-keyword">delete</span> values[<span class="hljs-string">"_keys"</span>];
+ <span class="hljs-keyword">return</span> Twig.lib.min(values);
+ }
+
+ <span class="hljs-keyword">return</span> Twig.lib.min.apply(<span class="hljs-literal">null</span>, <span class="hljs-built_in">arguments</span>);
+ },
+ template_from_string: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">template</span>) </span>{
+ <span class="hljs-keyword">if</span> (template === <span class="hljs-literal">undefined</span>) {
+ template = <span class="hljs-string">''</span>;
+ }
+ <span class="hljs-keyword">return</span> Twig.Templates.parsers.twig({
+ options: <span class="hljs-keyword">this</span>.options,
+ data: template
+ });
+ },
+ random: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">var</span> LIMIT_INT31 = <span class="hljs-number">0x80000000</span>;
+
+ <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getRandomNumber</span>(<span class="hljs-params">n</span>) </span>{
+ <span class="hljs-keyword">var</span> random = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * LIMIT_INT31);
+ <span class="hljs-keyword">var</span> limits = [<span class="hljs-number">0</span>, n];
+ <span class="hljs-keyword">var</span> min = <span class="hljs-built_in">Math</span>.min.apply(<span class="hljs-literal">null</span>, limits),
+ max = <span class="hljs-built_in">Math</span>.max.apply(<span class="hljs-literal">null</span>, limits);
+ <span class="hljs-keyword">return</span> min + <span class="hljs-built_in">Math</span>.floor((max - min + <span class="hljs-number">1</span>) * random / LIMIT_INT31);
+ }
+
+ <span class="hljs-keyword">if</span>(Twig.lib.is(<span class="hljs-string">"Number"</span>, value)) {
+ <span class="hljs-keyword">return</span> getRandomNumber(value);
+ }
+
+ <span class="hljs-keyword">if</span>(Twig.lib.is(<span class="hljs-string">"String"</span>, value)) {
+ <span class="hljs-keyword">return</span> value.charAt(getRandomNumber(value.length<span class="hljs-number">-1</span>));
+ }
+
+ <span class="hljs-keyword">if</span>(Twig.lib.is(<span class="hljs-string">"Array"</span>, value)) {
+ <span class="hljs-keyword">return</span> value[getRandomNumber(value.length<span class="hljs-number">-1</span>)];
+ }
+
+ <span class="hljs-keyword">if</span>(Twig.lib.is(<span class="hljs-string">"Object"</span>, value)) {
+ <span class="hljs-keyword">var</span> keys = <span class="hljs-built_in">Object</span>.keys(value);
+ <span class="hljs-keyword">return</span> value[keys[getRandomNumber(keys.length<span class="hljs-number">-1</span>)]];
+ }
+
+ <span class="hljs-keyword">return</span> getRandomNumber(LIMIT_INT31<span class="hljs-number">-1</span>);
+ },
+
+ <span class="hljs-comment">/**
+ * Returns the content of a template without rendering it
+ * @param {string} name
+ * @param {boolean} [ignore_missing=false]
+ * @returns {string}
+ */</span>
+ source: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">name, ignore_missing</span>) </span>{
+ <span class="hljs-keyword">var</span> templateSource;
+ <span class="hljs-keyword">var</span> templateFound = <span class="hljs-literal">false</span>;
+ <span class="hljs-keyword">var</span> isNodeEnvironment = <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">module</span> !== <span class="hljs-string">'undefined'</span> &amp;&amp; <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">module</span>.exports !== <span class="hljs-string">'undefined'</span> &amp;&amp; <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">window</span> === <span class="hljs-string">'undefined'</span>;
+ <span class="hljs-keyword">var</span> loader;
+ <span class="hljs-keyword">var</span> path;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-330">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-330">&#182;</a>
+ </div>
+ <p>if we are running in a node.js environment, set the loader to ‘fs’ and ensure the
+path is relative to the CWD of the running script
+else, set the loader to ‘ajax’ and set the path to the value of name</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (isNodeEnvironment) {
+ loader = <span class="hljs-string">'fs'</span>;
+ path = __dirname + <span class="hljs-string">'/'</span> + name;
+ } <span class="hljs-keyword">else</span> {
+ loader = <span class="hljs-string">'ajax'</span>;
+ path = name;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-331">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-331">&#182;</a>
+ </div>
+ <p>build the params object</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> params = {
+ id: name,
+ path: path,
+ method: loader,
+ parser: <span class="hljs-string">'source'</span>,
+ <span class="hljs-keyword">async</span>: <span class="hljs-literal">false</span>,
+ fetchTemplateSource: <span class="hljs-literal">true</span>
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-332">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-332">&#182;</a>
+ </div>
+ <p>default ignore_missing to false</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> ignore_missing === <span class="hljs-string">'undefined'</span>) {
+ ignore_missing = <span class="hljs-literal">false</span>;
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-333">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-333">&#182;</a>
+ </div>
+ <p>try to load the remote template</p>
+<p>on exception, log it</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">try</span> {
+ templateSource = Twig.Templates.loadRemote(name, params);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-334">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-334">&#182;</a>
+ </div>
+ <p>if the template is undefined or null, set the template to an empty string and do NOT flip the
+boolean indicating we found the template</p>
+<p>else, all is good! flip the boolean indicating we found the template</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> templateSource === <span class="hljs-string">'undefined'</span> || templateSource === <span class="hljs-literal">null</span>) {
+ templateSource = <span class="hljs-string">''</span>;
+ } <span class="hljs-keyword">else</span> {
+ templateFound = <span class="hljs-literal">true</span>;
+ }
+ } <span class="hljs-keyword">catch</span> (e) {
+ Twig.log.debug(<span class="hljs-string">'Twig.functions.source: '</span>, <span class="hljs-string">'Problem loading template '</span>, e);
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-335">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-335">&#182;</a>
+ </div>
+ <p>if the template was NOT found AND we are not ignoring missing templates, return the same message
+that is returned by the PHP implementation of the twig source() function</p>
+<p>else, return the template source</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (!templateFound &amp;&amp; !ignore_missing) {
+ <span class="hljs-keyword">return</span> TEMPLATE_NOT_FOUND_MESSAGE.replace(<span class="hljs-string">'{name}'</span>, name);
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">return</span> templateSource;
+ }
+ }
+ };
+
+ Twig._function = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">_function, value, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (!Twig.functions[_function]) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-string">"Unable to find function "</span> + _function;
+ }
+ <span class="hljs-keyword">return</span> Twig.functions[_function](value, params);
+ };
+
+ Twig._function.extend = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">_function, definition</span>) </span>{
+ Twig.functions[_function] = definition;
+ };
+
+ <span class="hljs-keyword">return</span> Twig;
+
+})(Twig || { });</pre></div></div>
+
+ </li>
+
+
+ <li id="section-336">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-336">&#182;</a>
+ </div>
+ <pre><code>Twig.js
+Available under the BSD <span class="hljs-number">2</span>-Clause License
+https:<span class="hljs-comment">//github.com/justjohn/twig.js</span>
+</code></pre>
+ </div>
+
+ </li>
+
+
+ <li id="section-337">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-337">&#182;</a>
+ </div>
+ <h2 id="twig-path-js">twig.path.js</h2>
+<p>This file handles path parsing</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> Twig = (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Twig</span>) </span>{
+<span class="hljs-meta"> "use strict"</span>;
+
+ <span class="hljs-comment">/**
+ * Namespace for path handling.
+ */</span>
+ Twig.path = {};
+
+ <span class="hljs-comment">/**
+ * Generate the canonical version of a url based on the given base path and file path and in
+ * the previously registered namespaces.
+ *
+ * @param {string} template The Twig Template
+ * @param {string} file The file path, may be relative and may contain namespaces.
+ *
+ * @return {string} The canonical version of the path
+ */</span>
+ Twig.path.parsePath = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">template, file</span>) </span>{
+ <span class="hljs-keyword">var</span> namespaces = <span class="hljs-literal">null</span>,
+ file = file || <span class="hljs-string">""</span>;
+
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> template === <span class="hljs-string">'object'</span> &amp;&amp; <span class="hljs-keyword">typeof</span> template.options === <span class="hljs-string">'object'</span>) {
+ namespaces = template.options.namespaces;
+ }
+
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> namespaces === <span class="hljs-string">'object'</span> &amp;&amp; (file.indexOf(<span class="hljs-string">'::'</span>) &gt; <span class="hljs-number">0</span>) || file.indexOf(<span class="hljs-string">'@'</span>) &gt;= <span class="hljs-number">0</span>){
+ <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> k <span class="hljs-keyword">in</span> namespaces){
+ <span class="hljs-keyword">if</span> (namespaces.hasOwnProperty(k)) {
+ file = file.replace(k + <span class="hljs-string">'::'</span>, namespaces[k]);
+ file = file.replace(<span class="hljs-string">'@'</span> + k, namespaces[k]);
+ }
+ }
+
+ <span class="hljs-keyword">return</span> file;
+ }
+
+ <span class="hljs-keyword">return</span> Twig.path.relativePath(template, file);
+ };
+
+ <span class="hljs-comment">/**
+ * Generate the relative canonical version of a url based on the given base path and file path.
+ *
+ * @param {Twig.Template} template The Twig.Template.
+ * @param {string} file The file path, relative to the base path.
+ *
+ * @return {string} The canonical version of the path.
+ */</span>
+ Twig.path.relativePath = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">template, file</span>) </span>{
+ <span class="hljs-keyword">var</span> base,
+ base_path,
+ sep_chr = <span class="hljs-string">"/"</span>,
+ new_path = [],
+ file = file || <span class="hljs-string">""</span>,
+ val;
+
+ <span class="hljs-keyword">if</span> (template.url) {
+ <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> template.base !== <span class="hljs-string">'undefined'</span>) {
+ base = template.base + ((template.base.charAt(template.base.length<span class="hljs-number">-1</span>) === <span class="hljs-string">'/'</span>) ? <span class="hljs-string">''</span> : <span class="hljs-string">'/'</span>);
+ } <span class="hljs-keyword">else</span> {
+ base = template.url;
+ }
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (template.path) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-338">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-338">&#182;</a>
+ </div>
+ <p>Get the system-specific path separator</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">"path"</span>),
+ sep = path.sep || sep_chr,
+ relative = <span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">"^\\.{1,2}"</span> + sep.replace(<span class="hljs-string">"\\"</span>, <span class="hljs-string">"\\\\"</span>));
+ file = file.replace(<span class="hljs-regexp">/\//g</span>, sep);
+
+ <span class="hljs-keyword">if</span> (template.base !== <span class="hljs-literal">undefined</span> &amp;&amp; file.match(relative) == <span class="hljs-literal">null</span>) {
+ file = file.replace(template.base, <span class="hljs-string">''</span>);
+ base = template.base + sep;
+ } <span class="hljs-keyword">else</span> {
+ base = path.normalize(template.path);
+ }
+
+ base = base.replace(sep+sep, sep);
+ sep_chr = sep;
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ((template.name || template.id) &amp;&amp; template.method &amp;&amp; template.method !== <span class="hljs-string">'fs'</span> &amp;&amp; template.method !== <span class="hljs-string">'ajax'</span>) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-339">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-339">&#182;</a>
+ </div>
+ <p>Custom registered loader</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> base = template.base || template.name || template.id;
+ } <span class="hljs-keyword">else</span> {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Cannot extend an inline template."</span>);
+ }
+
+ base_path = base.split(sep_chr);</pre></div></div>
+
+ </li>
+
+
+ <li id="section-340">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-340">&#182;</a>
+ </div>
+ <p>Remove file from url</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> base_path.pop();
+ base_path = base_path.concat(file.split(sep_chr));
+
+ <span class="hljs-keyword">while</span> (base_path.length &gt; <span class="hljs-number">0</span>) {
+ val = base_path.shift();
+ <span class="hljs-keyword">if</span> (val == <span class="hljs-string">"."</span>) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-341">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-341">&#182;</a>
+ </div>
+ <p>Ignore</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (val == <span class="hljs-string">".."</span> &amp;&amp; new_path.length &gt; <span class="hljs-number">0</span> &amp;&amp; new_path[new_path.length<span class="hljs-number">-1</span>] != <span class="hljs-string">".."</span>) {
+ new_path.pop();
+ } <span class="hljs-keyword">else</span> {
+ new_path.push(val);
+ }
+ }
+
+ <span class="hljs-keyword">return</span> new_path.join(sep_chr);
+ };
+
+ <span class="hljs-keyword">return</span> Twig;
+}) (Twig || { });</pre></div></div>
+
+ </li>
+
+
+ <li id="section-342">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-342">&#182;</a>
+ </div>
+ <pre><code>Twig.js
+Available under the BSD <span class="hljs-number">2</span>-Clause License
+https:<span class="hljs-comment">//github.com/justjohn/twig.js</span>
+</code></pre>
+ </div>
+
+ </li>
+
+
+ <li id="section-343">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-343">&#182;</a>
+ </div>
+ <h2 id="twig-tests-js">twig.tests.js</h2>
+<p>This file handles expression tests. (is empty, is not defined, etc…)</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> Twig = (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Twig</span>) </span>{
+<span class="hljs-meta"> "use strict"</span>;
+ Twig.tests = {
+ empty: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">null</span> || value === <span class="hljs-literal">undefined</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-344">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-344">&#182;</a>
+ </div>
+ <p>Handler numbers</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> value === <span class="hljs-string">"number"</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; <span class="hljs-comment">// numbers are never "empty"</span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-345">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-345">&#182;</a>
+ </div>
+ <p>Handle strings and arrays</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (value.length &amp;&amp; value.length &gt; <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-346">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-346">&#182;</a>
+ </div>
+ <p>Handle objects</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> key <span class="hljs-keyword">in</span> value) {
+ <span class="hljs-keyword">if</span> (value.hasOwnProperty(key)) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
+ }
+ <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
+ },
+ odd: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">return</span> value % <span class="hljs-number">2</span> === <span class="hljs-number">1</span>;
+ },
+ even: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">return</span> value % <span class="hljs-number">2</span> === <span class="hljs-number">0</span>;
+ },
+ divisibleby: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">return</span> value % params[<span class="hljs-number">0</span>] === <span class="hljs-number">0</span>;
+ },
+ defined: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">return</span> value !== <span class="hljs-literal">undefined</span>;
+ },
+ none: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">return</span> value === <span class="hljs-literal">null</span>;
+ },
+ <span class="hljs-string">'null'</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.none(value); <span class="hljs-comment">// Alias of none</span>
+ },
+ sameas: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value, params</span>) </span>{
+ <span class="hljs-keyword">return</span> value === params[<span class="hljs-number">0</span>];
+ },
+ iterable: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{
+ <span class="hljs-keyword">return</span> value &amp;&amp; (Twig.lib.is(<span class="hljs-string">"Array"</span>, value) || Twig.lib.is(<span class="hljs-string">"Object"</span>, value));
+ }
+ <span class="hljs-comment">/*
+ constant ?
+ */</span>
+ };
+
+ Twig.test = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">test, value, params</span>) </span>{
+ <span class="hljs-keyword">if</span> (!Twig.tests[test]) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-string">"Test "</span> + test + <span class="hljs-string">" is not defined."</span>;
+ }
+ <span class="hljs-keyword">return</span> Twig.tests[test](value, params);
+ };
+
+ Twig.test.extend = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">test, definition</span>) </span>{
+ Twig.tests[test] = definition;
+ };
+
+ <span class="hljs-keyword">return</span> Twig;
+})( Twig || { } );</pre></div></div>
+
+ </li>
+
+
+ <li id="section-347">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-347">&#182;</a>
+ </div>
+ <pre><code>Twig.js
+Available under the BSD <span class="hljs-number">2</span>-Clause License
+https:<span class="hljs-comment">//github.com/justjohn/twig.js</span>
+</code></pre>
+ </div>
+
+ </li>
+
+
+ <li id="section-348">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-348">&#182;</a>
+ </div>
+ <h2 id="twig-exports-js">twig.exports.js</h2>
+<p>This file provides extension points and other hooks into the twig functionality.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+<span class="hljs-keyword">var</span> Twig = (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Twig</span>) </span>{
+<span class="hljs-meta"> "use strict"</span>;
+ Twig.exports = {
+ VERSION: Twig.VERSION
+ };
+
+ <span class="hljs-comment">/**
+ * Create and compile a twig.js template.
+ *
+ * @param {Object} param Paramteres for creating a Twig template.
+ *
+ * @return {Twig.Template} A Twig template ready for rendering.
+ */</span>
+ Twig.exports.twig = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">twig</span>(<span class="hljs-params">params</span>) </span>{
+<span class="hljs-meta"> 'use strict'</span>;
+ <span class="hljs-keyword">var</span> id = params.id,
+ options = {
+ strict_variables: params.strict_variables || <span class="hljs-literal">false</span>,</pre></div></div>
+
+ </li>
+
+
+ <li id="section-349">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-349">&#182;</a>
+ </div>
+ <p>TODO: turn autoscape on in the next major version</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> autoescape: params.autoescape != <span class="hljs-literal">null</span> &amp;&amp; params.autoescape || <span class="hljs-literal">false</span>,
+ allowInlineIncludes: params.allowInlineIncludes || <span class="hljs-literal">false</span>,
+ rethrow: params.rethrow || <span class="hljs-literal">false</span>,
+ namespaces: params.namespaces
+ };
+
+ <span class="hljs-keyword">if</span> (Twig.cache &amp;&amp; id) {
+ Twig.validateId(id);
+ }
+
+ <span class="hljs-keyword">if</span> (params.debug !== <span class="hljs-literal">undefined</span>) {
+ Twig.debug = params.debug;
+ }
+ <span class="hljs-keyword">if</span> (params.trace !== <span class="hljs-literal">undefined</span>) {
+ Twig.trace = params.trace;
+ }
+
+ <span class="hljs-keyword">if</span> (params.data !== <span class="hljs-literal">undefined</span>) {
+ <span class="hljs-keyword">return</span> Twig.Templates.parsers.twig({
+ data: params.data,
+ path: params.hasOwnProperty(<span class="hljs-string">'path'</span>) ? params.path : <span class="hljs-literal">undefined</span>,
+ <span class="hljs-built_in">module</span>: params.module,
+ id: id,
+ options: options
+ });
+
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (params.ref !== <span class="hljs-literal">undefined</span>) {
+ <span class="hljs-keyword">if</span> (params.id !== <span class="hljs-literal">undefined</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Both ref and id cannot be set on a twig.js template."</span>);
+ }
+ <span class="hljs-keyword">return</span> Twig.Templates.load(params.ref);
+
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (params.method !== <span class="hljs-literal">undefined</span>) {
+ <span class="hljs-keyword">if</span> (!Twig.Templates.isRegisteredLoader(params.method)) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">'Loader for "'</span> + params.method + <span class="hljs-string">'" is not defined.'</span>);
+ }
+ <span class="hljs-keyword">return</span> Twig.Templates.loadRemote(params.name || params.href || params.path || id || <span class="hljs-literal">undefined</span>, {
+ id: id,
+ method: params.method,
+ parser: params.parser || <span class="hljs-string">'twig'</span>,
+ base: params.base,
+ <span class="hljs-built_in">module</span>: params.module,
+ precompiled: params.precompiled,
+ <span class="hljs-keyword">async</span>: params.async,
+ options: options
+
+ }, params.load, params.error);
+
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (params.href !== <span class="hljs-literal">undefined</span>) {
+ <span class="hljs-keyword">return</span> Twig.Templates.loadRemote(params.href, {
+ id: id,
+ method: <span class="hljs-string">'ajax'</span>,
+ parser: params.parser || <span class="hljs-string">'twig'</span>,
+ base: params.base,
+ <span class="hljs-built_in">module</span>: params.module,
+ precompiled: params.precompiled,
+ <span class="hljs-keyword">async</span>: params.async,
+ options: options
+
+ }, params.load, params.error);
+
+ } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (params.path !== <span class="hljs-literal">undefined</span>) {
+ <span class="hljs-keyword">return</span> Twig.Templates.loadRemote(params.path, {
+ id: id,
+ method: <span class="hljs-string">'fs'</span>,
+ parser: params.parser || <span class="hljs-string">'twig'</span>,
+ base: params.base,
+ <span class="hljs-built_in">module</span>: params.module,
+ precompiled: params.precompiled,
+ <span class="hljs-keyword">async</span>: params.async,
+ options: options
+
+ }, params.load, params.error);
+ }
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-350">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-350">&#182;</a>
+ </div>
+ <p>Extend Twig with a new filter.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.exports.extendFilter = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">filter, definition</span>) </span>{
+ Twig.filter.extend(filter, definition);
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-351">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-351">&#182;</a>
+ </div>
+ <p>Extend Twig with a new function.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.exports.extendFunction = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">fn, definition</span>) </span>{
+ Twig._function.extend(fn, definition);
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-352">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-352">&#182;</a>
+ </div>
+ <p>Extend Twig with a new test.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.exports.extendTest = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">test, definition</span>) </span>{
+ Twig.test.extend(test, definition);
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-353">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-353">&#182;</a>
+ </div>
+ <p>Extend Twig with a new definition.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.exports.extendTag = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">definition</span>) </span>{
+ Twig.logic.extend(definition);
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-354">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-354">&#182;</a>
+ </div>
+ <p>Provide an environment for extending Twig core.
+Calls fn with the internal Twig object.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.exports.extend = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">fn</span>) </span>{
+ fn(Twig);
+ };
+
+
+ <span class="hljs-comment">/**
+ * Provide an extension for use with express 2.
+ *
+ * @param {string} markup The template markup.
+ * @param {array} options The express options.
+ *
+ * @return {string} The rendered template.
+ */</span>
+ Twig.exports.compile = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">markup, options</span>) </span>{
+ <span class="hljs-keyword">var</span> id = options.filename,
+ path = options.filename,
+ template;</pre></div></div>
+
+ </li>
+
+
+ <li id="section-355">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-355">&#182;</a>
+ </div>
+ <p>Try to load the template from the cache</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> template = <span class="hljs-keyword">new</span> Twig.Template({
+ data: markup,
+ path: path,
+ id: id,
+ options: options.settings[<span class="hljs-string">'twig options'</span>]
+ }); <span class="hljs-comment">// Twig.Templates.load(id) ||</span>
+
+ <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">context</span>) </span>{
+ <span class="hljs-keyword">return</span> template.render(context);
+ };
+ };
+
+ <span class="hljs-comment">/**
+ * Provide an extension for use with express 3.
+ *
+ * @param {string} path The location of the template file on disk.
+ * @param {Object|Function} The options or callback.
+ * @param {Function} fn callback.
+ *
+ * @throws Twig.Error
+ */</span>
+ Twig.exports.renderFile = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">path, options, fn</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-356">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-356">&#182;</a>
+ </div>
+ <p>handle callback in options</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> options === <span class="hljs-string">'function'</span>) {
+ fn = options;
+ options = {};
+ }
+
+ options = options || {};
+
+ <span class="hljs-keyword">var</span> settings = options.settings || {};
+
+ <span class="hljs-keyword">var</span> params = {
+ path: path,
+ base: settings.views,
+ load: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">template</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-357">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-357">&#182;</a>
+ </div>
+ <p>render and return template</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> fn(<span class="hljs-literal">null</span>, template.render(options));
+ }
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-358">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-358">&#182;</a>
+ </div>
+ <p>mixin any options provided to the express app.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> view_options = settings[<span class="hljs-string">'twig options'</span>];
+
+ <span class="hljs-keyword">if</span> (view_options) {
+ <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> option <span class="hljs-keyword">in</span> view_options) {
+ <span class="hljs-keyword">if</span> (view_options.hasOwnProperty(option)) {
+ params[option] = view_options[option];
+ }
+ }
+ }
+
+ Twig.exports.twig(params);
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-359">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-359">&#182;</a>
+ </div>
+ <p>Express 3 handler</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.exports.__express = Twig.exports.renderFile;
+
+ <span class="hljs-comment">/**
+ * Shoud Twig.js cache templates.
+ * Disable during development to see changes to templates without
+ * reloading, and disable in production to improve performance.
+ *
+ * @param {boolean} cache
+ */</span>
+ Twig.exports.cache = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">cache</span>) </span>{
+ Twig.cache = cache;
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-360">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-360">&#182;</a>
+ </div>
+ <p>We need to export the path module so we can effectively test it</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.exports.path = Twig.path;
+
+ <span class="hljs-keyword">return</span> Twig;
+}) (Twig || { });</pre></div></div>
+
+ </li>
+
+
+ <li id="section-361">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-361">&#182;</a>
+ </div>
+ <pre><code>Twig.js
+Available under the BSD <span class="hljs-number">2</span>-Clause License
+https:<span class="hljs-comment">//github.com/justjohn/twig.js</span>
+</code></pre>
+ </div>
+
+ </li>
+
+
+ <li id="section-362">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-362">&#182;</a>
+ </div>
+ <h2 id="twig-compiler-js">twig.compiler.js</h2>
+<p>This file handles compiling templates into JS</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> Twig = (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Twig</span>) </span>{
+ <span class="hljs-comment">/**
+ * Namespace for compilation.
+ */</span>
+ Twig.compiler = {
+ <span class="hljs-built_in">module</span>: {}
+ };</pre></div></div>
+
+ </li>
+
+
+ <li id="section-363">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-363">&#182;</a>
+ </div>
+ <p>Compile a Twig Template to output.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> Twig.compiler.compile = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">template, options</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-364">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-364">&#182;</a>
+ </div>
+ <p>Get tokens</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> tokens = <span class="hljs-built_in">JSON</span>.stringify(template.tokens)
+ , id = template.id
+ , output;
+
+ <span class="hljs-keyword">if</span> (options.module) {
+ <span class="hljs-keyword">if</span> (Twig.compiler.module[options.module] === <span class="hljs-literal">undefined</span>) {
+ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Twig.Error(<span class="hljs-string">"Unable to find module type "</span> + options.module);
+ }
+ output = Twig.compiler.module[options.module](id, tokens, options.twig);
+ } <span class="hljs-keyword">else</span> {
+ output = Twig.compiler.wrap(id, tokens);
+ }
+ <span class="hljs-keyword">return</span> output;
+ };
+
+ Twig.compiler.module = {
+ amd: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">id, tokens, pathToTwig</span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-string">'define(["'</span> + pathToTwig + <span class="hljs-string">'"], function (Twig) {\n\tvar twig, templates;\ntwig = Twig.twig;\ntemplates = '</span> + Twig.compiler.wrap(id, tokens) + <span class="hljs-string">'\n\treturn templates;\n});'</span>;
+ }
+ , node: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">id, tokens</span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-string">'var twig = require("twig").twig;\n'</span>
+ + <span class="hljs-string">'exports.template = '</span> + Twig.compiler.wrap(id, tokens)
+ }
+ , cjs2: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">id, tokens, pathToTwig</span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-string">'module.declare([{ twig: "'</span> + pathToTwig + <span class="hljs-string">'" }], function (require, exports, module) {\n'</span>
+ + <span class="hljs-string">'\tvar twig = require("twig").twig;\n'</span>
+ + <span class="hljs-string">'\texports.template = '</span> + Twig.compiler.wrap(id, tokens)
+ + <span class="hljs-string">'\n});'</span>
+ }
+ };
+
+ Twig.compiler.wrap = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">id, tokens</span>) </span>{
+ <span class="hljs-keyword">return</span> <span class="hljs-string">'twig({id:"'</span>+id.replace(<span class="hljs-string">'"'</span>, <span class="hljs-string">'\\"'</span>)+<span class="hljs-string">'", data:'</span>+tokens+<span class="hljs-string">', precompiled: true});\n'</span>;
+ };
+
+ <span class="hljs-keyword">return</span> Twig;
+})(Twig || {});</pre></div></div>
+
+ </li>
+
+
+ <li id="section-365">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-365">&#182;</a>
+ </div>
+ <pre><code>Twig.js
+Available under the BSD <span class="hljs-number">2</span>-Clause License
+https:<span class="hljs-comment">//github.com/justjohn/twig.js</span>
+</code></pre>
+ </div>
+
+ </li>
+
+
+ <li id="section-366">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-366">&#182;</a>
+ </div>
+ <h2 id="twig-module-js">twig.module.js</h2>
+<p>Provide a CommonJS/AMD/Node module export.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+<span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">module</span> !== <span class="hljs-string">'undefined'</span> &amp;&amp; <span class="hljs-built_in">module</span>.declare) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-367">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-367">&#182;</a>
+ </div>
+ <p>Provide a CommonJS Modules/2.0 draft 8 module</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-built_in">module</span>.declare([], <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">require, exports, module</span>) </span>{</pre></div></div>
+
+ </li>
+
+
+ <li id="section-368">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-368">&#182;</a>
+ </div>
+ <p>Add exports from the Twig exports</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">for</span> (key <span class="hljs-keyword">in</span> Twig.exports) {
+ <span class="hljs-keyword">if</span> (Twig.exports.hasOwnProperty(key)) {
+ exports[key] = Twig.exports[key];
+ }
+ }
+ });
+} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> define == <span class="hljs-string">'function'</span> &amp;&amp; define.amd) {
+ define(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
+ <span class="hljs-keyword">return</span> Twig.exports;
+ });
+} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">module</span> !== <span class="hljs-string">'undefined'</span> &amp;&amp; <span class="hljs-built_in">module</span>.exports) {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-369">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-369">&#182;</a>
+ </div>
+ <p>Provide a CommonJS Modules/1.1 module</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-built_in">module</span>.exports = Twig.exports;
+} <span class="hljs-keyword">else</span> {</pre></div></div>
+
+ </li>
+
+
+ <li id="section-370">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-370">&#182;</a>
+ </div>
+ <p>Export for browser use</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="hljs-built_in">window</span>.twig = Twig.exports.twig;
+ <span class="hljs-built_in">window</span>.Twig = Twig.exports;
+}</pre></div></div>
+
+ </li>
+
+ </ul>
+ </div>
+</body>
+</html>