| 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++) { |
| if (i in context) { |
| 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 !== undefined) { |
| execIteration(priorKey, i - 1, true); |
| } |
| } |
| } |
| |
| if (i === 0) { |
| ret = inverse(this); |
| } |
| |
| return ret; |
| }); |
| } |