PageSourceSearch

https://my.hastings.gov.uk/libraries/js/dust-helpers.js

js hastings.gov.uk collected 2026-10-02 04:26:37 UTC 22,420 bytes, 518 lines download raw bytes

1/*! dustjs-helpers - v1.2.0
2* https://github.com/linkedin/dustjs-helpers
3* Copyright (c) 2014 Aleksander Williams; Released under the MIT License */
4(function(dust){
5
6    // Note: all error conditions are logged to console and failed silently
7    
8    /* make a safe version of console if it is not available
9     * currently supporting:
10     *   _console.log
11     * */
12    var _console = (typeof console !== 'undefined')? console: {
13      log: function(){
14         /* a noop*/
15       }
16    };
17    
18    function isSelect(context) {
19      var value = context.current();
20      return typeof value === "object" && value.isSelect === true;
21    }
22    
23    // Utility method : toString() equivalent for functions
24    function jsonFilter(key, value) {
25      if (typeof value === "function") {
26        //to make sure all environments format functions the same way
27        return value.toString()
28          //remove all leading and trailing whitespace
29          .replace(/(^\s+|\s+$)/mg, '')
30          //remove new line characters
31          .replace(/\n/mg, '')
32          //replace , and 0 or more spaces with ", "
33          .replace(/,\s*/mg, ', ')
34          //insert space between ){
35          .replace(/\)\{/mg, ') {')
36        ;
37      }
38      return value;
39    }
40    
41    // Utility method: to invoke the given filter operation such as eq/gt etc
42    function filter(chunk, context, bodies, params, filterOp) {
43      params = params || {};
44      var body = bodies.block,
45          actualKey,
46          expectedValue,
47          filterOpType = params.filterOpType || '';
48      // when @eq, @lt etc are used as standalone helpers, key is required and hence check for defined
49      if ( typeof params.key !== "undefined") {
50        actualKey = dust.helpers.tap(params.key, chunk, context);
51      }
52      else if (isSelect(context)) {
53        actualKey = context.current().selectKey;
54        //  supports only one of the blocks in the select to be selected
55        if (context.current().isResolved) {
56          filterOp = function() { return false; };
57        }
58      }
59      else {
60        _console.log ("No key specified for filter in:" + filterOpType + " helper ");
61        return chunk;
62      }
63      expectedValue = dust.helpers.tap(params.value, chunk, context);
64      // coerce both the actualKey and expectedValue to the same type for equality and non-equality compares
65      if (filterOp(coerce(expectedValue, params.type, context), coerce(actualKey, params.type, context))) {
66        if (isSelect(context)) {
67          context.current().isResolved = true;
68        }
69        // we want helpers without bodies to fail gracefully so check it first
70        if(body) {
71         return chunk.render(body, context);
72        }
73        else {
74          _console.log( "Missing body block in the " + filterOpType + " helper ");
75          return chunk;
76        }
77       }
78       else if (bodies['else']) {
79        return chunk.render(bodies['else'], context);
80      }
81      return chunk;
82    }
83    
84    function coerce (value, type, context) {
85      if (value) {
86        switch (type || typeof(value)) {
87          case 'number': return +value;
88          case 'string': return String(value);
89          case 'boolean': {
90            value = (value === 'false' ? false : value);
91            return Boolean(value);
92          }
93          case 'date': return new Date(value);
94          case 'context': return context.get(value);
95        }
96      }
97    
98      return value;
99    }
100    
101    var helpers = {
102    
103      // Utility helping to resolve dust references in the given chunk
104      // uses the Chunk.render method to resolve value
105      /*
106       Reference resolution rules:
107       if value exists in JSON:
108        "" or '' will evaluate to false, boolean false, null, or undefined will evaluate to false,
109        numeric 0 evaluates to true, so does, string "0", string "null", string "undefined" and string "false". 
110        Also note that empty array ->
110 [] is evaluated to false and empty object -> {} and non-empty object are evaluated to true
111        The type of the return value is string ( since we concatenate to support interpolated references 
112    
113       if value does not exist in JSON and the input is a single reference: {x}
114         dust render emits empty string, and we then return false   
115         
116       if values does not exist in JSON and the input is interpolated references : {x} < {y}
117         dust render emits <  and we return the partial output 
118         
119      */
120      "tap": function(input, chunk, context) {
121        // return given input if there is no dust reference to resolve
122        // dust compiles a string/reference such as {foo} to a function
123        if (typeof input !== "function") {
124          return input;
125        }
126    
127        var dustBodyOutput = '',
128          returnValue;
129    
130        //use chunk render to evaluate output. For simple functions result will be returned from render call,
131        //for dust body functions result will be output via callback function
132        returnValue = chunk.tap(function(data) {
133          dustBodyOutput += data;
134          return '';
135        }).render(input, context);
136    
137        chunk.untap();
138    
139        //assume it's a simple function call if return result is not a chunk
140        if (returnValue.constructor !== chunk.constructor) {
141          //use returnValue as a result of tap
142          return returnValue;
143        } else if (dustBodyOutput === '') {
144          return false;
145        } else {
146          return dustBodyOutput;
147        }
148      },
149    
150      "sep": function(chunk, context, bodies) {
151        var body = bodies.block;
152        if (context.stack.index === context.stack.of - 1) {
153          return chunk;
154        }
155        if(body) {
156         return bodies.block(chunk, context);
157        }
158        else {
159         return chunk;
160        }
161      },
162    
163      "idx": function(chunk, context, bodies) {
164        var body = bodies.block;
165         if(body) {
166           return bodies.block(chunk, context.push(context.stack.index));
167         }
168         else {
169           return chunk;
170         }
171      },
172    
173      /**
174       * contextDump helper
175       * @param key specifies how much to dump.
176       * "current" dumps current context. "full" dumps the full context stack.
177       * @param to specifies where to write dump output.
178       * Values can be "console" or "output". Default is output.
179       */
180      "contextDump": function(chunk, context, bodies, params) {
181        var p = params || {},
182          to = p.to || 'output',
183          key = p.key || 'current',
184          dump;
185        to = dust.helpers.tap(to, chunk, context);
186        key = dust.helpers.tap(key, chunk, context);
187        if (key === 'full') {
188          dump = JSON.stringify(context.stack, jsonFilter, 2);
189        }
190        else {
191          dump = JSON.stringify(context.stack.head, jsonFilter, 2);
192        }
193        if (to === 'console') {
194          _console.log(dump);
195          return chunk;
196        }
197        else {
198          return chunk.write(dump);
199        }
200      },
201      /**
202       if helper for complex evaluation complex logic expressions.
203       Note : #1 if helper fails gracefully when there is no body block nor else block
204              #2 Undefined values and false values in the JSON need to be handled specially with .length check
205                 for e.g @if cond=" '{a}'.length && '{b}'.length" is advised when there are chances of the a and b been
206                 undefined or false in the context
207              #3 Use only when the default ? and ^ dust operators and the select fall short in addressing the given logic,
208                 since eval executes in the global scope
209              #4 All dust references are default escaped as they are resolved, hence eval will block malicious scripts in the context
210                 Be mindful of evaluating a expression that is passed through the unescape filter -> |s
211       @param cond, either a string literal value or a dust reference
212                    a string literal value, is enclosed in double quotes, e.g. cond="2>3"
213                    a dust reference is also enclosed in double quotes, e.g. cond="'{val}'' > 3"
214        cond argument should evaluate to a valid javascript expression
215       **/
216    
217      "if": function( chunk, context, bodies, params ){
218        var body = bodies.block,
219            skip = bodies['else'];
220        if( params && params.cond){
221          var cond = params.cond;
222          cond = dust.helpers.tap(cond, chunk, context);
223          // eval expressions with given dust references
224          if(eval(cond)){
225           if(body) {
226            return chunk.render( bodies.block, context );
227           }
228           else {
229             _console.log( "Missing body block in the if helper!" );
230             return chunk;
231           }
232          }
233          if(skip){
234           return chunk.render( bodies['else'], context );
235          }
236        }
237        // no condition
238        else {
239          _console.log( "No condition given in the if helper!" );
240        }
241        return chunk;
242      },
243    
244      /**
245       * math helper
246       * @param key is the value to perform math against
247       * @param method is the math method,  is a valid string supported by math helper like mod, add, subtract
248       * @param operand is the second value needed for operations like mod, add, subtract, etc.
249       * @param round is a flag to assure that an integer is returned
250       */
251      "math": function ( chunk, context, bodies, params ) {
252        //key and method are required for further processing
253        if( params && typeof params.key !== "undefined" && params.method ){
254          var key  = params.key,
255              method = params.method,
256              // operand can be null for "abs", ceil and floor
257              operand = params.operand,
258              round = params.round,
259              mathOut = null,
260              operError = function(){_console.log("operand is required for this math method"); return null;};
261          key  = dust.helpers.tap(key, chunk, context);
262          operand = dust.helpers.tap(operand, chunk, context);
263          //  TODO: handle  and tests for negatives and floats in all math operations
264          switch(method) {
265            case "mod":
266              if(operand === 0 || operand === -0) {
267                _console.log("operand for divide operation is 0/-0: expect Nan!");
268              }
269              mathOut = parseFloat(key) %  parseFloat(operand);
270              break;
271            case "add":
272              mathOut = parseFloat(key) + parseFloat(operand);
273              break;
274            case "subtract":
275              mathOut = parseFloat(key) - parseFloat(operand);
276              break;
277            case "multiply":
278              mathOut = parseFloat(key) * parseFloat(operand);
279              break;
280            case "divide":
281             if(operand === 0 || operand === -0) {
282               _console.log("operand for divide operation is 0/-0: expect Nan/Infinity!");
283             }
284              mathOut = parseFloat(key) / parseFloat(operand);
285              break;
286            case "ceil":
287              mathOut = Math.ceil(parseFloat(key));
288              break;
289            case "floor":
290              mathOut = Math.floor(parseFloat(key));
291              break;
292            case "round":
293              mathOut = Math.round(parseFloat(key));
294              break;
295            case "abs":
296              mathOut = Math.abs(parseFloat(key));
297              break;
298            default:
299              _console.log( "method passed is not supported" );
300         }
301    
302          if (mathOut !== null){
303            if (round) {
304              mathOut = Math.round(mathOut);
305            }
306            if (bodies && bodies.block) {
307              // with bodies act like the select helper with mathOut as the key
308              // like the select helper bodies['else'] is meaningless and is ignored
309              return chunk.render(bodies.block, context.push({ isSelect: true, isResolved: false, selectKey: mathOut }));
310            } else {
311              // self closing math helper will return the calculated output
312              return chunk.write(mathOut);
313            }
314           } else {
315            return chunk;
316          }
317        }
318        // no key parameter and no method
319        else {
320          _console.log( "Key is a required parameter for math helper along with method/operand!" );
321        }
322        return chunk;
323      },
324       /**
325       select helper works with one of the eq/ne/gt/gte/lt/lte/default providing the functionality
326       of branching conditions
327       @param key,  ( required ) either a string literal value or a dust reference
328                    a string literal value, is enclosed in double quotes, e.g. key="foo"
329                    a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid
330       @param type (optional), supported types are  number, boolean, string, date, context, defaults to string
331       **/
332      "select": function(chunk, context, bodies, params) {
333        var body = bodies.block;
334        // key is required for processing, hence check for defined
335        if( params && typeof params.key !== "undefined"){
336          // returns given input as output, if the input is not a dust reference, else does a context lookup
337          var key = dust.helpers.tap(params.key, chunk, context);
338          // bodies['else'] is meaningless and is ignored
339          if( body ) {
340           return chunk.render(bodies.block, context.push({ isSelect: true, isResolved: false, selectKey: key }));
341          }
342          else {
343           _console.log( "Missing body block in the select helper ");
344           return chunk;
345          }
346        }
347        // no key
348        else {
349          _console.log( "No key given in the select helper!" );
350        }
351        return chunk;
352      },
353    
354      /**
355       eq helper compares the given key is same as the expected value
356       It can be used standalone or in conjunction with select for multiple branching
357       @param key,  The actual key to be compared ( optional when helper used in conjunction with select)
358                    either a string literal value or a dust reference
359                    a string literal value, is enclosed in double quotes, e.g. key="foo"
360                    a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid
361       @param value, The expected value to compare to, when helper is used standalone or in conjunction with select
362       @param type (optional), supported types are  number, boolean, string, date, context, defaults to string
363       Note : use type="number" when comparing numeric
364       **/
365      "eq": function(chunk, context, bodies, params) {
366        if(params) {
367          params.filterOpType = "eq";
368        }
369        return filter(chunk, context, bodies, params, function(expected, actual) { return actual === expected; });
370      },
371    
372      /**
373       ne helper compares the given key is not the same as the expected value
374       It can be used standalone or in conjunction with select for multiple branching
375       @param key,  The actual key to be compared ( optional when helper used in conjunction with select)
376                    either a string literal value or a dust reference
377                    a string literal value, is enclosed in double quotes, e.g. key="foo"
378                    a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid
379       @param value, The expected value to compare to, when helper is used standalone or in conjunction with select
380       @param type (optional), supported types are  number, boolean, string, date, context, defaults to string
381       Note : use type="number" when comparing numeric
382       **/
383      "ne": function(chunk, context, bodies, params) {
384        if(params) {
385          params.filterOpType = "ne";
386          return filter(chunk, context, bodies, params, function(expected, actual) { return actual !== expected; });
387        }
388       return chunk;
389      },
390    
391      /**
392       lt helper compares the given key is less than the expected value
393       It can be used standalone or in conjunction with select for multiple branching
394       @param key,  The actual key to be compared ( optional when helper used in conjunction with select)
395                    either a string literal value or a dust reference
396                    a string literal value, is enclosed in double quotes, e.g. key="foo"
397                    a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid
398       @param value, The expected value to compare to, when helper is used standalone  or in conjunction with select
399       @param type (optional), supported types are  number, boolean, string, date, context, defaults to string
400       Note : use type="number" when comparing numeric
401       **/
402      "lt": function(chunk, context, bodies, params) {
403         if(params) {
404           params.filterOpType = "lt";
405           return filter(chunk, context, bodies, params, function(expected, actual) { return actual < expected; });
406         }
407      },
408    
409      /**
410       lte helper compares the given key is less or equal to the expected value
411       It can be used standalone or in conjunction with select for multiple branching
412       @param key,  The actual key to be compared ( optional when helper used in conjunction with select)
413                    either a string literal value or a dust reference
414                    a string literal value, is enclosed in double quotes, e.g. key="foo"
415                    a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid
416       @param value, The expected value to compare to, when helper is used standalone or in conjunction with select
417       @param type (optional), supported types are  number, boolean, string, date, context, defaults to string
418       Note : use type="number" when comparing numeric
419      **/
420      "lte": function(chunk, context, bodies, params) {
421         if(params) {
422           params.filterOpType = "lte";
423           return filter(chunk, context, bodies, params, function(expected, actual) { return actual <= expected; });
424         }
425        return chunk;
426      },
427    
428    
429      /**
430       gt helper compares the given key is greater than the expected value
431       It can be used standalone or in conjunction with select for multiple branching
432       @param key,  The actual key to be compared ( optional when helper used in conjunction with select)
433                    either a string literal value or a dust reference
434                    a string literal value, is enclosed in double quotes, e.g. key="foo"
435                    a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid
436       @param value, The expected value to compare to, when helper is used standalone  or in conjunction with select
437       @param type (optional), supported types are  number, boolean, string, date, context, defaults to string
438       Note : use type="number" when comparing numeric
439       **/
440      "gt": function(chunk, context, bodies, params) {
441        // if no params do no go further
442        if(params) {
443          params.filterOpType = "gt";
444          return filter(chunk, context, bodies, params, function(expected, actual) { return actual > expected; });
445        }
446        return chunk;
447      },
448    
449     /**
450       gte helper, compares the given key is greater than or equal to the expected value
451       It can be used standalone or in conjunction with select for multiple branching
452       @param key,  The actual key to be compared ( optional when helper used in conjunction with select)
453                    either a string literal value or a dust reference
454                    a string literal value, is enclosed in double quotes, e.g. key="foo"
455                    a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid
456       @param value, The expected value to compare to, when helper is used standalone or in conjunction with select
457       @param type (optional), supported types are  number, boolean, string, date, context, defaults to string
458       Note : use type="number" when comparing numeric
459      **/
460      "gte": function(chunk, context, bodies, params) {
461         if(params) {
462          params.filterOpType = "gte";
463          return filter(chunk, context, bodies, params, function(expected, actual) { return actual >= expected; });
464         }
465        return chunk; 
466      },
467    
468      // to be used in conjunction with the select helper
469      // TODO: fix the helper to do nothing when used standalone
470      "default": function(chunk, context, bodies, params) {
471        // does not require any params
472         if(params) {
473            params.filterOpType = "default";
474          }
475         return filter(chunk, context, bodies, params, function(expected, actual) { return true; });
476      },
477    
478      /**
479      * size helper prints the size of the given key
480      * Note : size helper is self closing and does not support bodies
481      * @param key, the element whose size is returned
482      */
483      "size": function( chunk, context, bodies, params ) {
484        var key, value=0, nr, k;
485        params = params || {};
486        key = params.key;
487        if (!key || key === true) { //undefined, null, "", 0
488          value = 0;
489        }
490        else if(dust.isArray(key)) { //array
491          value = key.length;
492        }
493        else if (!isNaN(parseFloat(key)) && isFinite(key)) { //numeric values
494          value = key;
495        }
496        else if (typeof key  === "object") { //object test
497          //objects, null and array all have typeof ojbect...
498          //null and array are already tested so typeof is sufficient http://jsperf.com/isobject-tests
499          nr = 0;
500          for(k in key){
501            if(Object.hasOwnProperty.call(key,k)){
502              nr++;
503            }
504          }
505          value = nr;
506        } else {
507          value = (key + '').length; //any other value (strings etc.)
508        }
509        return chunk.write(value);
510      }
511      
512      
513    };
514    
515    dust.helpers = helpers;
516    
517    })(typeof exports !== 'undefined' ? module.exports = require('dustjs-linkedin') : dust);
518    

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.