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