diff --git a/ajax/libs/dustjs-helpers/1.3.0/dust-helpers.js b/ajax/libs/dustjs-helpers/1.3.0/dust-helpers.js new file mode 100644 index 000000000..d4a0d24a7 --- /dev/null +++ b/ajax/libs/dustjs-helpers/1.3.0/dust-helpers.js @@ -0,0 +1,517 @@ +/*! dustjs-helpers - v1.3.0 +* https://github.com/linkedin/dustjs-helpers +* Copyright (c) 2014 Aleksander Williams; Released under the MIT License */ +(function(dust){ + +//using the built in logging method of dust when accessible +var _log = dust.log ? function(mssg) { dust.log(mssg, "INFO"); } : function() {}; + +function isSelect(context) { + var value = context.current(); + return typeof value === "object" && value.isSelect === true; +} + +// Utility method : toString() equivalent for functions +function jsonFilter(key, value) { + if (typeof value === "function") { + //to make sure all environments format functions the same way + return value.toString() + //remove all leading and trailing whitespace + .replace(/(^\s+|\s+$)/mg, '') + //remove new line characters + .replace(/\n/mg, '') + //replace , and 0 or more spaces with ", " + .replace(/,\s*/mg, ', ') + //insert space between ){ + .replace(/\)\{/mg, ') {') + ; + } + return value; +} + +// Utility method: to invoke the given filter operation such as eq/gt etc +function filter(chunk, context, bodies, params, filterOp) { + params = params || {}; + var body = bodies.block, + actualKey, + expectedValue, + filterOpType = params.filterOpType || ''; + // when @eq, @lt etc are used as standalone helpers, key is required and hence check for defined + if ( typeof params.key !== "undefined") { + actualKey = dust.helpers.tap(params.key, chunk, context); + } + else if (isSelect(context)) { + actualKey = context.current().selectKey; + // supports only one of the blocks in the select to be selected + if (context.current().isResolved) { + filterOp = function() { return false; }; + } + } + else { + _log("No key specified for filter in:" + filterOpType + " helper "); + return chunk; + } + expectedValue = dust.helpers.tap(params.value, chunk, context); + // coerce both the actualKey and expectedValue to the same type for equality and non-equality compares + if (filterOp(coerce(expectedValue, params.type, context), coerce(actualKey, params.type, context))) { + if (isSelect(context)) { + context.current().isResolved = true; + } + // we want helpers without bodies to fail gracefully so check it first + if(body) { + return chunk.render(body, context); + } + else { + _log("No key specified for filter in:" + filterOpType + " helper "); + return chunk; + } + } + else if (bodies['else']) { + return chunk.render(bodies['else'], context); + } + return chunk; +} + +function coerce (value, type, context) { + if (value) { + switch (type || typeof(value)) { + case 'number': return +value; + case 'string': return String(value); + case 'boolean': { + value = (value === 'false' ? false : value); + return Boolean(value); + } + case 'date': return new Date(value); + case 'context': return context.get(value); + } + } + + return value; +} + +var helpers = { + + // Utility helping to resolve dust references in the given chunk + // uses the Chunk.render method to resolve value + /* + Reference resolution rules: + if value exists in JSON: + "" or '' will evaluate to false, boolean false, null, or undefined will evaluate to false, + numeric 0 evaluates to true, so does, string "0", string "null", string "undefined" and string "false". + Also note that empty array -> [] is evaluated to false and empty object -> {} and non-empty object are evaluated to true + The type of the return value is string ( since we concatenate to support interpolated references + + if value does not exist in JSON and the input is a single reference: {x} + dust render emits empty string, and we then return false + + if values does not exist in JSON and the input is interpolated references : {x} < {y} + dust render emits < and we return the partial output + + */ + "tap": function(input, chunk, context) { + // return given input if there is no dust reference to resolve + // dust compiles a string/reference such as {foo} to a function + if (typeof input !== "function") { + return input; + } + + var dustBodyOutput = '', + returnValue; + + //use chunk render to evaluate output. For simple functions result will be returned from render call, + //for dust body functions result will be output via callback function + returnValue = chunk.tap(function(data) { + dustBodyOutput += data; + return ''; + }).render(input, context); + + chunk.untap(); + + //assume it's a simple function call if return result is not a chunk + if (returnValue.constructor !== chunk.constructor) { + //use returnValue as a result of tap + return returnValue; + } else if (dustBodyOutput === '') { + return false; + } else { + return dustBodyOutput; + } + }, + + "sep": function(chunk, context, bodies) { + var body = bodies.block; + if (context.stack.index === context.stack.of - 1) { + return chunk; + } + if(body) { + return bodies.block(chunk, context); + } + else { + return chunk; + } + }, + + "idx": function(chunk, context, bodies) { + var body = bodies.block; + if(body) { + return bodies.block(chunk, context.push(context.stack.index)); + } + else { + return chunk; + } + }, + + /** + * contextDump helper + * @param key specifies how much to dump. + * "current" dumps current context. "full" dumps the full context stack. + * @param to specifies where to write dump output. + * Values can be "console" or "output". Default is output. + */ + "contextDump": function(chunk, context, bodies, params) { + var p = params || {}, + to = p.to || 'output', + key = p.key || 'current', + dump; + to = dust.helpers.tap(to, chunk, context); + key = dust.helpers.tap(key, chunk, context); + if (key === 'full') { + dump = JSON.stringify(context.stack, jsonFilter, 2); + } + else { + dump = JSON.stringify(context.stack.head, jsonFilter, 2); + } + if (to === 'console') { + _log(dump); + return chunk; + } + else { + return chunk.write(dump); + } + }, + /** + if helper for complex evaluation complex logic expressions. + Note : #1 if helper fails gracefully when there is no body block nor else block + #2 Undefined values and false values in the JSON need to be handled specially with .length check + for e.g @if cond=" '{a}'.length && '{b}'.length" is advised when there are chances of the a and b been + undefined or false in the context + #3 Use only when the default ? and ^ dust operators and the select fall short in addressing the given logic, + since eval executes in the global scope + #4 All dust references are default escaped as they are resolved, hence eval will block malicious scripts in the context + Be mindful of evaluating a expression that is passed through the unescape filter -> |s + @param cond, either a string literal value or a dust reference + a string literal value, is enclosed in double quotes, e.g. cond="2>3" + a dust reference is also enclosed in double quotes, e.g. cond="'{val}'' > 3" + cond argument should evaluate to a valid javascript expression + **/ + + "if": function( chunk, context, bodies, params ){ + var body = bodies.block, + skip = bodies['else']; + if( params && params.cond){ + var cond = params.cond; + cond = dust.helpers.tap(cond, chunk, context); + // eval expressions with given dust references + if(eval(cond)){ + if(body) { + return chunk.render( bodies.block, context ); + } + else { + _log("Missing body block in the if helper!"); + return chunk; + } + } + if(skip){ + return chunk.render( bodies['else'], context ); + } + } + // no condition + else { + _log("No condition given in the if helper!"); + } + return chunk; + }, + + /** + * math helper + * @param key is the value to perform math against + * @param method is the math method, is a valid string supported by math helper like mod, add, subtract + * @param operand is the second value needed for operations like mod, add, subtract, etc. + * @param round is a flag to assure that an integer is returned + */ + "math": function ( chunk, context, bodies, params ) { + //key and method are required for further processing + if( params && typeof params.key !== "undefined" && params.method ){ + var key = params.key, + method = params.method, + // operand can be null for "abs", ceil and floor + operand = params.operand, + round = params.round, + mathOut = null, + operError = function(){ + _log("operand is required for this math method"); + return null; + }; + key = dust.helpers.tap(key, chunk, context); + operand = dust.helpers.tap(operand, chunk, context); + // TODO: handle and tests for negatives and floats in all math operations + switch(method) { + case "mod": + if(operand === 0 || operand === -0) { + _log("operand for divide operation is 0/-0: expect Nan!"); + } + mathOut = parseFloat(key) % parseFloat(operand); + break; + case "add": + mathOut = parseFloat(key) + parseFloat(operand); + break; + case "subtract": + mathOut = parseFloat(key) - parseFloat(operand); + break; + case "multiply": + mathOut = parseFloat(key) * parseFloat(operand); + break; + case "divide": + if(operand === 0 || operand === -0) { + _log("operand for divide operation is 0/-0: expect Nan/Infinity!"); + } + mathOut = parseFloat(key) / parseFloat(operand); + break; + case "ceil": + mathOut = Math.ceil(parseFloat(key)); + break; + case "floor": + mathOut = Math.floor(parseFloat(key)); + break; + case "round": + mathOut = Math.round(parseFloat(key)); + break; + case "abs": + mathOut = Math.abs(parseFloat(key)); + break; + default: + _log("method passed is not supported"); + } + + if (mathOut !== null){ + if (round) { + mathOut = Math.round(mathOut); + } + if (bodies && bodies.block) { + // with bodies act like the select helper with mathOut as the key + // like the select helper bodies['else'] is meaningless and is ignored + return chunk.render(bodies.block, context.push({ isSelect: true, isResolved: false, selectKey: mathOut })); + } else { + // self closing math helper will return the calculated output + return chunk.write(mathOut); + } + } else { + return chunk; + } + } + // no key parameter and no method + else { + _log("Key is a required parameter for math helper along with method/operand!"); + } + return chunk; + }, + /** + select helper works with one of the eq/ne/gt/gte/lt/lte/default providing the functionality + of branching conditions + @param key, ( required ) either a string literal value or a dust reference + a string literal value, is enclosed in double quotes, e.g. key="foo" + a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid + @param type (optional), supported types are number, boolean, string, date, context, defaults to string + **/ + "select": function(chunk, context, bodies, params) { + var body = bodies.block; + // key is required for processing, hence check for defined + if( params && typeof params.key !== "undefined"){ + // returns given input as output, if the input is not a dust reference, else does a context lookup + var key = dust.helpers.tap(params.key, chunk, context); + // bodies['else'] is meaningless and is ignored + if( body ) { + return chunk.render(bodies.block, context.push({ isSelect: true, isResolved: false, selectKey: key })); + } + else { + _log("Missing body block in the select helper "); + return chunk; + } + } + // no key + else { + _log("No key given in the select helper!"); + } + return chunk; + }, + + /** + eq helper compares the given key is same as the expected value + It can be used standalone or in conjunction with select for multiple branching + @param key, The actual key to be compared ( optional when helper used in conjunction with select) + either a string literal value or a dust reference + a string literal value, is enclosed in double quotes, e.g. key="foo" + a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid + @param value, The expected value to compare to, when helper is used standalone or in conjunction with select + @param type (optional), supported types are number, boolean, string, date, context, defaults to string + Note : use type="number" when comparing numeric + **/ + "eq": function(chunk, context, bodies, params) { + if(params) { + params.filterOpType = "eq"; + } + return filter(chunk, context, bodies, params, function(expected, actual) { return actual === expected; }); + }, + + /** + ne helper compares the given key is not the same as the expected value + It can be used standalone or in conjunction with select for multiple branching + @param key, The actual key to be compared ( optional when helper used in conjunction with select) + either a string literal value or a dust reference + a string literal value, is enclosed in double quotes, e.g. key="foo" + a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid + @param value, The expected value to compare to, when helper is used standalone or in conjunction with select + @param type (optional), supported types are number, boolean, string, date, context, defaults to string + Note : use type="number" when comparing numeric + **/ + "ne": function(chunk, context, bodies, params) { + if(params) { + params.filterOpType = "ne"; + return filter(chunk, context, bodies, params, function(expected, actual) { return actual !== expected; }); + } + return chunk; + }, + + /** + lt helper compares the given key is less than the expected value + It can be used standalone or in conjunction with select for multiple branching + @param key, The actual key to be compared ( optional when helper used in conjunction with select) + either a string literal value or a dust reference + a string literal value, is enclosed in double quotes, e.g. key="foo" + a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid + @param value, The expected value to compare to, when helper is used standalone or in conjunction with select + @param type (optional), supported types are number, boolean, string, date, context, defaults to string + Note : use type="number" when comparing numeric + **/ + "lt": function(chunk, context, bodies, params) { + if(params) { + params.filterOpType = "lt"; + return filter(chunk, context, bodies, params, function(expected, actual) { return actual < expected; }); + } + }, + + /** + lte helper compares the given key is less or equal to the expected value + It can be used standalone or in conjunction with select for multiple branching + @param key, The actual key to be compared ( optional when helper used in conjunction with select) + either a string literal value or a dust reference + a string literal value, is enclosed in double quotes, e.g. key="foo" + a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid + @param value, The expected value to compare to, when helper is used standalone or in conjunction with select + @param type (optional), supported types are number, boolean, string, date, context, defaults to string + Note : use type="number" when comparing numeric + **/ + "lte": function(chunk, context, bodies, params) { + if(params) { + params.filterOpType = "lte"; + return filter(chunk, context, bodies, params, function(expected, actual) { return actual <= expected; }); + } + return chunk; + }, + + + /** + gt helper compares the given key is greater than the expected value + It can be used standalone or in conjunction with select for multiple branching + @param key, The actual key to be compared ( optional when helper used in conjunction with select) + either a string literal value or a dust reference + a string literal value, is enclosed in double quotes, e.g. key="foo" + a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid + @param value, The expected value to compare to, when helper is used standalone or in conjunction with select + @param type (optional), supported types are number, boolean, string, date, context, defaults to string + Note : use type="number" when comparing numeric + **/ + "gt": function(chunk, context, bodies, params) { + // if no params do no go further + if(params) { + params.filterOpType = "gt"; + return filter(chunk, context, bodies, params, function(expected, actual) { return actual > expected; }); + } + return chunk; + }, + + /** + gte helper, compares the given key is greater than or equal to the expected value + It can be used standalone or in conjunction with select for multiple branching + @param key, The actual key to be compared ( optional when helper used in conjunction with select) + either a string literal value or a dust reference + a string literal value, is enclosed in double quotes, e.g. key="foo" + a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid + @param value, The expected value to compare to, when helper is used standalone or in conjunction with select + @param type (optional), supported types are number, boolean, string, date, context, defaults to string + Note : use type="number" when comparing numeric + **/ + "gte": function(chunk, context, bodies, params) { + if(params) { + params.filterOpType = "gte"; + return filter(chunk, context, bodies, params, function(expected, actual) { return actual >= expected; }); + } + return chunk; + }, + + // to be used in conjunction with the select helper + // TODO: fix the helper to do nothing when used standalone + "default": function(chunk, context, bodies, params) { + // does not require any params + if(params) { + params.filterOpType = "default"; + } + return filter(chunk, context, bodies, params, function(expected, actual) { return true; }); + }, + + /** + * size helper prints the size of the given key + * Note : size helper is self closing and does not support bodies + * @param key, the element whose size is returned + */ + "size": function( chunk, context, bodies, params ) { + var key, value=0, nr, k; + params = params || {}; + key = params.key; + if (!key || key === true) { //undefined, null, "", 0 + value = 0; + } + else if(dust.isArray(key)) { //array + value = key.length; + } + else if (!isNaN(parseFloat(key)) && isFinite(key)) { //numeric values + value = key; + } + else if (typeof key === "object") { //object test + //objects, null and array all have typeof ojbect... + //null and array are already tested so typeof is sufficient http://jsperf.com/isobject-tests + nr = 0; + for(k in key){ + if(Object.hasOwnProperty.call(key,k)){ + nr++; + } + } + value = nr; + } else { + value = (key + '').length; //any other value (strings etc.) + } + return chunk.write(value); + } + + +}; + + for (var key in helpers) { + dust.helpers[key] = helpers[key]; + } + + if(typeof exports !== 'undefined') { + module.exports = dust; + } + +})(typeof exports !== 'undefined' ? require('dustjs-linkedin') : dust); \ No newline at end of file diff --git a/ajax/libs/dustjs-helpers/1.3.0/dust-helpers.min.js b/ajax/libs/dustjs-helpers/1.3.0/dust-helpers.min.js new file mode 100644 index 000000000..c18717b27 --- /dev/null +++ b/ajax/libs/dustjs-helpers/1.3.0/dust-helpers.min.js @@ -0,0 +1,4 @@ +/*! dustjs-helpers - v1.3.0 +* https://github.com/linkedin/dustjs-helpers +* Copyright (c) 2014 Aleksander Williams; Released under the MIT License */ +!function(dust){function isSelect(a){var b=a.current();return"object"==typeof b&&b.isSelect===!0}function jsonFilter(a,b){return"function"==typeof b?b.toString().replace(/(^\s+|\s+$)/gm,"").replace(/\n/gm,"").replace(/,\s*/gm,", ").replace(/\)\{/gm,") {"):b}function filter(a,b,c,d,e){d=d||{};var f,g,h=c.block,i=d.filterOpType||"";if("undefined"!=typeof d.key)f=dust.helpers.tap(d.key,a,b);else{if(!isSelect(b))return _log("No key specified for filter in:"+i+" helper "),a;f=b.current().selectKey,b.current().isResolved&&(e=function(){return!1})}return g=dust.helpers.tap(d.value,a,b),e(coerce(g,d.type,b),coerce(f,d.type,b))?(isSelect(b)&&(b.current().isResolved=!0),h?a.render(h,b):(_log("No key specified for filter in:"+i+" helper "),a)):c["else"]?a.render(c["else"],b):a}function coerce(a,b,c){if(a)switch(b||typeof a){case"number":return+a;case"string":return String(a);case"boolean":return a="false"===a?!1:a,Boolean(a);case"date":return new Date(a);case"context":return c.get(a)}return a}var _log=dust.log?function(a){dust.log(a,"INFO")}:function(){},helpers={tap:function(a,b,c){if("function"!=typeof a)return a;var d,e="";return d=b.tap(function(a){return e+=a,""}).render(a,c),b.untap(),d.constructor!==b.constructor?d:""===e?!1:e},sep:function(a,b,c){var d=c.block;return b.stack.index===b.stack.of-1?a:d?c.block(a,b):a},idx:function(a,b,c){var d=c.block;return d?c.block(a,b.push(b.stack.index)):a},contextDump:function(a,b,c,d){var e,f=d||{},g=f.to||"output",h=f.key||"current";return g=dust.helpers.tap(g,a,b),h=dust.helpers.tap(h,a,b),e="full"===h?JSON.stringify(b.stack,jsonFilter,2):JSON.stringify(b.stack.head,jsonFilter,2),"console"===g?(_log(e),a):a.write(e)},"if":function(chunk,context,bodies,params){var body=bodies.block,skip=bodies["else"];if(params&¶ms.cond){var cond=params.cond;if(cond=dust.helpers.tap(cond,chunk,context),eval(cond))return body?chunk.render(bodies.block,context):(_log("Missing body block in the if helper!"),chunk);if(skip)return chunk.render(bodies["else"],context)}else _log("No condition given in the if helper!");return chunk},math:function(a,b,c,d){if(d&&"undefined"!=typeof d.key&&d.method){var e=d.key,f=d.method,g=d.operand,h=d.round,i=null;switch(e=dust.helpers.tap(e,a,b),g=dust.helpers.tap(g,a,b),f){case"mod":(0===g||g===-0)&&_log("operand for divide operation is 0/-0: expect Nan!"),i=parseFloat(e)%parseFloat(g);break;case"add":i=parseFloat(e)+parseFloat(g);break;case"subtract":i=parseFloat(e)-parseFloat(g);break;case"multiply":i=parseFloat(e)*parseFloat(g);break;case"divide":(0===g||g===-0)&&_log("operand for divide operation is 0/-0: expect Nan/Infinity!"),i=parseFloat(e)/parseFloat(g);break;case"ceil":i=Math.ceil(parseFloat(e));break;case"floor":i=Math.floor(parseFloat(e));break;case"round":i=Math.round(parseFloat(e));break;case"abs":i=Math.abs(parseFloat(e));break;default:_log("method passed is not supported")}return null!==i?(h&&(i=Math.round(i)),c&&c.block?a.render(c.block,b.push({isSelect:!0,isResolved:!1,selectKey:i})):a.write(i)):a}return _log("Key is a required parameter for math helper along with method/operand!"),a},select:function(a,b,c,d){var e=c.block;if(d&&"undefined"!=typeof d.key){var f=dust.helpers.tap(d.key,a,b);return e?a.render(c.block,b.push({isSelect:!0,isResolved:!1,selectKey:f})):(_log("Missing body block in the select helper "),a)}return _log("No key given in the select helper!"),a},eq:function(a,b,c,d){return d&&(d.filterOpType="eq"),filter(a,b,c,d,function(a,b){return b===a})},ne:function(a,b,c,d){return d?(d.filterOpType="ne",filter(a,b,c,d,function(a,b){return b!==a})):a},lt:function(a,b,c,d){return d?(d.filterOpType="lt",filter(a,b,c,d,function(a,b){return a>b})):void 0},lte:function(a,b,c,d){return d?(d.filterOpType="lte",filter(a,b,c,d,function(a,b){return a>=b})):a},gt:function(a,b,c,d){return d?(d.filterOpType="gt",filter(a,b,c,d,function(a,b){return b>a})):a},gte:function(a,b,c,d){return d?(d.filterOpType="gte",filter(a,b,c,d,function(a,b){return b>=a})):a},"default":function(a,b,c,d){return d&&(d.filterOpType="default"),filter(a,b,c,d,function(){return!0})},size:function(a,b,c,d){var e,f,g,h=0;if(d=d||{},e=d.key,e&&e!==!0)if(dust.isArray(e))h=e.length;else if(!isNaN(parseFloat(e))&&isFinite(e))h=e;else if("object"==typeof e){f=0;for(g in e)Object.hasOwnProperty.call(e,g)&&f++;h=f}else h=(e+"").length;else h=0;return a.write(h)}};for(var key in helpers)dust.helpers[key]=helpers[key];"undefined"!=typeof exports&&(module.exports=dust)}("undefined"!=typeof exports?require("dustjs-linkedin"):dust); \ No newline at end of file diff --git a/ajax/libs/dustjs-helpers/package.json b/ajax/libs/dustjs-helpers/package.json index 61e0bf3e3..69ceb772d 100644 --- a/ajax/libs/dustjs-helpers/package.json +++ b/ajax/libs/dustjs-helpers/package.json @@ -1,7 +1,7 @@ { "name": "dustjs-helpers", "filename": "dust-helpers.min.js", - "version": "1.2.0", + "version": "1.3.0", "description": "Additional functionality for dustjs-linkedin package", "homepage": "Additional functionality for dustjs-linkedin package", "keywords": [