From 15b55a307b4f95d4a861df8b32c3c1ddb4825414 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 1 Aug 2015 17:54:47 -0500 Subject: Move helpers into separate modules --- lib/handlebars/base.js | 179 +------------------------ lib/handlebars/helpers.js | 17 +++ lib/handlebars/helpers/block-helper-missing.js | 32 +++++ lib/handlebars/helpers/each.js | 77 +++++++++++ lib/handlebars/helpers/helper-missing.js | 13 ++ lib/handlebars/helpers/if.js | 20 +++ lib/handlebars/helpers/log.js | 6 + lib/handlebars/helpers/lookup.js | 5 + lib/handlebars/helpers/with.js | 24 ++++ lib/handlebars/utils.js | 6 + 10 files changed, 206 insertions(+), 173 deletions(-) create mode 100644 lib/handlebars/helpers.js create mode 100644 lib/handlebars/helpers/block-helper-missing.js create mode 100644 lib/handlebars/helpers/each.js create mode 100644 lib/handlebars/helpers/helper-missing.js create mode 100644 lib/handlebars/helpers/if.js create mode 100644 lib/handlebars/helpers/log.js create mode 100644 lib/handlebars/helpers/lookup.js create mode 100644 lib/handlebars/helpers/with.js diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js index 756fb77..cc3d2fa 100644 --- a/lib/handlebars/base.js +++ b/lib/handlebars/base.js @@ -1,5 +1,6 @@ -import * as Utils from './utils'; +import {createFrame, extend, toString} from './utils'; import Exception from './exception'; +import {registerDefaultHelpers} from './helpers'; export const VERSION = '3.0.1'; export const COMPILER_REVISION = 6; @@ -13,10 +14,7 @@ export const REVISION_CHANGES = { 6: '>= 2.0.0-beta.1' }; -const isArray = Utils.isArray, - isFunction = Utils.isFunction, - toString = Utils.toString, - objectType = '[object Object]'; +const objectType = '[object Object]'; export function HandlebarsEnvironment(helpers, partials) { this.helpers = helpers || {}; @@ -34,7 +32,7 @@ HandlebarsEnvironment.prototype = { registerHelper: function(name, fn) { if (toString.call(name) === objectType) { if (fn) { throw new Exception('Arg not supported with multiple helpers'); } - Utils.extend(this.helpers, name); + extend(this.helpers, name); } else { this.helpers[name] = fn; } @@ -45,7 +43,7 @@ HandlebarsEnvironment.prototype = { registerPartial: function(name, partial) { if (toString.call(name) === objectType) { - Utils.extend(this.partials, name); + extend(this.partials, name); } else { if (typeof partial === 'undefined') { throw new Exception('Attempting to register a partial as undefined'); @@ -58,167 +56,6 @@ HandlebarsEnvironment.prototype = { } }; -function registerDefaultHelpers(instance) { - instance.registerHelper('helperMissing', function(/* [args, ]options */) { - if (arguments.length === 1) { - // A missing field in a {{foo}} construct. - return undefined; - } else { - // Someone is actually trying to call something, blow up. - throw new Exception('Missing helper: "' + arguments[arguments.length - 1].name + '"'); - } - }); - - instance.registerHelper('blockHelperMissing', function(context, options) { - let inverse = options.inverse, - fn = options.fn; - - if (context === true) { - return fn(this); - } else if (context === false || context == null) { - return inverse(this); - } else if (isArray(context)) { - if (context.length > 0) { - if (options.ids) { - options.ids = [options.name]; - } - - return instance.helpers.each(context, options); - } else { - return inverse(this); - } - } else { - if (options.data && options.ids) { - let data = createFrame(options.data); - data.contextPath = Utils.appendContextPath(options.data.contextPath, options.name); - options = {data: data}; - } - - return fn(context, options); - } - }); - - instance.registerHelper('each', function(context, options) { - if (!options) { - throw new Exception('Must pass iterator to #each'); - } - - let fn = options.fn, - inverse = options.inverse, - i = 0, - ret = '', - data, - contextPath; - - if (options.data && options.ids) { - contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.'; - } - - if (isFunction(context)) { context = context.call(this); } - - if (options.data) { - data = createFrame(options.data); - } - - function execIteration(field, index, last) { - if (data) { - data.key = field; - data.index = index; - data.first = index === 0; - data.last = !!last; - - if (contextPath) { - data.contextPath = contextPath + field; - } - } - - ret = ret + fn(context[field], { - data: data, - blockParams: Utils.blockParams([context[field], field], [contextPath + field, null]) - }); - } - - if (context && typeof context === 'object') { - if (isArray(context)) { - for (let j = context.length; i < j; i++) { - execIteration(i, i, i === context.length - 1); - } - } else { - let priorKey; - - for (let key in context) { - if (context.hasOwnProperty(key)) { - // We're running the iterations one step out of sync so we can detect - // the last iteration without have to scan the object twice and create - // an itermediate keys array. - if (priorKey !== undefined) { - execIteration(priorKey, i - 1); - } - priorKey = key; - i++; - } - } - if (priorKey) { - execIteration(priorKey, i - 1, true); - } - } - } - - if (i === 0) { - ret = inverse(this); - } - - return ret; - }); - - instance.registerHelper('if', function(conditional, options) { - if (isFunction(conditional)) { conditional = conditional.call(this); } - - // Default behavior is to render the positive path if the value is truthy and not empty. - // The `includeZero` option may be set to treat the condtional as purely not empty based on the - // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative. - if ((!options.hash.includeZero && !conditional) || Utils.isEmpty(conditional)) { - return options.inverse(this); - } else { - return options.fn(this); - } - }); - - instance.registerHelper('unless', function(conditional, options) { - return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn, hash: options.hash}); - }); - - instance.registerHelper('with', function(context, options) { - if (isFunction(context)) { context = context.call(this); } - - let fn = options.fn; - - if (!Utils.isEmpty(context)) { - let data = options.data; - if (options.data && options.ids) { - data = createFrame(options.data); - data.contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]); - } - - return fn(context, { - data: data, - blockParams: Utils.blockParams([context], [data && data.contextPath]) - }); - } else { - return options.inverse(this); - } - }); - - instance.registerHelper('log', function(message, options) { - let level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1; - instance.log(level, message); - }); - - instance.registerHelper('lookup', function(obj, field) { - return obj && obj[field]; - }); -} - export let logger = { methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' }, @@ -240,8 +77,4 @@ export let logger = { export let log = logger.log; -export function createFrame(object) { - let frame = Utils.extend({}, object); - frame._parent = object; - return frame; -} +export {createFrame}; diff --git a/lib/handlebars/helpers.js b/lib/handlebars/helpers.js new file mode 100644 index 0000000..7a4365a --- /dev/null +++ b/lib/handlebars/helpers.js @@ -0,0 +1,17 @@ +import registerBlockHelperMissing from './helpers/block-helper-missing'; +import registerEach from './helpers/each'; +import registerHelperMissing from './helpers/helper-missing'; +import registerIf from './helpers/if'; +import registerLog from './helpers/log'; +import registerLookup from './helpers/lookup'; +import registerWith from './helpers/with'; + +export function registerDefaultHelpers(instance) { + registerBlockHelperMissing(instance); + registerEach(instance); + registerHelperMissing(instance); + registerIf(instance); + registerLog(instance); + registerLookup(instance); + registerWith(instance); +} diff --git a/lib/handlebars/helpers/block-helper-missing.js b/lib/handlebars/helpers/block-helper-missing.js new file mode 100644 index 0000000..6639ddb --- /dev/null +++ b/lib/handlebars/helpers/block-helper-missing.js @@ -0,0 +1,32 @@ +import {appendContextPath, createFrame, isArray} from '../utils'; + +export default function(instance) { + instance.registerHelper('blockHelperMissing', function(context, options) { + let inverse = options.inverse, + fn = options.fn; + + if (context === true) { + return fn(this); + } else if (context === false || context == null) { + return inverse(this); + } else if (isArray(context)) { + if (context.length > 0) { + if (options.ids) { + options.ids = [options.name]; + } + + return instance.helpers.each(context, options); + } else { + return inverse(this); + } + } else { + if (options.data && options.ids) { + let data = createFrame(options.data); + data.contextPath = appendContextPath(options.data.contextPath, options.name); + options = {data: data}; + } + + return fn(context, options); + } + }); +} diff --git a/lib/handlebars/helpers/each.js b/lib/handlebars/helpers/each.js new file mode 100644 index 0000000..9fc5a09 --- /dev/null +++ b/lib/handlebars/helpers/each.js @@ -0,0 +1,77 @@ +import {appendContextPath, blockParams, createFrame, isArray, isFunction} from '../utils'; +import Exception from '../exception'; + +export default function(instance) { + instance.registerHelper('each', function(context, options) { + if (!options) { + throw new Exception('Must pass iterator to #each'); + } + + let fn = options.fn, + inverse = options.inverse, + i = 0, + ret = '', + data, + contextPath; + + if (options.data && options.ids) { + contextPath = appendContextPath(options.data.contextPath, options.ids[0]) + '.'; + } + + if (isFunction(context)) { context = context.call(this); } + + if (options.data) { + data = createFrame(options.data); + } + + function execIteration(field, index, last) { + if (data) { + data.key = field; + data.index = index; + data.first = index === 0; + data.last = !!last; + + if (contextPath) { + data.contextPath = contextPath + field; + } + } + + ret = ret + fn(context[field], { + data: data, + blockParams: blockParams([context[field], field], [contextPath + field, null]) + }); + } + + if (context && typeof context === 'object') { + if (isArray(context)) { + for (let j = context.length; i < j; i++) { + execIteration(i, i, i === context.length - 1); + } + } else { + let priorKey; + + for (let key in context) { + if (context.hasOwnProperty(key)) { + // We're running the iterations one step out of sync so we can detect + // the last iteration without have to scan the object twice and create + // an itermediate keys array. + if (priorKey !== undefined) { + execIteration(priorKey, i - 1); + } + priorKey = key; + i++; + } + } + if (priorKey) { + execIteration(priorKey, i - 1, true); + } + } + } + + if (i === 0) { + ret = inverse(this); + } + + return ret; + }); +} diff --git a/lib/handlebars/helpers/helper-missing.js b/lib/handlebars/helpers/helper-missing.js new file mode 100644 index 0000000..ec32e82 --- /dev/null +++ b/lib/handlebars/helpers/helper-missing.js @@ -0,0 +1,13 @@ +import Exception from '../exception'; + +export default function(instance) { + instance.registerHelper('helperMissing', function(/* [args, ]options */) { + if (arguments.length === 1) { + // A missing field in a {{foo}} construct. + return undefined; + } else { + // Someone is actually trying to call something, blow up. + throw new Exception('Missing helper: "' + arguments[arguments.length - 1].name + '"'); + } + }); +} diff --git a/lib/handlebars/helpers/if.js b/lib/handlebars/helpers/if.js new file mode 100644 index 0000000..11d08df --- /dev/null +++ b/lib/handlebars/helpers/if.js @@ -0,0 +1,20 @@ +import {isEmpty, isFunction} from '../utils'; + +export default function(instance) { + instance.registerHelper('if', function(conditional, options) { + if (isFunction(conditional)) { conditional = conditional.call(this); } + + // Default behavior is to render the positive path if the value is truthy and not empty. + // The `includeZero` option may be set to treat the condtional as purely not empty based on the + // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative. + if ((!options.hash.includeZero && !conditional) || isEmpty(conditional)) { + return options.inverse(this); + } else { + return options.fn(this); + } + }); + + instance.registerHelper('unless', function(conditional, options) { + return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn, hash: options.hash}); + }); +} diff --git a/lib/handlebars/helpers/log.js b/lib/handlebars/helpers/log.js new file mode 100644 index 0000000..ab83604 --- /dev/null +++ b/lib/handlebars/helpers/log.js @@ -0,0 +1,6 @@ +export default function(instance) { + instance.registerHelper('log', function(message, options) { + let level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1; + instance.log(level, message); + }); +} diff --git a/lib/handlebars/helpers/lookup.js b/lib/handlebars/helpers/lookup.js new file mode 100644 index 0000000..a52e77a --- /dev/null +++ b/lib/handlebars/helpers/lookup.js @@ -0,0 +1,5 @@ +export default function(instance) { + instance.registerHelper('lookup', function(obj, field) { + return obj && obj[field]; + }); +} diff --git a/lib/handlebars/helpers/with.js b/lib/handlebars/helpers/with.js new file mode 100644 index 0000000..7418cd0 --- /dev/null +++ b/lib/handlebars/helpers/with.js @@ -0,0 +1,24 @@ +import {appendContextPath, blockParams, createFrame, isEmpty, isFunction} from '../utils'; + +export default function(instance) { + instance.registerHelper('with', function(context, options) { + if (isFunction(context)) { context = context.call(this); } + + let fn = options.fn; + + if (!isEmpty(context)) { + let data = options.data; + if (options.data && options.ids) { + data = createFrame(options.data); + data.contextPath = appendContextPath(options.data.contextPath, options.ids[0]); + } + + return fn(context, { + data: data, + blockParams: blockParams([context], [data && data.contextPath]) + }); + } else { + return options.inverse(this); + } + }); +} diff --git a/lib/handlebars/utils.js b/lib/handlebars/utils.js index c522394..c7a5762 100644 --- a/lib/handlebars/utils.js +++ b/lib/handlebars/utils.js @@ -91,6 +91,12 @@ export function isEmpty(value) { } } +export function createFrame(object) { + let frame = extend({}, object); + frame._parent = object; + return frame; +} + export function blockParams(params, ids) { params.path = ids; return params; -- cgit v1.1