Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80713 views
1
"use strict";
2
var Utils = require("./utils");
3
var Exception = require("./exception")["default"];
4
5
var VERSION = "3.0.0";
6
exports.VERSION = VERSION;var COMPILER_REVISION = 6;
7
exports.COMPILER_REVISION = COMPILER_REVISION;
8
var REVISION_CHANGES = {
9
1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
10
2: '== 1.0.0-rc.3',
11
3: '== 1.0.0-rc.4',
12
4: '== 1.x.x',
13
5: '== 2.0.0-alpha.x',
14
6: '>= 2.0.0-beta.1'
15
};
16
exports.REVISION_CHANGES = REVISION_CHANGES;
17
var isArray = Utils.isArray,
18
isFunction = Utils.isFunction,
19
toString = Utils.toString,
20
objectType = '[object Object]';
21
22
function HandlebarsEnvironment(helpers, partials) {
23
this.helpers = helpers || {};
24
this.partials = partials || {};
25
26
registerDefaultHelpers(this);
27
}
28
29
exports.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = {
30
constructor: HandlebarsEnvironment,
31
32
logger: logger,
33
log: log,
34
35
registerHelper: function(name, fn) {
36
if (toString.call(name) === objectType) {
37
if (fn) { throw new Exception('Arg not supported with multiple helpers'); }
38
Utils.extend(this.helpers, name);
39
} else {
40
this.helpers[name] = fn;
41
}
42
},
43
unregisterHelper: function(name) {
44
delete this.helpers[name];
45
},
46
47
registerPartial: function(name, partial) {
48
if (toString.call(name) === objectType) {
49
Utils.extend(this.partials, name);
50
} else {
51
if (typeof partial === 'undefined') {
52
throw new Exception('Attempting to register a partial as undefined');
53
}
54
this.partials[name] = partial;
55
}
56
},
57
unregisterPartial: function(name) {
58
delete this.partials[name];
59
}
60
};
61
62
function registerDefaultHelpers(instance) {
63
instance.registerHelper('helperMissing', function(/* [args, ]options */) {
64
if(arguments.length === 1) {
65
// A missing field in a {{foo}} constuct.
66
return undefined;
67
} else {
68
// Someone is actually trying to call something, blow up.
69
throw new Exception("Missing helper: '" + arguments[arguments.length-1].name + "'");
70
}
71
});
72
73
instance.registerHelper('blockHelperMissing', function(context, options) {
74
var inverse = options.inverse,
75
fn = options.fn;
76
77
if(context === true) {
78
return fn(this);
79
} else if(context === false || context == null) {
80
return inverse(this);
81
} else if (isArray(context)) {
82
if(context.length > 0) {
83
if (options.ids) {
84
options.ids = [options.name];
85
}
86
87
return instance.helpers.each(context, options);
88
} else {
89
return inverse(this);
90
}
91
} else {
92
if (options.data && options.ids) {
93
var data = createFrame(options.data);
94
data.contextPath = Utils.appendContextPath(options.data.contextPath, options.name);
95
options = {data: data};
96
}
97
98
return fn(context, options);
99
}
100
});
101
102
instance.registerHelper('each', function(context, options) {
103
if (!options) {
104
throw new Exception('Must pass iterator to #each');
105
}
106
107
var fn = options.fn, inverse = options.inverse;
108
var i = 0, ret = "", data;
109
110
var contextPath;
111
if (options.data && options.ids) {
112
contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.';
113
}
114
115
if (isFunction(context)) { context = context.call(this); }
116
117
if (options.data) {
118
data = createFrame(options.data);
119
}
120
121
function execIteration(key, i, last) {
122
if (data) {
123
data.key = key;
124
data.index = i;
125
data.first = i === 0;
126
data.last = !!last;
127
128
if (contextPath) {
129
data.contextPath = contextPath + key;
130
}
131
}
132
133
ret = ret + fn(context[key], {
134
data: data,
135
blockParams: Utils.blockParams([context[key], key], [contextPath + key, null])
136
});
137
}
138
139
if(context && typeof context === 'object') {
140
if (isArray(context)) {
141
for(var j = context.length; i<j; i++) {
142
execIteration(i, i, i === context.length-1);
143
}
144
} else {
145
var priorKey;
146
147
for(var key in context) {
148
if(context.hasOwnProperty(key)) {
149
// We're running the iterations one step out of sync so we can detect
150
// the last iteration without have to scan the object twice and create
151
// an itermediate keys array.
152
if (priorKey) {
153
execIteration(priorKey, i-1);
154
}
155
priorKey = key;
156
i++;
157
}
158
}
159
if (priorKey) {
160
execIteration(priorKey, i-1, true);
161
}
162
}
163
}
164
165
if(i === 0){
166
ret = inverse(this);
167
}
168
169
return ret;
170
});
171
172
instance.registerHelper('if', function(conditional, options) {
173
if (isFunction(conditional)) { conditional = conditional.call(this); }
174
175
// Default behavior is to render the positive path if the value is truthy and not empty.
176
// The `includeZero` option may be set to treat the condtional as purely not empty based on the
177
// behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative.
178
if ((!options.hash.includeZero && !conditional) || Utils.isEmpty(conditional)) {
179
return options.inverse(this);
180
} else {
181
return options.fn(this);
182
}
183
});
184
185
instance.registerHelper('unless', function(conditional, options) {
186
return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn, hash: options.hash});
187
});
188
189
instance.registerHelper('with', function(context, options) {
190
if (isFunction(context)) { context = context.call(this); }
191
192
var fn = options.fn;
193
194
if (!Utils.isEmpty(context)) {
195
if (options.data && options.ids) {
196
var data = createFrame(options.data);
197
data.contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]);
198
options = {data:data};
199
}
200
201
return fn(context, options);
202
} else {
203
return options.inverse(this);
204
}
205
});
206
207
instance.registerHelper('log', function(message, options) {
208
var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
209
instance.log(level, message);
210
});
211
212
instance.registerHelper('lookup', function(obj, field) {
213
return obj && obj[field];
214
});
215
}
216
217
var logger = {
218
methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' },
219
220
// State enum
221
DEBUG: 0,
222
INFO: 1,
223
WARN: 2,
224
ERROR: 3,
225
level: 1,
226
227
// Can be overridden in the host environment
228
log: function(level, message) {
229
if (typeof console !== 'undefined' && logger.level <= level) {
230
var method = logger.methodMap[level];
231
(console[method] || console.log).call(console, message);
232
}
233
}
234
};
235
exports.logger = logger;
236
var log = logger.log;
237
exports.log = log;
238
var createFrame = function(object) {
239
var frame = Utils.extend({}, object);
240
frame._parent = object;
241
return frame;
242
};
243
exports.createFrame = createFrame;
244