(function(root, factory) { if (typeof define === 'function' && define.amd && define.amd.dust === true) { define(['dust.core'], factory); } else if (typeof exports === 'object') { module.exports = factory(require('dustjs-linkedin')); module.exports.registerWith = factory; } else { factory(root.dust); } }(this, function(dust) { function log(helper, msg, level) { level = level || "INFO"; helper = helper ? '{@' + helper + '}: ' : ''; dust.log(helper + msg, level); } var _deprecatedCache = {}; function _deprecated(target) { if(_deprecatedCache[target]) { return; } log(target, "Deprecation warning: " + target + " is deprecated and will be removed in a future version of dustjs-helpers", "WARN"); log(null, "For help and a deprecation timeline, see https://github.com/linkedin/dustjs-helpers/wiki/Deprecated-Features#" + target.replace(/\W+/g, ""), "WARN"); _deprecatedCache[target] = true; } function isSelect(context) { return context.stack.tail && context.stack.tail.head && typeof context.stack.tail.head.__select__ !== "undefined"; } function getSelectState(context) { return isSelect(context) && context.get('__select__'); } /** * Adds a special __select__ key behind the head of the context stack. Used to maintain the state * of {@select} blocks * @param context {Context} add state to this Context * @param opts {Object} add these properties to the state (`key` and `type`) */ function addSelectState(context, opts) { var head = context.stack.head, newContext = context.rebase(), key; if(context.stack && context.stack.tail) { newContext.stack = context.stack.tail; } var state = { isPending: false, isResolved: false, isDeferredComplete: false, deferreds: [] }; for(key in opts) { state[key] = opts[key]; } return newContext .push({ "__select__": state }) .push(head, context.stack.index, context.stack.of); } /** * After a {@select} or {@math} block is complete, they invoke this function */ function resolveSelectDeferreds(state) { var x, len; state.isDeferredPending = true; if(state.deferreds.length) { state.isDeferredComplete = true; for(x=0, len=state.deferreds.length; x right; }), "gte": truthTest('gte', function(left, right) { return left >= right; }), /** * {@any} * Outputs as long as at least one truth test inside a {@select} has passed. * Must be contained inside a {@select} block. * The passing truth test can be before or after the {@any} block. */ "any": function(chunk, context, bodies, params) { var selectState = getSelectState(context); if(!selectState) { log("any", "Must be used inside a {@select} block", "ERROR"); } else { if(selectState.isDeferredComplete) { log("any", "Must not be nested inside {@any} or {@none} block", "ERROR"); } else { chunk = chunk.map(function(chunk) { selectState.deferreds.push(function() { if(selectState.isResolved) { chunk = chunk.render(bodies.block, context); } chunk.end(); }); }); } } return chunk; }, /** * {@none} * Outputs if no truth tests inside a {@select} pass. * Must be contained inside a {@select} block. * The position of the helper does not matter. */ "none": function(chunk, context, bodies, params) { var selectState = getSelectState(context); if(!selectState) { log("none", "Must be used inside a {@select} block", "ERROR"); } else { if(selectState.isDeferredComplete) { log("none", "Must not be nested inside {@any} or {@none} block", "ERROR"); } else { chunk = chunk.map(function(chunk) { selectState.deferreds.push(function() { if(!selectState.isResolved) { chunk = chunk.render(bodies.block, context); } chunk.end(); }); }); } } return chunk; }, /** * {@size} * Write the size of the target to the chunk * Falsy values and true have size 0 * Numbers are returned as-is * Arrays and Strings have size equal to their length * Objects have size equal to the number of keys they contain * Dust bodies are evaluated and the length of the string is returned * Functions are evaluated and the length of their return value is evaluated * @param key find the size of this value or reference */ "size": function(chunk, context, bodies, params) { var key = params.key, value, k; key = context.resolve(params.key); if (!key || key === true) { value = 0; } else if(dust.isArray(key)) { value = key.length; } else if (!isNaN(parseFloat(key)) && isFinite(key)) { value = key; } else if (typeof key === "object") { value = 0; for(k in key){ if(key.hasOwnProperty(k)){ value++; } } } else { value = (key + '').length; } return chunk.write(value); } }; for(var key in helpers) { dust.helpers[key] = helpers[key]; } return dust; }));