diff options
Diffstat (limited to 'node_modules/twig/docs/twig.html')
-rw-r--r-- | node_modules/twig/docs/twig.html | 11250 |
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">¶</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">¶</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">¶</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">¶</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 >>> <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 > <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> && n !== <span class="hljs-literal">Infinity</span> && n !== -<span class="hljs-literal">Infinity</span>) { + n = (n > <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 >= len) {</pre></div></div> + + </li> + + + <li id="section-5"> + <div class="annotation"> + + <div class="pilwrap "> + <a class="pilcrow" href="#section-5">¶</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 >= <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 < len; k++) { + <span class="hljs-keyword">if</span> (k <span class="hljs-keyword">in</span> t && 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">¶</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">¶</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">¶</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 >>> <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">¶</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">¶</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">¶</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">¶</a> + </div> + <ol> +<li>Repeat, while k < len</li> +</ol> + + </div> + + <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">while</span>( k < 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">¶</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">¶</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">¶</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">¶</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">¶</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 && !(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 && <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 && <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">¶</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">¶</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">¶</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">¶</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<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">¶</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 >= <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">¶</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">¶</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 < <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">¶</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">¶</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 >= <span class="hljs-number">0</span> && (output.position === <span class="hljs-literal">null</span> || first_key_position < 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 >= <span class="hljs-number">0</span> && output.position !== <span class="hljs-literal">null</span> && 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 > output.def.open.length) {</pre></div></div> + + </li> + + + <li id="section-27"> + <div class="annotation"> + + <div class="pilwrap "> + <a class="pilcrow" href="#section-27">¶</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 > output.def.close.length) {</pre></div></div> + + </li> + + + <li id="section-28"> + <div class="annotation"> + + <div class="pilwrap "> + <a class="pilcrow" href="#section-28">¶</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 >= <span class="hljs-number">0</span> && close_key_position < output.close_position) {</pre></div></div> + + </li> + + + <li id="section-29"> + <div class="annotation"> + + <div class="pilwrap "> + <a class="pilcrow" href="#section-29">¶</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 >= <span class="hljs-number">0</span> && close_key_position < output.close_position) {</pre></div></div> + + </li> + + + <li id="section-30"> + <div class="annotation"> + + <div class="pilwrap "> + <a class="pilcrow" href="#section-30">¶</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">¶</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">¶</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 >= <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">¶</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">¶</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">¶</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 < 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 > <span class="hljs-number">0</span> && this_str_pos < pos && + (str_pos === <span class="hljs-literal">null</span> || this_str_pos < 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">¶</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 < <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">¶</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">¶</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">¶</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">¶</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 > <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">¶</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">¶</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 > <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">¶</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">¶</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">¶</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">¶</a> + </div> + <p>No more tokens -> 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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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 > <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">¶</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">¶</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> && !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) < <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 > <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">¶</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> && next.length > <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 > <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">¶</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">¶</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> && 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">¶</a> + </div> + <p>Standalone token (like {% set … %}</p> + + </div> + + <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (stack.length > <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 > <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 > <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">¶</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">¶</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 && 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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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 && 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">¶</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">¶</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">¶</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">¶</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 > <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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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 && (str.twig_markup !== <span class="hljs-literal">true</span> && 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">¶</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 && 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">¶</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">¶</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">¶</a> + </div> + <p>Check for existing template</p> + + </div> + + <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (Twig.cache && 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">¶</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">¶</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">¶</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">¶</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">¶</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> && obj !== <span class="hljs-literal">null</span> && 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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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 && <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">¶</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">¶</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">¶</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">¶</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> && content.length > <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 && 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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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] && 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 < 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 < 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>]) && re.not_json.test(match[<span class="hljs-number">8</span>]) && (get_type(arg) != <span class="hljs-string">"number"</span> && <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 >= <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)) && 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 >>> <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>]) && (!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 > <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">¶</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> && 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> && 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> + && 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> < <span class="hljs-number">7</span> && (aDate.getDay() + <span class="hljs-number">6</span>) % <span class="hljs-number">7</span> < (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() > <span class="hljs-number">0</span> || aDate.getDate() >= <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() > <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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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() < <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">¶</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() < <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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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 < 5 5 > 1’);</li> +<li>returns 4: ‘1 < 5 5 > 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">/<[a-z][a-z0-9]*>/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 (<a><b><c>)</span> + <span class="hljs-keyword">var</span> tags = <span class="hljs-regexp">/<\/?([a-z][a-z0-9]*)\b[^>]*>/gi</span>, + commentsAndPhpTags = <span class="hljs-regexp">/<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/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">'<'</span> + $<span class="hljs-number">1.</span>toLowerCase() + <span class="hljs-string">'>'</span>) > <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">¶</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">¶</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">¶</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">¶</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">¶</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>] > <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">¶</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> && 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">¶</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">¶</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">¶</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 && 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>] > <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">¶</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>] > <span class="hljs-number">12</span> || match[<span class="hljs-number">5</span>] > <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">¶</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">¶</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>] > <span class="hljs-number">12</span> || match[<span class="hljs-number">5</span>] > <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>] > <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">¶</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>] > <span class="hljs-number">12</span> || match[<span class="hljs-number">1</span>] > <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">¶</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>] > <span class="hljs-number">12</span> || match[<span class="hljs-number">1</span>] > <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">¶</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>] > <span class="hljs-number">12</span> || match[<span class="hljs-number">3</span>] > <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">¶</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>] > <span class="hljs-number">12</span> || match[<span class="hljs-number">5</span>] > <span class="hljs-number">31</span> || (match[<span class="hljs-number">1</span>] < <span class="hljs-number">70</span> && match[<span class="hljs-number">1</span>] > <span class="hljs-number">38</span>)) { + <span class="hljs-keyword">return</span> fail; + } + + year = match[<span class="hljs-number">1</span>] >= <span class="hljs-number">0</span> && match[<span class="hljs-number">1</span>] <= <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">¶</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>] >= <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">¶</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>] > <span class="hljs-number">12</span> || match[<span class="hljs-number">1</span>] > <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>] < <span class="hljs-number">60</span> && !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">¶</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>] > <span class="hljs-number">23</span> || match[<span class="hljs-number">3</span>] > <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">¶</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">¶</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>] > <span class="hljs-number">12</span> || match[<span class="hljs-number">3</span>] > <span class="hljs-number">31</span> || (match[<span class="hljs-number">5</span>] < <span class="hljs-number">70</span> && match[<span class="hljs-number">5</span>] > <span class="hljs-number">38</span>)) { + <span class="hljs-keyword">return</span> fail; + } + + year = match[<span class="hljs-number">5</span>] >= <span class="hljs-number">0</span> && match[<span class="hljs-number">5</span>] <= <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">¶</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>] > <span class="hljs-number">23</span> || match[<span class="hljs-number">3</span>] > <span class="hljs-number">59</span> || match[<span class="hljs-number">5</span>] > <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">¶</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">¶</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">¶</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 > <span class="hljs-number">0</span> && 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 < <span class="hljs-number">0</span> && 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) && !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 < 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">¶</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> && obj !== <span class="hljs-literal">null</span> && clas === type; + };</pre></div></div> + + </li> + + + <li id="section-171"> + <div class="annotation"> + + <div class="pilwrap "> + <a class="pilcrow" href="#section-171">¶</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">¶</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 < <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 < 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">¶</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 & 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 > <span class="hljs-number">0</span>) | -(value < <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 < <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 > <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">¶</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 > 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 < 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 < 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) && !<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 < <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) && !<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 > <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 > 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 < 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">¶</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 > 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 < 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 < 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) && !<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 < <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) && !<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 > <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 > 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 < 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">¶</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">¶</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">¶</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'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">¶</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">¶</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">¶</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">¶</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">¶</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 && 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">¶</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>) >= <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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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) > <span class="hljs-number">-1</span>, + hasParent = <span class="hljs-keyword">this</span>.blocks[token.block] && Twig.indexOf(<span class="hljs-keyword">this</span>.blocks[token.block], Twig.placeholders.parent) > <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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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>) && 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">¶</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">¶</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">¶</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">¶</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">/>\s+</g</span>,</pre></div></div> + + </li> + + + <li id="section-210"> + <div class="annotation"> + + <div class="pilwrap "> + <a class="pilcrow" href="#section-210">¶</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">'><'</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">¶</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">¶</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<parameters.length; i++) { + <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> j=<span class="hljs-number">0</span>; j<parameters.length; j++){ + <span class="hljs-keyword">if</span> (parameters[i] === parameters[j] && 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">¶</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">¶</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<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">¶</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<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">¶</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">¶</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>) && 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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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 > <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">¶</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">¶</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">¶</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">¶</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">¶</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 > <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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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 && 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">¶</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">¶</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 >= <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">¶</a> + </div> + <p>Match any of +, <em>, /, -, %, ~, <, <=, >, >=, !=, ==, *</em>, ?, :, and, or, not</p> + + </div> + + <div class="content"><div class='highlight'><pre> regex: <span class="hljs-regexp">/(^[\+\-~%\?\:]|^[!=]==?|^[!<>]=?|^\*\*?|^\/\/?|^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 > <span class="hljs-number">0</span> && + (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) && + ( + (operator.associativity === Twig.expression.operator.leftToRight && + operator.precidence >= stack[stack.length<span class="hljs-number">-1</span>].precidence) || + + (operator.associativity === Twig.expression.operator.rightToLeft && + operator.precidence > 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">¶</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>] && 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">¶</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">¶</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">¶</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 && + 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">¶</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">¶</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">¶</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 > <span class="hljs-number">0</span> && + (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) && + ( + (operator.associativity === Twig.expression.operator.leftToRight && + operator.precidence >= stack[stack.length<span class="hljs-number">-1</span>].precidence) || + + (operator.associativity === Twig.expression.operator.rightToLeft && + operator.precidence > 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">¶</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">¶</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 > <span class="hljs-number">0</span> && 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">¶</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">¶</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">¶</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 && + token.type !== Twig.expression.type.filter && + token.type !== Twig.expression.type.test && + token.type !== Twig.expression.type.key.brackets && + 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">¶</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 > <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">¶</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 && value.type && 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">¶</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 >= <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 > <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">¶</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 && 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">¶</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">¶</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">¶</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 >= <span class="hljs-number">0</span>; i--) { + stack_token = stack.pop(); + <span class="hljs-keyword">if</span> (stack_token && 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 > <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">¶</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 && token.type && 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 && token.type && (token.type === Twig.expression.type.operator.binary || token.type === Twig.expression.type.operator.unary) && 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">¶</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">¶</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">¶</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">¶</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 && 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">¶</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">¶</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 && 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">¶</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">¶</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">¶</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">¶</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>]) < <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">¶</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 && 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">¶</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> && 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">¶</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">¶</a> + </div> + <p>Evaluate key</p> + + </div> + + <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> params = token.params && 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">¶</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> && 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">¶</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">¶</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">¶</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 > <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">¶</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">¶</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">¶</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">¶</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">¶</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 && Twig.indexOf(next, type) < <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">¶</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">¶</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 && + !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">¶</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 > <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">¶</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 > <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">¶</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 > <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">¶</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">¶</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 > <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">¶</a> + </div> + <p>Compile the template</p> + + </div> + + <div class="content"><div class='highlight'><pre> token_template.compile && 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 > <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">¶</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">¶</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 && 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">¶</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">¶</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">¶</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">¶</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> && b.indexOf(a) > <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) && 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">¶</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">'<'</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">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">¶</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">'<'</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">'==='</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 && 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">¶</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">¶</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">¶</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> && obj !== <span class="hljs-literal">null</span> && clas === type; + } + + Twig.filters = {</pre></div></div> + + </li> + + + <li id="section-301"> + <div class="annotation"> + + <div class="pilwrap "> + <a class="pilcrow" href="#section-301">¶</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">¶</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">¶</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">¶</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] > value[b]) == !(value[a] <= value[b])) { + <span class="hljs-keyword">return</span> value[a] > value[b] ? <span class="hljs-number">1</span> : + value[a] < 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">¶</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])) && + !<span class="hljs-built_in">isNaN</span>(b1 = <span class="hljs-built_in">parseFloat</span>(value[b]))) { + <span class="hljs-keyword">return</span> a1 > b1 ? <span class="hljs-number">1</span> : + a1 < 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">¶</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] > value[b].toString() ? <span class="hljs-number">1</span> : + value[a] < 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() > value[b] ? <span class="hljs-number">1</span> : + value[a].toString() < 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">¶</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 && 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> && 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">"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>) && (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">¶</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">¶</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">¶</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) && int_key >= 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">¶</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) && int_key >= 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 && 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) && 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 && params.length && 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">/&/g</span>, <span class="hljs-string">"&amp;"</span>) + .replace(<span class="hljs-regexp">/</g</span>, <span class="hljs-string">"&lt;"</span>) + .replace(<span class="hljs-regexp">/>/g</span>, <span class="hljs-string">"&gt;"</span>) + .replace(<span class="hljs-regexp">/"/g</span>, <span class="hljs-string">"&quot;"</span>) + .replace(<span class="hljs-regexp">/'/g</span>, <span class="hljs-string">"&#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 < 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 < <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 < 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 < 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">/^[&<>"]$/</span>)) + result += raw_value[i].replace(<span class="hljs-regexp">/&/g</span>, <span class="hljs-string">"&amp;"</span>) + .replace(<span class="hljs-regexp">/</g</span>, <span class="hljs-string">"&lt;"</span>) + .replace(<span class="hljs-regexp">/>/g</span>, <span class="hljs-string">"&gt;"</span>) + .replace(<span class="hljs-regexp">/"/g</span>, <span class="hljs-string">"&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">¶</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 <= <span class="hljs-number">0x1f</span> && char_code != <span class="hljs-number">0x09</span> && char_code != <span class="hljs-number">0x0a</span> && char_code != <span class="hljs-number">0x0d</span>) + result += <span class="hljs-string">"&#xFFFD;"</span>; + <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(char_code < <span class="hljs-number">0x80</span>) + result += Twig.lib.sprintf(<span class="hljs-string">"&#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">"&#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">"<br />"</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 && params[<span class="hljs-number">0</span>]) ? params[<span class="hljs-number">0</span>] : <span class="hljs-literal">undefined</span>, + dec = (params && 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 && 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">¶</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 > <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 < 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 && 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 < 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 >= <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 > 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 < <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">¶</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">¶</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 > <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">¶</a> + </div> + <p>handle negative start values</p> + + </div> + + <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> startIndex = start >= <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 < startIndex + length && i < 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 < <span class="hljs-number">1</span> || params.length > <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 < <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">¶</a> + </div> + <p>empty delimiter +“aabbcc”|split(‘’, 2) + -> [‘aa’, ‘bb’, ‘cc’]</p> + + </div> + + <div class="content"><div class='highlight'><pre> + <span class="hljs-keyword">while</span>(split.length > <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<limit && split.length > <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">¶</a> + </div> + <p>non-empty delimiter +“one,two,three,four,five”|split(‘,’, 3) + -> [‘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<limit<span class="hljs-number">-1</span> && split.length > <span class="hljs-number">0</span>; i++) { + limitedSplit.push(split.shift()); + } + + <span class="hljs-keyword">if</span> (split.length > <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">¶</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 && 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 > <span class="hljs-number">0</span> ? params[<span class="hljs-number">0</span>] : <span class="hljs-number">0</span>, + method = params.length > <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 && !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">¶</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">¶</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">¶</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> && obj !== <span class="hljs-literal">null</span> && clas === type; + } + + Twig.functions = {</pre></div></div> + + </li> + + + <li id="section-323"> + <div class="annotation"> + + <div class="pilwrap "> + <a class="pilcrow" href="#section-323">¶</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">¶</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">¶</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) && !<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) && <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 > 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 <= 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 >= 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 > <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">']=> '</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">¶</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">¶</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">¶</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">¶</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> && <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">module</span>.exports !== <span class="hljs-string">'undefined'</span> && <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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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 && !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">¶</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">¶</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> && <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> && (file.indexOf(<span class="hljs-string">'::'</span>) > <span class="hljs-number">0</span>) || file.indexOf(<span class="hljs-string">'@'</span>) >= <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">¶</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> && 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) && template.method && template.method !== <span class="hljs-string">'fs'</span> && 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">¶</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">¶</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 > <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">¶</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> && new_path.length > <span class="hljs-number">0</span> && 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">¶</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">¶</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">¶</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">¶</a> + </div> + <p>Handle strings and arrays</p> + + </div> + + <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (value.length && value.length > <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">¶</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 && (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">¶</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">¶</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">¶</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> && 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 && 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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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> && <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">¶</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">¶</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> && 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> && <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">¶</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">¶</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> |