jade-js-source 0.19.0 → 0.27.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/jade_js/jade.js +722 -194
- data/lib/jade_js/runtime.js +64 -8
- metadata +3 -3
data/lib/jade_js/jade.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
(function() {
|
1
2
|
|
2
3
|
// CommonJS require()
|
3
4
|
|
@@ -29,7 +30,7 @@ require.register = function (path, fn){
|
|
29
30
|
|
30
31
|
require.relative = function (parent) {
|
31
32
|
return function(p){
|
32
|
-
if ('.' != p
|
33
|
+
if ('.' != p.charAt(0)) return require(p);
|
33
34
|
|
34
35
|
var path = parent.split('/')
|
35
36
|
, segs = p.split('/');
|
@@ -62,10 +63,10 @@ var nodes = require('./nodes')
|
|
62
63
|
, filters = require('./filters')
|
63
64
|
, doctypes = require('./doctypes')
|
64
65
|
, selfClosing = require('./self-closing')
|
65
|
-
,
|
66
|
+
, runtime = require('./runtime')
|
66
67
|
, utils = require('./utils');
|
67
68
|
|
68
|
-
|
69
|
+
|
69
70
|
if (!Object.keys) {
|
70
71
|
Object.keys = function(obj){
|
71
72
|
var arr = [];
|
@@ -75,9 +76,9 @@ var nodes = require('./nodes')
|
|
75
76
|
}
|
76
77
|
}
|
77
78
|
return arr;
|
78
|
-
}
|
79
|
+
}
|
79
80
|
}
|
80
|
-
|
81
|
+
|
81
82
|
if (!String.prototype.trimLeft) {
|
82
83
|
String.prototype.trimLeft = function(){
|
83
84
|
return this.replace(/^\s+/, '');
|
@@ -102,6 +103,7 @@ var Compiler = module.exports = function Compiler(node, options) {
|
|
102
103
|
this.pp = options.pretty || false;
|
103
104
|
this.debug = false !== options.compileDebug;
|
104
105
|
this.indents = 0;
|
106
|
+
this.parentIndents = 0;
|
105
107
|
if (options.doctype) this.setDoctype(options.doctype);
|
106
108
|
};
|
107
109
|
|
@@ -110,16 +112,17 @@ var Compiler = module.exports = function Compiler(node, options) {
|
|
110
112
|
*/
|
111
113
|
|
112
114
|
Compiler.prototype = {
|
113
|
-
|
115
|
+
|
114
116
|
/**
|
115
117
|
* Compile parse tree to JavaScript.
|
116
118
|
*
|
117
119
|
* @api public
|
118
120
|
*/
|
119
|
-
|
121
|
+
|
120
122
|
compile: function(){
|
121
123
|
this.buf = ['var interp;'];
|
122
|
-
this.
|
124
|
+
if (this.pp) this.buf.push("var __indent = [];");
|
125
|
+
this.lastBufferedIdx = -1;
|
123
126
|
this.visit(this.node);
|
124
127
|
return this.buf.join('\n');
|
125
128
|
},
|
@@ -132,15 +135,14 @@ Compiler.prototype = {
|
|
132
135
|
* @param {string} name
|
133
136
|
* @api public
|
134
137
|
*/
|
135
|
-
|
138
|
+
|
136
139
|
setDoctype: function(name){
|
137
|
-
|
138
|
-
doctype =
|
139
|
-
this.
|
140
|
-
this.terse = '5' == name || 'html' == name;
|
140
|
+
name = (name && name.toLowerCase()) || 'default';
|
141
|
+
this.doctype = doctypes[name] || '<!DOCTYPE ' + name + '>';
|
142
|
+
this.terse = this.doctype.toLowerCase() == '<!doctype html>';
|
141
143
|
this.xml = 0 == this.doctype.indexOf('<?xml');
|
142
144
|
},
|
143
|
-
|
145
|
+
|
144
146
|
/**
|
145
147
|
* Buffer the given `str` optionally escaped.
|
146
148
|
*
|
@@ -148,10 +150,10 @@ Compiler.prototype = {
|
|
148
150
|
* @param {Boolean} esc
|
149
151
|
* @api public
|
150
152
|
*/
|
151
|
-
|
153
|
+
|
152
154
|
buffer: function(str, esc){
|
153
155
|
if (esc) str = utils.escape(str);
|
154
|
-
|
156
|
+
|
155
157
|
if (this.lastBufferedIdx == this.buf.length) {
|
156
158
|
this.lastBuffered += str;
|
157
159
|
this.buf[this.lastBufferedIdx - 1] = "buf.push('" + this.lastBuffered + "');"
|
@@ -159,24 +161,41 @@ Compiler.prototype = {
|
|
159
161
|
this.buf.push("buf.push('" + str + "');");
|
160
162
|
this.lastBuffered = str;
|
161
163
|
this.lastBufferedIdx = this.buf.length;
|
162
|
-
}
|
164
|
+
}
|
163
165
|
},
|
164
|
-
|
166
|
+
|
167
|
+
/**
|
168
|
+
* Buffer an indent based on the current `indent`
|
169
|
+
* property and an additional `offset`.
|
170
|
+
*
|
171
|
+
* @param {Number} offset
|
172
|
+
* @param {Boolean} newline
|
173
|
+
* @api public
|
174
|
+
*/
|
175
|
+
|
176
|
+
prettyIndent: function(offset, newline){
|
177
|
+
offset = offset || 0;
|
178
|
+
newline = newline ? '\\n' : '';
|
179
|
+
this.buffer(newline + Array(this.indents + offset).join(' '));
|
180
|
+
if (this.parentIndents)
|
181
|
+
this.buf.push("buf.push.apply(buf, __indent);");
|
182
|
+
},
|
183
|
+
|
165
184
|
/**
|
166
185
|
* Visit `node`.
|
167
186
|
*
|
168
187
|
* @param {Node} node
|
169
188
|
* @api public
|
170
189
|
*/
|
171
|
-
|
190
|
+
|
172
191
|
visit: function(node){
|
173
192
|
var debug = this.debug;
|
174
193
|
|
175
194
|
if (debug) {
|
176
|
-
this.buf.push('
|
195
|
+
this.buf.push('__jade.unshift({ lineno: ' + node.line
|
177
196
|
+ ', filename: ' + (node.filename
|
178
|
-
?
|
179
|
-
: '
|
197
|
+
? JSON.stringify(node.filename)
|
198
|
+
: '__jade[0].filename')
|
180
199
|
+ ' });');
|
181
200
|
}
|
182
201
|
|
@@ -189,16 +208,16 @@ Compiler.prototype = {
|
|
189
208
|
|
190
209
|
this.visitNode(node);
|
191
210
|
|
192
|
-
if (debug) this.buf.push('
|
211
|
+
if (debug) this.buf.push('__jade.shift();');
|
193
212
|
},
|
194
|
-
|
213
|
+
|
195
214
|
/**
|
196
215
|
* Visit `node`.
|
197
216
|
*
|
198
217
|
* @param {Node} node
|
199
218
|
* @api public
|
200
219
|
*/
|
201
|
-
|
220
|
+
|
202
221
|
visitNode: function(node){
|
203
222
|
var name = node.constructor.name
|
204
223
|
|| node.constructor.toString().match(/function ([^(\s]+)()/)[1];
|
@@ -220,7 +239,7 @@ Compiler.prototype = {
|
|
220
239
|
this.buf.push('}');
|
221
240
|
this.withinCase = _;
|
222
241
|
},
|
223
|
-
|
242
|
+
|
224
243
|
/**
|
225
244
|
* Visit when `node`.
|
226
245
|
*
|
@@ -258,12 +277,34 @@ Compiler.prototype = {
|
|
258
277
|
*/
|
259
278
|
|
260
279
|
visitBlock: function(block){
|
261
|
-
var len = block.nodes.length
|
280
|
+
var len = block.nodes.length
|
281
|
+
, escape = this.escape
|
282
|
+
, pp = this.pp
|
283
|
+
|
284
|
+
// Block keyword has a special meaning in mixins
|
285
|
+
if (this.parentIndents && block.mode) {
|
286
|
+
if (pp) this.buf.push("__indent.push('" + Array(this.indents + 1).join(' ') + "');")
|
287
|
+
this.buf.push('block && block();');
|
288
|
+
if (pp) this.buf.push("__indent.pop();")
|
289
|
+
return;
|
290
|
+
}
|
291
|
+
|
292
|
+
// Pretty print multi-line text
|
293
|
+
if (pp && len > 1 && !escape && block.nodes[0].isText && block.nodes[1].isText)
|
294
|
+
this.prettyIndent(1, true);
|
295
|
+
|
262
296
|
for (var i = 0; i < len; ++i) {
|
297
|
+
// Pretty print text
|
298
|
+
if (pp && i > 0 && !escape && block.nodes[i].isText && block.nodes[i-1].isText)
|
299
|
+
this.prettyIndent(1, false);
|
300
|
+
|
263
301
|
this.visit(block.nodes[i]);
|
302
|
+
// Multiple text nodes are separated by newlines
|
303
|
+
if (block.nodes[i+1] && block.nodes[i].isText && block.nodes[i+1].isText)
|
304
|
+
this.buffer('\\n');
|
264
305
|
}
|
265
306
|
},
|
266
|
-
|
307
|
+
|
267
308
|
/**
|
268
309
|
* Visit `doctype`. Sets terse mode to `true` when html 5
|
269
310
|
* is used, causing self-closing tags to end with ">" vs "/>",
|
@@ -272,7 +313,7 @@ Compiler.prototype = {
|
|
272
313
|
* @param {Doctype} doctype
|
273
314
|
* @api public
|
274
315
|
*/
|
275
|
-
|
316
|
+
|
276
317
|
visitDoctype: function(doctype){
|
277
318
|
if (doctype && (doctype.val || !this.doctype)) {
|
278
319
|
this.setDoctype(doctype.val || 'default');
|
@@ -292,14 +333,62 @@ Compiler.prototype = {
|
|
292
333
|
|
293
334
|
visitMixin: function(mixin){
|
294
335
|
var name = mixin.name.replace(/-/g, '_') + '_mixin'
|
295
|
-
, args = mixin.args || ''
|
336
|
+
, args = mixin.args || ''
|
337
|
+
, block = mixin.block
|
338
|
+
, attrs = mixin.attrs
|
339
|
+
, pp = this.pp;
|
340
|
+
|
341
|
+
if (mixin.call) {
|
342
|
+
if (pp) this.buf.push("__indent.push('" + Array(this.indents + 1).join(' ') + "');")
|
343
|
+
if (block || attrs.length) {
|
344
|
+
|
345
|
+
this.buf.push(name + '.call({');
|
346
|
+
|
347
|
+
if (block) {
|
348
|
+
this.buf.push('block: function(){');
|
349
|
+
|
350
|
+
// Render block with no indents, dynamically added when rendered
|
351
|
+
this.parentIndents++;
|
352
|
+
var _indents = this.indents;
|
353
|
+
this.indents = 0;
|
354
|
+
this.visit(mixin.block);
|
355
|
+
this.indents = _indents;
|
356
|
+
this.parentIndents--;
|
357
|
+
|
358
|
+
if (attrs.length) {
|
359
|
+
this.buf.push('},');
|
360
|
+
} else {
|
361
|
+
this.buf.push('}');
|
362
|
+
}
|
363
|
+
}
|
296
364
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
365
|
+
if (attrs.length) {
|
366
|
+
var val = this.attrs(attrs);
|
367
|
+
if (val.inherits) {
|
368
|
+
this.buf.push('attributes: merge({' + val.buf
|
369
|
+
+ '}, attributes), escaped: merge(' + val.escaped + ', escaped, true)');
|
370
|
+
} else {
|
371
|
+
this.buf.push('attributes: {' + val.buf + '}, escaped: ' + val.escaped);
|
372
|
+
}
|
373
|
+
}
|
374
|
+
|
375
|
+
if (args) {
|
376
|
+
this.buf.push('}, ' + args + ');');
|
377
|
+
} else {
|
378
|
+
this.buf.push('});');
|
379
|
+
}
|
380
|
+
|
381
|
+
} else {
|
382
|
+
this.buf.push(name + '(' + args + ');');
|
383
|
+
}
|
384
|
+
if (pp) this.buf.push("__indent.pop();")
|
301
385
|
} else {
|
302
|
-
this.buf.push(name + '(' + args + ')
|
386
|
+
this.buf.push('var ' + name + ' = function(' + args + '){');
|
387
|
+
this.buf.push('var block = this.block, attributes = this.attributes || {}, escaped = this.escaped || {};');
|
388
|
+
this.parentIndents++;
|
389
|
+
this.visit(block);
|
390
|
+
this.parentIndents--;
|
391
|
+
this.buf.push('};');
|
303
392
|
}
|
304
393
|
},
|
305
394
|
|
@@ -310,10 +399,13 @@ Compiler.prototype = {
|
|
310
399
|
* @param {Tag} tag
|
311
400
|
* @api public
|
312
401
|
*/
|
313
|
-
|
402
|
+
|
314
403
|
visitTag: function(tag){
|
315
404
|
this.indents++;
|
316
|
-
var name = tag.name
|
405
|
+
var name = tag.name
|
406
|
+
, pp = this.pp;
|
407
|
+
|
408
|
+
if (tag.buffer) name = "' + (" + name + ") + '";
|
317
409
|
|
318
410
|
if (!this.hasCompiledTag) {
|
319
411
|
if (!this.hasCompiledDoctype && 'html' == name) {
|
@@ -323,11 +415,10 @@ Compiler.prototype = {
|
|
323
415
|
}
|
324
416
|
|
325
417
|
// pretty print
|
326
|
-
if (
|
327
|
-
this.
|
328
|
-
}
|
418
|
+
if (pp && !tag.isInline())
|
419
|
+
this.prettyIndent(0, true);
|
329
420
|
|
330
|
-
if (~selfClosing.indexOf(name) && !this.xml) {
|
421
|
+
if ((~selfClosing.indexOf(name) || tag.selfClosing) && !this.xml) {
|
331
422
|
this.buffer('<' + name);
|
332
423
|
this.visitAttributes(tag.attrs);
|
333
424
|
this.terse
|
@@ -343,27 +434,25 @@ Compiler.prototype = {
|
|
343
434
|
this.buffer('<' + name + '>');
|
344
435
|
}
|
345
436
|
if (tag.code) this.visitCode(tag.code);
|
346
|
-
if (tag.text) this.buffer(utils.text(tag.text.nodes[0].trimLeft()));
|
347
437
|
this.escape = 'pre' == tag.name;
|
348
438
|
this.visit(tag.block);
|
349
439
|
|
350
440
|
// pretty print
|
351
|
-
if (
|
352
|
-
this.
|
353
|
-
}
|
441
|
+
if (pp && !tag.isInline() && 'pre' != tag.name && !tag.canInline())
|
442
|
+
this.prettyIndent(0, true);
|
354
443
|
|
355
444
|
this.buffer('</' + name + '>');
|
356
445
|
}
|
357
446
|
this.indents--;
|
358
447
|
},
|
359
|
-
|
448
|
+
|
360
449
|
/**
|
361
450
|
* Visit `filter`, throwing when the filter does not exist.
|
362
451
|
*
|
363
452
|
* @param {Filter} filter
|
364
453
|
* @api public
|
365
454
|
*/
|
366
|
-
|
455
|
+
|
367
456
|
visitFilter: function(filter){
|
368
457
|
var fn = filters[filter.name];
|
369
458
|
|
@@ -375,48 +464,50 @@ Compiler.prototype = {
|
|
375
464
|
throw new Error('unknown filter ":' + filter.name + '"');
|
376
465
|
}
|
377
466
|
}
|
467
|
+
|
378
468
|
if (filter.isASTFilter) {
|
379
469
|
this.buf.push(fn(filter.block, this, filter.attrs));
|
380
470
|
} else {
|
381
|
-
var text = filter.block.nodes.join('');
|
471
|
+
var text = filter.block.nodes.map(function(node){ return node.val }).join('\n');
|
472
|
+
filter.attrs = filter.attrs || {};
|
473
|
+
filter.attrs.filename = this.options.filename;
|
382
474
|
this.buffer(utils.text(fn(text, filter.attrs)));
|
383
475
|
}
|
384
476
|
},
|
385
|
-
|
477
|
+
|
386
478
|
/**
|
387
479
|
* Visit `text` node.
|
388
480
|
*
|
389
481
|
* @param {Text} text
|
390
482
|
* @api public
|
391
483
|
*/
|
392
|
-
|
484
|
+
|
393
485
|
visitText: function(text){
|
394
|
-
text = utils.text(text.
|
486
|
+
text = utils.text(text.val.replace(/\\/g, '\\\\'));
|
395
487
|
if (this.escape) text = escape(text);
|
396
488
|
this.buffer(text);
|
397
|
-
this.buffer('\\n');
|
398
489
|
},
|
399
|
-
|
490
|
+
|
400
491
|
/**
|
401
492
|
* Visit a `comment`, only buffering when the buffer flag is set.
|
402
493
|
*
|
403
494
|
* @param {Comment} comment
|
404
495
|
* @api public
|
405
496
|
*/
|
406
|
-
|
497
|
+
|
407
498
|
visitComment: function(comment){
|
408
499
|
if (!comment.buffer) return;
|
409
|
-
if (this.pp) this.
|
500
|
+
if (this.pp) this.prettyIndent(1, true);
|
410
501
|
this.buffer('<!--' + utils.escape(comment.val) + '-->');
|
411
502
|
},
|
412
|
-
|
503
|
+
|
413
504
|
/**
|
414
505
|
* Visit a `BlockComment`.
|
415
506
|
*
|
416
507
|
* @param {Comment} comment
|
417
508
|
* @api public
|
418
509
|
*/
|
419
|
-
|
510
|
+
|
420
511
|
visitBlockComment: function(comment){
|
421
512
|
if (!comment.buffer) return;
|
422
513
|
if (0 == comment.val.trim().indexOf('if')) {
|
@@ -429,7 +520,7 @@ Compiler.prototype = {
|
|
429
520
|
this.buffer('-->');
|
430
521
|
}
|
431
522
|
},
|
432
|
-
|
523
|
+
|
433
524
|
/**
|
434
525
|
* Visit `code`, respecting buffer / escape flags.
|
435
526
|
* If the code is followed by a block, wrap it in
|
@@ -438,7 +529,7 @@ Compiler.prototype = {
|
|
438
529
|
* @param {Code} code
|
439
530
|
* @api public
|
440
531
|
*/
|
441
|
-
|
532
|
+
|
442
533
|
visitCode: function(code){
|
443
534
|
// Wrap code blocks with {}.
|
444
535
|
// we only wrap unbuffered code blocks ATM
|
@@ -462,26 +553,39 @@ Compiler.prototype = {
|
|
462
553
|
if (!code.buffer) this.buf.push('}');
|
463
554
|
}
|
464
555
|
},
|
465
|
-
|
556
|
+
|
466
557
|
/**
|
467
558
|
* Visit `each` block.
|
468
559
|
*
|
469
560
|
* @param {Each} each
|
470
561
|
* @api public
|
471
562
|
*/
|
472
|
-
|
563
|
+
|
473
564
|
visitEach: function(each){
|
474
565
|
this.buf.push(''
|
475
566
|
+ '// iterate ' + each.obj + '\n'
|
476
|
-
+ '(function(){\n'
|
477
|
-
+ ' if (\'number\' == typeof ' + each.obj + '.length) {\n'
|
567
|
+
+ ';(function(){\n'
|
568
|
+
+ ' if (\'number\' == typeof ' + each.obj + '.length) {\n');
|
569
|
+
|
570
|
+
if (each.alternative) {
|
571
|
+
this.buf.push(' if (' + each.obj + '.length) {');
|
572
|
+
}
|
573
|
+
|
574
|
+
this.buf.push(''
|
478
575
|
+ ' for (var ' + each.key + ' = 0, $$l = ' + each.obj + '.length; ' + each.key + ' < $$l; ' + each.key + '++) {\n'
|
479
576
|
+ ' var ' + each.val + ' = ' + each.obj + '[' + each.key + '];\n');
|
480
577
|
|
481
578
|
this.visit(each.block);
|
482
579
|
|
580
|
+
this.buf.push(' }\n');
|
581
|
+
|
582
|
+
if (each.alternative) {
|
583
|
+
this.buf.push(' } else {');
|
584
|
+
this.visit(each.alternative);
|
585
|
+
this.buf.push(' }');
|
586
|
+
}
|
587
|
+
|
483
588
|
this.buf.push(''
|
484
|
-
+ ' }\n'
|
485
589
|
+ ' } else {\n'
|
486
590
|
+ ' for (var ' + each.key + ' in ' + each.obj + ') {\n'
|
487
591
|
+ ' if (' + each.obj + '.hasOwnProperty(' + each.key + ')){'
|
@@ -493,21 +597,43 @@ Compiler.prototype = {
|
|
493
597
|
|
494
598
|
this.buf.push(' }\n }\n}).call(this);\n');
|
495
599
|
},
|
496
|
-
|
600
|
+
|
497
601
|
/**
|
498
602
|
* Visit `attrs`.
|
499
603
|
*
|
500
604
|
* @param {Array} attrs
|
501
605
|
* @api public
|
502
606
|
*/
|
503
|
-
|
607
|
+
|
504
608
|
visitAttributes: function(attrs){
|
609
|
+
var val = this.attrs(attrs);
|
610
|
+
if (val.inherits) {
|
611
|
+
this.buf.push("buf.push(attrs(merge({ " + val.buf +
|
612
|
+
" }, attributes), merge(" + val.escaped + ", escaped, true)));");
|
613
|
+
} else if (val.constant) {
|
614
|
+
eval('var buf={' + val.buf + '};');
|
615
|
+
this.buffer(runtime.attrs(buf, JSON.parse(val.escaped)), true);
|
616
|
+
} else {
|
617
|
+
this.buf.push("buf.push(attrs({ " + val.buf + " }, " + val.escaped + "));");
|
618
|
+
}
|
619
|
+
},
|
620
|
+
|
621
|
+
/**
|
622
|
+
* Compile attributes.
|
623
|
+
*/
|
624
|
+
|
625
|
+
attrs: function(attrs){
|
505
626
|
var buf = []
|
506
|
-
, classes = []
|
627
|
+
, classes = []
|
628
|
+
, escaped = {}
|
629
|
+
, constant = attrs.every(function(attr){ return isConstant(attr.val) })
|
630
|
+
, inherits = false;
|
507
631
|
|
508
632
|
if (this.terse) buf.push('terse: true');
|
509
633
|
|
510
634
|
attrs.forEach(function(attr){
|
635
|
+
if (attr.name == 'attributes') return inherits = true;
|
636
|
+
escaped[attr.name] = attr.escaped;
|
511
637
|
if (attr.name == 'class') {
|
512
638
|
classes.push('(' + attr.val + ')');
|
513
639
|
} else {
|
@@ -521,12 +647,40 @@ Compiler.prototype = {
|
|
521
647
|
buf.push("class: " + classes);
|
522
648
|
}
|
523
649
|
|
524
|
-
|
525
|
-
|
526
|
-
|
650
|
+
return {
|
651
|
+
buf: buf.join(', ').replace('class:', '"class":'),
|
652
|
+
escaped: JSON.stringify(escaped),
|
653
|
+
inherits: inherits,
|
654
|
+
constant: constant
|
655
|
+
};
|
527
656
|
}
|
528
657
|
};
|
529
658
|
|
659
|
+
/**
|
660
|
+
* Check if expression can be evaluated to a constant
|
661
|
+
*
|
662
|
+
* @param {String} expression
|
663
|
+
* @return {Boolean}
|
664
|
+
* @api private
|
665
|
+
*/
|
666
|
+
|
667
|
+
function isConstant(val){
|
668
|
+
// Check strings/literals
|
669
|
+
if (/^ *("([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'|true|false|null|undefined) *$/i.test(val))
|
670
|
+
return true;
|
671
|
+
|
672
|
+
// Check numbers
|
673
|
+
if (!isNaN(Number(val)))
|
674
|
+
return true;
|
675
|
+
|
676
|
+
// Check arrays
|
677
|
+
var matches;
|
678
|
+
if (matches = /^ *\[(.*)\] *$/.exec(val))
|
679
|
+
return matches[1].split(',').every(isConstant);
|
680
|
+
|
681
|
+
return false;
|
682
|
+
}
|
683
|
+
|
530
684
|
/**
|
531
685
|
* Escape the given string of `html`.
|
532
686
|
*
|
@@ -555,8 +709,8 @@ require.register("doctypes.js", function(module, exports, require){
|
|
555
709
|
|
556
710
|
module.exports = {
|
557
711
|
'5': '<!DOCTYPE html>'
|
712
|
+
, 'default': '<!DOCTYPE html>'
|
558
713
|
, 'xml': '<?xml version="1.0" encoding="utf-8" ?>'
|
559
|
-
, 'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
|
560
714
|
, 'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
|
561
715
|
, 'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
|
562
716
|
, 'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
|
@@ -640,7 +794,12 @@ module.exports = {
|
|
640
794
|
try {
|
641
795
|
md = require('markdown-js');
|
642
796
|
} catch (err) {
|
643
|
-
|
797
|
+
try {
|
798
|
+
md = require('marked');
|
799
|
+
} catch (err) {
|
800
|
+
throw new
|
801
|
+
Error('Cannot find markdown library, install markdown, discount, or marked.');
|
802
|
+
}
|
644
803
|
}
|
645
804
|
}
|
646
805
|
}
|
@@ -655,7 +814,7 @@ module.exports = {
|
|
655
814
|
|
656
815
|
coffeescript: function(str){
|
657
816
|
str = str.replace(/\\n/g, '\n');
|
658
|
-
var js = require('coffee-script').compile(str).replace(/\n/g, '\\n');
|
817
|
+
var js = require('coffee-script').compile(str).replace(/\\/g, '\\\\').replace(/\n/g, '\\n');
|
659
818
|
return '<script type="text/javascript">\\n' + js + '</script>';
|
660
819
|
}
|
661
820
|
};
|
@@ -694,7 +853,6 @@ module.exports = [
|
|
694
853
|
}); // module: inline-tags.js
|
695
854
|
|
696
855
|
require.register("jade.js", function(module, exports, require){
|
697
|
-
|
698
856
|
/*!
|
699
857
|
* Jade
|
700
858
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
@@ -714,7 +872,7 @@ var Parser = require('./parser')
|
|
714
872
|
* Library version.
|
715
873
|
*/
|
716
874
|
|
717
|
-
exports.version = '0.
|
875
|
+
exports.version = '0.27.6';
|
718
876
|
|
719
877
|
/**
|
720
878
|
* Expose self closing tags.
|
@@ -811,11 +969,25 @@ function parse(str, options){
|
|
811
969
|
}
|
812
970
|
}
|
813
971
|
|
972
|
+
/**
|
973
|
+
* Strip any UTF-8 BOM off of the start of `str`, if it exists.
|
974
|
+
*
|
975
|
+
* @param {String} str
|
976
|
+
* @return {String}
|
977
|
+
* @api private
|
978
|
+
*/
|
979
|
+
|
980
|
+
function stripBOM(str){
|
981
|
+
return 0xFEFF == str.charCodeAt(0)
|
982
|
+
? str.substring(1)
|
983
|
+
: str;
|
984
|
+
}
|
985
|
+
|
814
986
|
/**
|
815
987
|
* Compile a `Function` representation of the given jade `str`.
|
816
988
|
*
|
817
989
|
* Options:
|
818
|
-
*
|
990
|
+
*
|
819
991
|
* - `compileDebug` when `false` debugging code is stripped from the compiled template
|
820
992
|
* - `client` when `true` the helper functions `escape()` etc will reference `jade.escape()`
|
821
993
|
* for use with the Jade client-side runtime.js
|
@@ -834,29 +1006,31 @@ exports.compile = function(str, options){
|
|
834
1006
|
: 'undefined'
|
835
1007
|
, fn;
|
836
1008
|
|
1009
|
+
str = stripBOM(String(str));
|
1010
|
+
|
837
1011
|
if (options.compileDebug !== false) {
|
838
1012
|
fn = [
|
839
|
-
'var
|
1013
|
+
'var __jade = [{ lineno: 1, filename: ' + filename + ' }];'
|
840
1014
|
, 'try {'
|
841
|
-
, parse(
|
1015
|
+
, parse(str, options)
|
842
1016
|
, '} catch (err) {'
|
843
|
-
, ' rethrow(err,
|
1017
|
+
, ' rethrow(err, __jade[0].filename, __jade[0].lineno);'
|
844
1018
|
, '}'
|
845
1019
|
].join('\n');
|
846
1020
|
} else {
|
847
|
-
fn = parse(
|
1021
|
+
fn = parse(str, options);
|
848
1022
|
}
|
849
1023
|
|
850
1024
|
if (client) {
|
851
|
-
fn = '
|
1025
|
+
fn = 'attrs = attrs || jade.attrs; escape = escape || jade.escape; rethrow = rethrow || jade.rethrow; merge = merge || jade.merge;\n' + fn;
|
852
1026
|
}
|
853
1027
|
|
854
|
-
fn = new Function('locals, attrs, escape, rethrow', fn);
|
1028
|
+
fn = new Function('locals, attrs, escape, rethrow, merge', fn);
|
855
1029
|
|
856
1030
|
if (client) return fn;
|
857
1031
|
|
858
1032
|
return function(locals){
|
859
|
-
return fn(locals, runtime.attrs, runtime.escape, runtime.rethrow);
|
1033
|
+
return fn(locals, runtime.attrs, runtime.escape, runtime.rethrow, runtime.merge);
|
860
1034
|
};
|
861
1035
|
};
|
862
1036
|
|
@@ -929,16 +1103,18 @@ exports.renderFile = function(path, options, fn){
|
|
929
1103
|
*/
|
930
1104
|
|
931
1105
|
exports.__express = exports.renderFile;
|
1106
|
+
|
932
1107
|
}); // module: jade.js
|
933
1108
|
|
934
1109
|
require.register("lexer.js", function(module, exports, require){
|
935
|
-
|
936
1110
|
/*!
|
937
1111
|
* Jade - Lexer
|
938
1112
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
939
1113
|
* MIT Licensed
|
940
1114
|
*/
|
941
1115
|
|
1116
|
+
var utils = require('./utils');
|
1117
|
+
|
942
1118
|
/**
|
943
1119
|
* Initialize `Lexer` with the given `str`.
|
944
1120
|
*
|
@@ -1055,9 +1231,9 @@ Lexer.prototype = {
|
|
1055
1231
|
, nend = 0
|
1056
1232
|
, pos = 0;
|
1057
1233
|
for (var i = 0, len = str.length; i < len; ++i) {
|
1058
|
-
if (start == str
|
1234
|
+
if (start == str.charAt(i)) {
|
1059
1235
|
++nstart;
|
1060
|
-
} else if (end == str
|
1236
|
+
} else if (end == str.charAt(i)) {
|
1061
1237
|
if (++nend == nstart) {
|
1062
1238
|
pos = i;
|
1063
1239
|
break;
|
@@ -1099,6 +1275,19 @@ Lexer.prototype = {
|
|
1099
1275
|
}
|
1100
1276
|
},
|
1101
1277
|
|
1278
|
+
/**
|
1279
|
+
* Blank line.
|
1280
|
+
*/
|
1281
|
+
|
1282
|
+
blank: function() {
|
1283
|
+
var captures;
|
1284
|
+
if (captures = /^\n *\n/.exec(this.input)) {
|
1285
|
+
this.consume(captures[0].length - 1);
|
1286
|
+
if (this.pipeless) return this.tok('text', '');
|
1287
|
+
return this.next();
|
1288
|
+
}
|
1289
|
+
},
|
1290
|
+
|
1102
1291
|
/**
|
1103
1292
|
* Comment.
|
1104
1293
|
*/
|
@@ -1112,14 +1301,26 @@ Lexer.prototype = {
|
|
1112
1301
|
return tok;
|
1113
1302
|
}
|
1114
1303
|
},
|
1115
|
-
|
1304
|
+
|
1305
|
+
/**
|
1306
|
+
* Interpolated tag.
|
1307
|
+
*/
|
1308
|
+
|
1309
|
+
interpolation: function() {
|
1310
|
+
var captures;
|
1311
|
+
if (captures = /^#\{(.*?)\}/.exec(this.input)) {
|
1312
|
+
this.consume(captures[0].length);
|
1313
|
+
return this.tok('interpolation', captures[1]);
|
1314
|
+
}
|
1315
|
+
},
|
1316
|
+
|
1116
1317
|
/**
|
1117
1318
|
* Tag.
|
1118
1319
|
*/
|
1119
1320
|
|
1120
1321
|
tag: function() {
|
1121
1322
|
var captures;
|
1122
|
-
if (captures = /^(\w[-:\w]*)/.exec(this.input)) {
|
1323
|
+
if (captures = /^(\w[-:\w]*)(\/?)/.exec(this.input)) {
|
1123
1324
|
this.consume(captures[0].length);
|
1124
1325
|
var tok, name = captures[1];
|
1125
1326
|
if (':' == name[name.length - 1]) {
|
@@ -1130,6 +1331,7 @@ Lexer.prototype = {
|
|
1130
1331
|
} else {
|
1131
1332
|
tok = this.tok('tag', name);
|
1132
1333
|
}
|
1334
|
+
tok.selfClosing = !! captures[2];
|
1133
1335
|
return tok;
|
1134
1336
|
}
|
1135
1337
|
},
|
@@ -1171,15 +1373,15 @@ Lexer.prototype = {
|
|
1171
1373
|
*/
|
1172
1374
|
|
1173
1375
|
text: function() {
|
1174
|
-
return this.scan(/^(?:\| ?)?([^\n]+)/, 'text');
|
1376
|
+
return this.scan(/^(?:\| ?| ?)?([^\n]+)/, 'text');
|
1175
1377
|
},
|
1176
1378
|
|
1177
1379
|
/**
|
1178
1380
|
* Extends.
|
1179
1381
|
*/
|
1180
1382
|
|
1181
|
-
extends: function() {
|
1182
|
-
return this.scan(/^extends +([^\n]+)/, 'extends');
|
1383
|
+
"extends": function() {
|
1384
|
+
return this.scan(/^extends? +([^\n]+)/, 'extends');
|
1183
1385
|
},
|
1184
1386
|
|
1185
1387
|
/**
|
@@ -1220,16 +1422,25 @@ Lexer.prototype = {
|
|
1220
1422
|
|
1221
1423
|
block: function() {
|
1222
1424
|
var captures;
|
1223
|
-
if (captures = /^block
|
1425
|
+
if (captures = /^block\b *(?:(prepend|append) +)?([^\n]*)/.exec(this.input)) {
|
1224
1426
|
this.consume(captures[0].length);
|
1225
1427
|
var mode = captures[1] || 'replace'
|
1226
1428
|
, name = captures[2]
|
1227
1429
|
, tok = this.tok('block', name);
|
1430
|
+
|
1228
1431
|
tok.mode = mode;
|
1229
1432
|
return tok;
|
1230
1433
|
}
|
1231
1434
|
},
|
1232
1435
|
|
1436
|
+
/**
|
1437
|
+
* Yield.
|
1438
|
+
*/
|
1439
|
+
|
1440
|
+
yield: function() {
|
1441
|
+
return this.scan(/^yield */, 'yield');
|
1442
|
+
},
|
1443
|
+
|
1233
1444
|
/**
|
1234
1445
|
* Include.
|
1235
1446
|
*/
|
@@ -1242,7 +1453,7 @@ Lexer.prototype = {
|
|
1242
1453
|
* Case.
|
1243
1454
|
*/
|
1244
1455
|
|
1245
|
-
case: function() {
|
1456
|
+
"case": function() {
|
1246
1457
|
return this.scan(/^case +([^\n]+)/, 'case');
|
1247
1458
|
},
|
1248
1459
|
|
@@ -1258,7 +1469,7 @@ Lexer.prototype = {
|
|
1258
1469
|
* Default.
|
1259
1470
|
*/
|
1260
1471
|
|
1261
|
-
default: function() {
|
1472
|
+
"default": function() {
|
1262
1473
|
return this.scan(/^default */, 'default');
|
1263
1474
|
},
|
1264
1475
|
|
@@ -1276,13 +1487,35 @@ Lexer.prototype = {
|
|
1276
1487
|
}
|
1277
1488
|
},
|
1278
1489
|
|
1490
|
+
/**
|
1491
|
+
* Call mixin.
|
1492
|
+
*/
|
1493
|
+
|
1494
|
+
call: function(){
|
1495
|
+
var captures;
|
1496
|
+
if (captures = /^\+([-\w]+)/.exec(this.input)) {
|
1497
|
+
this.consume(captures[0].length);
|
1498
|
+
var tok = this.tok('call', captures[1]);
|
1499
|
+
|
1500
|
+
// Check for args (not attributes)
|
1501
|
+
if (captures = /^ *\((.*?)\)/.exec(this.input)) {
|
1502
|
+
if (!/^ *[-\w]+ *=/.test(captures[1])) {
|
1503
|
+
this.consume(captures[0].length);
|
1504
|
+
tok.args = captures[1];
|
1505
|
+
}
|
1506
|
+
}
|
1507
|
+
|
1508
|
+
return tok;
|
1509
|
+
}
|
1510
|
+
},
|
1511
|
+
|
1279
1512
|
/**
|
1280
1513
|
* Mixin.
|
1281
1514
|
*/
|
1282
1515
|
|
1283
1516
|
mixin: function(){
|
1284
1517
|
var captures;
|
1285
|
-
if (captures = /^mixin +([-\w]+)(
|
1518
|
+
if (captures = /^mixin +([-\w]+)(?: *\((.*)\))?/.exec(this.input)) {
|
1286
1519
|
this.consume(captures[0].length);
|
1287
1520
|
var tok = this.tok('mixin', captures[1]);
|
1288
1521
|
tok.args = captures[2];
|
@@ -1316,7 +1549,7 @@ Lexer.prototype = {
|
|
1316
1549
|
* While.
|
1317
1550
|
*/
|
1318
1551
|
|
1319
|
-
while: function() {
|
1552
|
+
"while": function() {
|
1320
1553
|
var captures;
|
1321
1554
|
if (captures = /^while +([^\n]+)/.exec(this.input)) {
|
1322
1555
|
this.consume(captures[0].length);
|
@@ -1350,8 +1583,8 @@ Lexer.prototype = {
|
|
1350
1583
|
var flags = captures[1];
|
1351
1584
|
captures[1] = captures[2];
|
1352
1585
|
var tok = this.tok('code', captures[1]);
|
1353
|
-
tok.escape = flags
|
1354
|
-
tok.buffer = flags
|
1586
|
+
tok.escape = flags.charAt(0) === '=';
|
1587
|
+
tok.buffer = flags.charAt(0) === '=' || flags.charAt(1) === '=';
|
1355
1588
|
return tok;
|
1356
1589
|
}
|
1357
1590
|
},
|
@@ -1361,30 +1594,35 @@ Lexer.prototype = {
|
|
1361
1594
|
*/
|
1362
1595
|
|
1363
1596
|
attrs: function() {
|
1364
|
-
if ('(' == this.input
|
1597
|
+
if ('(' == this.input.charAt(0)) {
|
1365
1598
|
var index = this.indexOfDelimiters('(', ')')
|
1366
1599
|
, str = this.input.substr(1, index-1)
|
1367
1600
|
, tok = this.tok('attrs')
|
1368
1601
|
, len = str.length
|
1369
1602
|
, colons = this.colons
|
1370
1603
|
, states = ['key']
|
1604
|
+
, escapedAttr
|
1371
1605
|
, key = ''
|
1372
1606
|
, val = ''
|
1373
1607
|
, quote
|
1374
|
-
, c
|
1608
|
+
, c
|
1609
|
+
, p;
|
1375
1610
|
|
1376
1611
|
function state(){
|
1377
1612
|
return states[states.length - 1];
|
1378
1613
|
}
|
1379
1614
|
|
1380
1615
|
function interpolate(attr) {
|
1381
|
-
return attr.replace(
|
1382
|
-
return
|
1616
|
+
return attr.replace(/(\\)?#\{([^}]+)\}/g, function(_, escape, expr){
|
1617
|
+
return escape
|
1618
|
+
? _
|
1619
|
+
: quote + " + (" + expr + ") + " + quote;
|
1383
1620
|
});
|
1384
1621
|
}
|
1385
1622
|
|
1386
1623
|
this.consume(index + 1);
|
1387
1624
|
tok.attrs = {};
|
1625
|
+
tok.escaped = {};
|
1388
1626
|
|
1389
1627
|
function parse(c) {
|
1390
1628
|
var real = c;
|
@@ -1405,7 +1643,9 @@ Lexer.prototype = {
|
|
1405
1643
|
val = val.trim();
|
1406
1644
|
key = key.trim();
|
1407
1645
|
if ('' == key) return;
|
1408
|
-
|
1646
|
+
key = key.replace(/^['"]|['"]$/g, '').replace('!', '');
|
1647
|
+
tok.escaped[key] = escapedAttr;
|
1648
|
+
tok.attrs[key] = '' == val
|
1409
1649
|
? true
|
1410
1650
|
: interpolate(val);
|
1411
1651
|
key = val = '';
|
@@ -1424,6 +1664,7 @@ Lexer.prototype = {
|
|
1424
1664
|
val += real;
|
1425
1665
|
break;
|
1426
1666
|
default:
|
1667
|
+
escapedAttr = '!' != p;
|
1427
1668
|
states.push('val');
|
1428
1669
|
}
|
1429
1670
|
break;
|
@@ -1484,14 +1725,20 @@ Lexer.prototype = {
|
|
1484
1725
|
val += c;
|
1485
1726
|
}
|
1486
1727
|
}
|
1728
|
+
p = c;
|
1487
1729
|
}
|
1488
1730
|
|
1489
1731
|
for (var i = 0; i < len; ++i) {
|
1490
|
-
parse(str
|
1732
|
+
parse(str.charAt(i));
|
1491
1733
|
}
|
1492
1734
|
|
1493
1735
|
parse(',');
|
1494
1736
|
|
1737
|
+
if ('/' == this.input.charAt(0)) {
|
1738
|
+
this.consume(1);
|
1739
|
+
tok.selfClosing = true;
|
1740
|
+
}
|
1741
|
+
|
1495
1742
|
return tok;
|
1496
1743
|
}
|
1497
1744
|
},
|
@@ -1602,21 +1849,25 @@ Lexer.prototype = {
|
|
1602
1849
|
|
1603
1850
|
next: function() {
|
1604
1851
|
return this.deferred()
|
1852
|
+
|| this.blank()
|
1605
1853
|
|| this.eos()
|
1606
1854
|
|| this.pipelessText()
|
1855
|
+
|| this.yield()
|
1607
1856
|
|| this.doctype()
|
1608
|
-
|| this.
|
1857
|
+
|| this.interpolation()
|
1858
|
+
|| this["case"]()
|
1609
1859
|
|| this.when()
|
1610
|
-
|| this
|
1611
|
-
|| this
|
1860
|
+
|| this["default"]()
|
1861
|
+
|| this["extends"]()
|
1612
1862
|
|| this.append()
|
1613
1863
|
|| this.prepend()
|
1614
1864
|
|| this.block()
|
1615
1865
|
|| this.include()
|
1616
1866
|
|| this.mixin()
|
1867
|
+
|| this.call()
|
1617
1868
|
|| this.conditional()
|
1618
1869
|
|| this.each()
|
1619
|
-
|| this
|
1870
|
+
|| this["while"]()
|
1620
1871
|
|| this.assignment()
|
1621
1872
|
|| this.tag()
|
1622
1873
|
|| this.filter()
|
@@ -1633,6 +1884,89 @@ Lexer.prototype = {
|
|
1633
1884
|
|
1634
1885
|
}); // module: lexer.js
|
1635
1886
|
|
1887
|
+
require.register("nodes/attrs.js", function(module, exports, require){
|
1888
|
+
|
1889
|
+
/*!
|
1890
|
+
* Jade - nodes - Attrs
|
1891
|
+
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
1892
|
+
* MIT Licensed
|
1893
|
+
*/
|
1894
|
+
|
1895
|
+
/**
|
1896
|
+
* Module dependencies.
|
1897
|
+
*/
|
1898
|
+
|
1899
|
+
var Node = require('./node'),
|
1900
|
+
Block = require('./block');
|
1901
|
+
|
1902
|
+
/**
|
1903
|
+
* Initialize a `Attrs` node.
|
1904
|
+
*
|
1905
|
+
* @api public
|
1906
|
+
*/
|
1907
|
+
|
1908
|
+
var Attrs = module.exports = function Attrs() {
|
1909
|
+
this.attrs = [];
|
1910
|
+
};
|
1911
|
+
|
1912
|
+
/**
|
1913
|
+
* Inherit from `Node`.
|
1914
|
+
*/
|
1915
|
+
|
1916
|
+
Attrs.prototype = new Node;
|
1917
|
+
Attrs.prototype.constructor = Attrs;
|
1918
|
+
|
1919
|
+
|
1920
|
+
/**
|
1921
|
+
* Set attribute `name` to `val`, keep in mind these become
|
1922
|
+
* part of a raw js object literal, so to quote a value you must
|
1923
|
+
* '"quote me"', otherwise or example 'user.name' is literal JavaScript.
|
1924
|
+
*
|
1925
|
+
* @param {String} name
|
1926
|
+
* @param {String} val
|
1927
|
+
* @param {Boolean} escaped
|
1928
|
+
* @return {Tag} for chaining
|
1929
|
+
* @api public
|
1930
|
+
*/
|
1931
|
+
|
1932
|
+
Attrs.prototype.setAttribute = function(name, val, escaped){
|
1933
|
+
this.attrs.push({ name: name, val: val, escaped: escaped });
|
1934
|
+
return this;
|
1935
|
+
};
|
1936
|
+
|
1937
|
+
/**
|
1938
|
+
* Remove attribute `name` when present.
|
1939
|
+
*
|
1940
|
+
* @param {String} name
|
1941
|
+
* @api public
|
1942
|
+
*/
|
1943
|
+
|
1944
|
+
Attrs.prototype.removeAttribute = function(name){
|
1945
|
+
for (var i = 0, len = this.attrs.length; i < len; ++i) {
|
1946
|
+
if (this.attrs[i] && this.attrs[i].name == name) {
|
1947
|
+
delete this.attrs[i];
|
1948
|
+
}
|
1949
|
+
}
|
1950
|
+
};
|
1951
|
+
|
1952
|
+
/**
|
1953
|
+
* Get attribute value by `name`.
|
1954
|
+
*
|
1955
|
+
* @param {String} name
|
1956
|
+
* @return {String}
|
1957
|
+
* @api public
|
1958
|
+
*/
|
1959
|
+
|
1960
|
+
Attrs.prototype.getAttribute = function(name){
|
1961
|
+
for (var i = 0, len = this.attrs.length; i < len; ++i) {
|
1962
|
+
if (this.attrs[i] && this.attrs[i].name == name) {
|
1963
|
+
return this.attrs[i].val;
|
1964
|
+
}
|
1965
|
+
}
|
1966
|
+
};
|
1967
|
+
|
1968
|
+
}); // module: nodes/attrs.js
|
1969
|
+
|
1636
1970
|
require.register("nodes/block-comment.js", function(module, exports, require){
|
1637
1971
|
|
1638
1972
|
/*!
|
@@ -1705,6 +2039,12 @@ Block.prototype = new Node;
|
|
1705
2039
|
Block.prototype.constructor = Block;
|
1706
2040
|
|
1707
2041
|
|
2042
|
+
/**
|
2043
|
+
* Block flag.
|
2044
|
+
*/
|
2045
|
+
|
2046
|
+
Block.prototype.isBlock = true;
|
2047
|
+
|
1708
2048
|
/**
|
1709
2049
|
* Replace the nodes in `other` with the nodes
|
1710
2050
|
* in `this` block.
|
@@ -1753,21 +2093,41 @@ Block.prototype.unshift = function(node){
|
|
1753
2093
|
};
|
1754
2094
|
|
1755
2095
|
/**
|
1756
|
-
* Return the "last" block.
|
2096
|
+
* Return the "last" block, or the first `yield` node.
|
1757
2097
|
*
|
1758
2098
|
* @return {Block}
|
1759
2099
|
* @api private
|
1760
2100
|
*/
|
1761
2101
|
|
1762
|
-
Block.prototype.
|
1763
|
-
var
|
2102
|
+
Block.prototype.includeBlock = function(){
|
2103
|
+
var ret = this
|
1764
2104
|
, node;
|
2105
|
+
|
1765
2106
|
for (var i = 0, len = this.nodes.length; i < len; ++i) {
|
1766
2107
|
node = this.nodes[i];
|
1767
|
-
if (node.
|
1768
|
-
else if (node.
|
2108
|
+
if (node.yield) return node;
|
2109
|
+
else if (node.textOnly) continue;
|
2110
|
+
else if (node.includeBlock) ret = node.includeBlock();
|
2111
|
+
else if (node.block && !node.block.isEmpty()) ret = node.block.includeBlock();
|
2112
|
+
if (ret.yield) return ret;
|
2113
|
+
}
|
2114
|
+
|
2115
|
+
return ret;
|
2116
|
+
};
|
2117
|
+
|
2118
|
+
/**
|
2119
|
+
* Return a clone of this block.
|
2120
|
+
*
|
2121
|
+
* @return {Block}
|
2122
|
+
* @api private
|
2123
|
+
*/
|
2124
|
+
|
2125
|
+
Block.prototype.clone = function(){
|
2126
|
+
var clone = new Block;
|
2127
|
+
for (var i = 0, len = this.nodes.length; i < len; ++i) {
|
2128
|
+
clone.push(this.nodes[i].clone());
|
1769
2129
|
}
|
1770
|
-
return
|
2130
|
+
return clone;
|
1771
2131
|
};
|
1772
2132
|
|
1773
2133
|
|
@@ -2003,7 +2363,7 @@ var Filter = module.exports = function Filter(name, block, attrs) {
|
|
2003
2363
|
this.name = name;
|
2004
2364
|
this.block = block;
|
2005
2365
|
this.attrs = attrs;
|
2006
|
-
this.isASTFilter = block
|
2366
|
+
this.isASTFilter = !block.nodes.every(function(node){ return node.isText });
|
2007
2367
|
};
|
2008
2368
|
|
2009
2369
|
/**
|
@@ -2062,7 +2422,8 @@ var Node = require('./node');
|
|
2062
2422
|
|
2063
2423
|
var Literal = module.exports = function Literal(str) {
|
2064
2424
|
this.str = str
|
2065
|
-
.replace(
|
2425
|
+
.replace(/\\/g, "\\\\")
|
2426
|
+
.replace(/\n|\r\n/g, "\\n")
|
2066
2427
|
.replace(/'/g, "\\'");
|
2067
2428
|
};
|
2068
2429
|
|
@@ -2088,7 +2449,7 @@ require.register("nodes/mixin.js", function(module, exports, require){
|
|
2088
2449
|
* Module dependencies.
|
2089
2450
|
*/
|
2090
2451
|
|
2091
|
-
var
|
2452
|
+
var Attrs = require('./attrs');
|
2092
2453
|
|
2093
2454
|
/**
|
2094
2455
|
* Initialize a new `Mixin` with `name` and `block`.
|
@@ -2099,17 +2460,19 @@ var Node = require('./node');
|
|
2099
2460
|
* @api public
|
2100
2461
|
*/
|
2101
2462
|
|
2102
|
-
var Mixin = module.exports = function Mixin(name, args, block){
|
2463
|
+
var Mixin = module.exports = function Mixin(name, args, block, call){
|
2103
2464
|
this.name = name;
|
2104
2465
|
this.args = args;
|
2105
2466
|
this.block = block;
|
2467
|
+
this.attrs = [];
|
2468
|
+
this.call = call;
|
2106
2469
|
};
|
2107
2470
|
|
2108
2471
|
/**
|
2109
|
-
* Inherit from `
|
2472
|
+
* Inherit from `Attrs`.
|
2110
2473
|
*/
|
2111
2474
|
|
2112
|
-
Mixin.prototype = new
|
2475
|
+
Mixin.prototype = new Attrs;
|
2113
2476
|
Mixin.prototype.constructor = Mixin;
|
2114
2477
|
|
2115
2478
|
|
@@ -2131,6 +2494,18 @@ require.register("nodes/node.js", function(module, exports, require){
|
|
2131
2494
|
*/
|
2132
2495
|
|
2133
2496
|
var Node = module.exports = function Node(){};
|
2497
|
+
|
2498
|
+
/**
|
2499
|
+
* Clone this node (return itself)
|
2500
|
+
*
|
2501
|
+
* @return {Node}
|
2502
|
+
* @api private
|
2503
|
+
*/
|
2504
|
+
|
2505
|
+
Node.prototype.clone = function(){
|
2506
|
+
return this;
|
2507
|
+
};
|
2508
|
+
|
2134
2509
|
}); // module: nodes/node.js
|
2135
2510
|
|
2136
2511
|
require.register("nodes/tag.js", function(module, exports, require){
|
@@ -2145,8 +2520,9 @@ require.register("nodes/tag.js", function(module, exports, require){
|
|
2145
2520
|
* Module dependencies.
|
2146
2521
|
*/
|
2147
2522
|
|
2148
|
-
var
|
2149
|
-
Block = require('./block')
|
2523
|
+
var Attrs = require('./attrs'),
|
2524
|
+
Block = require('./block'),
|
2525
|
+
inlineTags = require('../inline-tags');
|
2150
2526
|
|
2151
2527
|
/**
|
2152
2528
|
* Initialize a `Tag` node with the given tag `name` and optional `block`.
|
@@ -2163,60 +2539,73 @@ var Tag = module.exports = function Tag(name, block) {
|
|
2163
2539
|
};
|
2164
2540
|
|
2165
2541
|
/**
|
2166
|
-
* Inherit from `
|
2542
|
+
* Inherit from `Attrs`.
|
2167
2543
|
*/
|
2168
2544
|
|
2169
|
-
Tag.prototype = new
|
2545
|
+
Tag.prototype = new Attrs;
|
2170
2546
|
Tag.prototype.constructor = Tag;
|
2171
2547
|
|
2172
2548
|
|
2173
2549
|
/**
|
2174
|
-
*
|
2175
|
-
* part of a raw js object literal, so to quote a value you must
|
2176
|
-
* '"quote me"', otherwise or example 'user.name' is literal JavaScript.
|
2550
|
+
* Clone this tag.
|
2177
2551
|
*
|
2178
|
-
* @
|
2179
|
-
* @
|
2180
|
-
* @return {Tag} for chaining
|
2181
|
-
* @api public
|
2552
|
+
* @return {Tag}
|
2553
|
+
* @api private
|
2182
2554
|
*/
|
2183
2555
|
|
2184
|
-
Tag.prototype.
|
2185
|
-
this.
|
2186
|
-
|
2556
|
+
Tag.prototype.clone = function(){
|
2557
|
+
var clone = new Tag(this.name, this.block.clone());
|
2558
|
+
clone.line = this.line;
|
2559
|
+
clone.attrs = this.attrs;
|
2560
|
+
clone.textOnly = this.textOnly;
|
2561
|
+
return clone;
|
2187
2562
|
};
|
2188
2563
|
|
2189
2564
|
/**
|
2190
|
-
*
|
2565
|
+
* Check if this tag is an inline tag.
|
2191
2566
|
*
|
2192
|
-
* @
|
2193
|
-
* @api
|
2567
|
+
* @return {Boolean}
|
2568
|
+
* @api private
|
2194
2569
|
*/
|
2195
2570
|
|
2196
|
-
Tag.prototype.
|
2197
|
-
|
2198
|
-
if (this.attrs[i] && this.attrs[i].name == name) {
|
2199
|
-
delete this.attrs[i];
|
2200
|
-
}
|
2201
|
-
}
|
2571
|
+
Tag.prototype.isInline = function(){
|
2572
|
+
return ~inlineTags.indexOf(this.name);
|
2202
2573
|
};
|
2203
2574
|
|
2204
2575
|
/**
|
2205
|
-
*
|
2576
|
+
* Check if this tag's contents can be inlined. Used for pretty printing.
|
2206
2577
|
*
|
2207
|
-
* @
|
2208
|
-
* @
|
2209
|
-
* @api public
|
2578
|
+
* @return {Boolean}
|
2579
|
+
* @api private
|
2210
2580
|
*/
|
2211
2581
|
|
2212
|
-
Tag.prototype.
|
2213
|
-
|
2214
|
-
|
2215
|
-
|
2582
|
+
Tag.prototype.canInline = function(){
|
2583
|
+
var nodes = this.block.nodes;
|
2584
|
+
|
2585
|
+
function isInline(node){
|
2586
|
+
// Recurse if the node is a block
|
2587
|
+
if (node.isBlock) return node.nodes.every(isInline);
|
2588
|
+
return node.isText || (node.isInline && node.isInline());
|
2589
|
+
}
|
2590
|
+
|
2591
|
+
// Empty tag
|
2592
|
+
if (!nodes.length) return true;
|
2593
|
+
|
2594
|
+
// Text-only or inline-only tag
|
2595
|
+
if (1 == nodes.length) return isInline(nodes[0]);
|
2596
|
+
|
2597
|
+
// Multi-line inline-only tag
|
2598
|
+
if (this.block.nodes.every(isInline)) {
|
2599
|
+
for (var i = 1, len = nodes.length; i < len; ++i) {
|
2600
|
+
if (nodes[i-1].isText && nodes[i].isText)
|
2601
|
+
return false;
|
2216
2602
|
}
|
2603
|
+
return true;
|
2217
2604
|
}
|
2605
|
+
|
2606
|
+
// Mixed tag
|
2607
|
+
return false;
|
2218
2608
|
};
|
2219
|
-
|
2220
2609
|
}); // module: nodes/tag.js
|
2221
2610
|
|
2222
2611
|
require.register("nodes/text.js", function(module, exports, require){
|
@@ -2241,8 +2630,8 @@ var Node = require('./node');
|
|
2241
2630
|
*/
|
2242
2631
|
|
2243
2632
|
var Text = module.exports = function Text(line) {
|
2244
|
-
this.
|
2245
|
-
if ('string' == typeof line) this.
|
2633
|
+
this.val = '';
|
2634
|
+
if ('string' == typeof line) this.val = line;
|
2246
2635
|
};
|
2247
2636
|
|
2248
2637
|
/**
|
@@ -2254,17 +2643,10 @@ Text.prototype.constructor = Text;
|
|
2254
2643
|
|
2255
2644
|
|
2256
2645
|
/**
|
2257
|
-
*
|
2258
|
-
*
|
2259
|
-
* @param {Node} node
|
2260
|
-
* @return {Number}
|
2261
|
-
* @api public
|
2646
|
+
* Flag as text.
|
2262
2647
|
*/
|
2263
2648
|
|
2264
|
-
Text.prototype.
|
2265
|
-
return this.nodes.push(node);
|
2266
|
-
};
|
2267
|
-
|
2649
|
+
Text.prototype.isText = true;
|
2268
2650
|
}); // module: nodes/text.js
|
2269
2651
|
|
2270
2652
|
require.register("parser.js", function(module, exports, require){
|
@@ -2280,7 +2662,8 @@ require.register("parser.js", function(module, exports, require){
|
|
2280
2662
|
*/
|
2281
2663
|
|
2282
2664
|
var Lexer = require('./lexer')
|
2283
|
-
, nodes = require('./nodes')
|
2665
|
+
, nodes = require('./nodes')
|
2666
|
+
, utils = require('./utils');
|
2284
2667
|
|
2285
2668
|
/**
|
2286
2669
|
* Initialize `Parser` with the given input `str` and `filename`.
|
@@ -2296,6 +2679,7 @@ var Parser = exports = module.exports = function Parser(str, filename, options){
|
|
2296
2679
|
this.lexer = new Lexer(str, options);
|
2297
2680
|
this.filename = filename;
|
2298
2681
|
this.blocks = {};
|
2682
|
+
this.mixins = {};
|
2299
2683
|
this.options = options;
|
2300
2684
|
this.contexts = [this];
|
2301
2685
|
};
|
@@ -2404,6 +2788,9 @@ Parser.prototype = {
|
|
2404
2788
|
this.context(parser);
|
2405
2789
|
var ast = parser.parse();
|
2406
2790
|
this.context();
|
2791
|
+
// hoist mixins
|
2792
|
+
for (var name in this.mixins)
|
2793
|
+
ast.unshift(this.mixins[name]);
|
2407
2794
|
return ast;
|
2408
2795
|
}
|
2409
2796
|
|
@@ -2448,8 +2835,10 @@ Parser.prototype = {
|
|
2448
2835
|
* | text
|
2449
2836
|
* | each
|
2450
2837
|
* | code
|
2838
|
+
* | yield
|
2451
2839
|
* | id
|
2452
2840
|
* | class
|
2841
|
+
* | interpolation
|
2453
2842
|
*/
|
2454
2843
|
|
2455
2844
|
parseExpr: function(){
|
@@ -2482,6 +2871,15 @@ Parser.prototype = {
|
|
2482
2871
|
return this.parseEach();
|
2483
2872
|
case 'code':
|
2484
2873
|
return this.parseCode();
|
2874
|
+
case 'call':
|
2875
|
+
return this.parseCall();
|
2876
|
+
case 'interpolation':
|
2877
|
+
return this.parseInterpolation();
|
2878
|
+
case 'yield':
|
2879
|
+
this.advance();
|
2880
|
+
var block = new nodes.Block;
|
2881
|
+
block.yield = true;
|
2882
|
+
return block;
|
2485
2883
|
case 'id':
|
2486
2884
|
case 'class':
|
2487
2885
|
var tok = this.advance();
|
@@ -2640,6 +3038,10 @@ Parser.prototype = {
|
|
2640
3038
|
, node = new nodes.Each(tok.code, tok.val, tok.key);
|
2641
3039
|
node.line = this.line();
|
2642
3040
|
node.block = this.block();
|
3041
|
+
if (this.peek().type == 'code' && this.peek().val == 'else') {
|
3042
|
+
this.advance();
|
3043
|
+
node.alternative = this.block();
|
3044
|
+
}
|
2643
3045
|
return node;
|
2644
3046
|
},
|
2645
3047
|
|
@@ -2657,7 +3059,7 @@ Parser.prototype = {
|
|
2657
3059
|
if (!this.filename)
|
2658
3060
|
throw new Error('the "filename" option is required to extend templates');
|
2659
3061
|
|
2660
|
-
var path =
|
3062
|
+
var path = this.expect('extends').val.trim()
|
2661
3063
|
, dir = dirname(this.filename);
|
2662
3064
|
|
2663
3065
|
var path = join(dir, path + '.jade')
|
@@ -2715,7 +3117,7 @@ Parser.prototype = {
|
|
2715
3117
|
, basename = path.basename
|
2716
3118
|
, join = path.join;
|
2717
3119
|
|
2718
|
-
var path =
|
3120
|
+
var path = this.expect('include').val.trim()
|
2719
3121
|
, dir = dirname(this.filename);
|
2720
3122
|
|
2721
3123
|
if (!this.filename)
|
@@ -2736,6 +3138,8 @@ Parser.prototype = {
|
|
2736
3138
|
var path = join(dir, path)
|
2737
3139
|
, str = fs.readFileSync(path, 'utf8')
|
2738
3140
|
, parser = new Parser(str, path, this.options);
|
3141
|
+
parser.blocks = utils.merge({}, this.blocks);
|
3142
|
+
parser.mixins = this.mixins;
|
2739
3143
|
|
2740
3144
|
this.context(parser);
|
2741
3145
|
var ast = parser.parse();
|
@@ -2743,12 +3147,27 @@ Parser.prototype = {
|
|
2743
3147
|
ast.filename = path;
|
2744
3148
|
|
2745
3149
|
if ('indent' == this.peek().type) {
|
2746
|
-
ast.
|
3150
|
+
ast.includeBlock().push(this.block());
|
2747
3151
|
}
|
2748
3152
|
|
2749
3153
|
return ast;
|
2750
3154
|
},
|
2751
3155
|
|
3156
|
+
/**
|
3157
|
+
* call ident block
|
3158
|
+
*/
|
3159
|
+
|
3160
|
+
parseCall: function(){
|
3161
|
+
var tok = this.expect('call')
|
3162
|
+
, name = tok.val
|
3163
|
+
, args = tok.args
|
3164
|
+
, mixin = new nodes.Mixin(name, args, new nodes.Block, true);
|
3165
|
+
|
3166
|
+
this.tag(mixin);
|
3167
|
+
if (mixin.block.isEmpty()) mixin.block = null;
|
3168
|
+
return mixin;
|
3169
|
+
},
|
3170
|
+
|
2752
3171
|
/**
|
2753
3172
|
* mixin block
|
2754
3173
|
*/
|
@@ -2756,11 +3175,18 @@ Parser.prototype = {
|
|
2756
3175
|
parseMixin: function(){
|
2757
3176
|
var tok = this.expect('mixin')
|
2758
3177
|
, name = tok.val
|
2759
|
-
, args = tok.args
|
2760
|
-
|
2761
|
-
|
2762
|
-
|
2763
|
-
|
3178
|
+
, args = tok.args
|
3179
|
+
, mixin;
|
3180
|
+
|
3181
|
+
// definition
|
3182
|
+
if ('indent' == this.peek().type) {
|
3183
|
+
mixin = new nodes.Mixin(name, args, this.block(), false);
|
3184
|
+
this.mixins[name] = mixin;
|
3185
|
+
return mixin;
|
3186
|
+
// call
|
3187
|
+
} else {
|
3188
|
+
return new nodes.Mixin(name, args, null, true);
|
3189
|
+
}
|
2764
3190
|
},
|
2765
3191
|
|
2766
3192
|
/**
|
@@ -2768,32 +3194,31 @@ Parser.prototype = {
|
|
2768
3194
|
*/
|
2769
3195
|
|
2770
3196
|
parseTextBlock: function(){
|
2771
|
-
var
|
2772
|
-
|
3197
|
+
var block = new nodes.Block;
|
3198
|
+
block.line = this.line();
|
2773
3199
|
var spaces = this.expect('indent').val;
|
2774
3200
|
if (null == this._spaces) this._spaces = spaces;
|
2775
3201
|
var indent = Array(spaces - this._spaces + 1).join(' ');
|
2776
3202
|
while ('outdent' != this.peek().type) {
|
2777
3203
|
switch (this.peek().type) {
|
2778
3204
|
case 'newline':
|
2779
|
-
text.push('\\n');
|
2780
3205
|
this.advance();
|
2781
3206
|
break;
|
2782
3207
|
case 'indent':
|
2783
|
-
text.push('\\n');
|
2784
3208
|
this.parseTextBlock().nodes.forEach(function(node){
|
2785
|
-
|
3209
|
+
block.push(node);
|
2786
3210
|
});
|
2787
|
-
text.push('\\n');
|
2788
3211
|
break;
|
2789
3212
|
default:
|
2790
|
-
text.
|
3213
|
+
var text = new nodes.Text(indent + this.advance().val);
|
3214
|
+
text.line = this.line();
|
3215
|
+
block.push(text);
|
2791
3216
|
}
|
2792
3217
|
}
|
2793
3218
|
|
2794
3219
|
if (spaces == this._spaces) this._spaces = null;
|
2795
3220
|
this.expect('outdent');
|
2796
|
-
return
|
3221
|
+
return block;
|
2797
3222
|
},
|
2798
3223
|
|
2799
3224
|
/**
|
@@ -2815,6 +3240,17 @@ Parser.prototype = {
|
|
2815
3240
|
return block;
|
2816
3241
|
},
|
2817
3242
|
|
3243
|
+
/**
|
3244
|
+
* interpolation (attrs | class | id)* (text | code | ':')? newline* block?
|
3245
|
+
*/
|
3246
|
+
|
3247
|
+
parseInterpolation: function(){
|
3248
|
+
var tok = this.advance();
|
3249
|
+
var tag = new nodes.Tag(tok.val);
|
3250
|
+
tag.buffer = true;
|
3251
|
+
return this.tag(tag);
|
3252
|
+
},
|
3253
|
+
|
2818
3254
|
/**
|
2819
3255
|
* tag (attrs | class | id)* (text | code | ':')? newline* block?
|
2820
3256
|
*/
|
@@ -2829,9 +3265,20 @@ Parser.prototype = {
|
|
2829
3265
|
}
|
2830
3266
|
}
|
2831
3267
|
|
2832
|
-
var
|
2833
|
-
, tag = new nodes.Tag(
|
2834
|
-
|
3268
|
+
var tok = this.advance()
|
3269
|
+
, tag = new nodes.Tag(tok.val);
|
3270
|
+
|
3271
|
+
tag.selfClosing = tok.selfClosing;
|
3272
|
+
|
3273
|
+
return this.tag(tag);
|
3274
|
+
},
|
3275
|
+
|
3276
|
+
/**
|
3277
|
+
* Parse tag.
|
3278
|
+
*/
|
3279
|
+
|
3280
|
+
tag: function(tag){
|
3281
|
+
var dot;
|
2835
3282
|
|
2836
3283
|
tag.line = this.line();
|
2837
3284
|
|
@@ -2845,12 +3292,17 @@ Parser.prototype = {
|
|
2845
3292
|
tag.setAttribute(tok.type, "'" + tok.val + "'");
|
2846
3293
|
continue;
|
2847
3294
|
case 'attrs':
|
2848
|
-
var
|
3295
|
+
var tok = this.advance()
|
3296
|
+
, obj = tok.attrs
|
3297
|
+
, escaped = tok.escaped
|
2849
3298
|
, names = Object.keys(obj);
|
3299
|
+
|
3300
|
+
if (tok.selfClosing) tag.selfClosing = true;
|
3301
|
+
|
2850
3302
|
for (var i = 0, len = names.length; i < len; ++i) {
|
2851
3303
|
var name = names[i]
|
2852
3304
|
, val = obj[name];
|
2853
|
-
tag.setAttribute(name, val);
|
3305
|
+
tag.setAttribute(name, val, escaped[name]);
|
2854
3306
|
}
|
2855
3307
|
continue;
|
2856
3308
|
default:
|
@@ -2867,7 +3319,7 @@ Parser.prototype = {
|
|
2867
3319
|
// (text | code | ':')?
|
2868
3320
|
switch (this.peek().type) {
|
2869
3321
|
case 'text':
|
2870
|
-
tag.
|
3322
|
+
tag.block.push(this.parseText());
|
2871
3323
|
break;
|
2872
3324
|
case 'code':
|
2873
3325
|
tag.code = this.parseCode();
|
@@ -2875,7 +3327,7 @@ Parser.prototype = {
|
|
2875
3327
|
case ':':
|
2876
3328
|
this.advance();
|
2877
3329
|
tag.block = new nodes.Block;
|
2878
|
-
tag.block.push(this.
|
3330
|
+
tag.block.push(this.parseExpr());
|
2879
3331
|
break;
|
2880
3332
|
}
|
2881
3333
|
|
@@ -2947,41 +3399,97 @@ if (!Object.keys) {
|
|
2947
3399
|
}
|
2948
3400
|
}
|
2949
3401
|
return arr;
|
2950
|
-
}
|
3402
|
+
}
|
3403
|
+
}
|
3404
|
+
|
3405
|
+
/**
|
3406
|
+
* Merge two attribute objects giving precedence
|
3407
|
+
* to values in object `b`. Classes are special-cased
|
3408
|
+
* allowing for arrays and merging/joining appropriately
|
3409
|
+
* resulting in a string.
|
3410
|
+
*
|
3411
|
+
* @param {Object} a
|
3412
|
+
* @param {Object} b
|
3413
|
+
* @return {Object} a
|
3414
|
+
* @api private
|
3415
|
+
*/
|
3416
|
+
|
3417
|
+
exports.merge = function merge(a, b) {
|
3418
|
+
var ac = a['class'];
|
3419
|
+
var bc = b['class'];
|
3420
|
+
|
3421
|
+
if (ac || bc) {
|
3422
|
+
ac = ac || [];
|
3423
|
+
bc = bc || [];
|
3424
|
+
if (!Array.isArray(ac)) ac = [ac];
|
3425
|
+
if (!Array.isArray(bc)) bc = [bc];
|
3426
|
+
ac = ac.filter(nulls);
|
3427
|
+
bc = bc.filter(nulls);
|
3428
|
+
a['class'] = ac.concat(bc).join(' ');
|
3429
|
+
}
|
3430
|
+
|
3431
|
+
for (var key in b) {
|
3432
|
+
if (key != 'class') {
|
3433
|
+
a[key] = b[key];
|
3434
|
+
}
|
3435
|
+
}
|
3436
|
+
|
3437
|
+
return a;
|
3438
|
+
};
|
3439
|
+
|
3440
|
+
/**
|
3441
|
+
* Filter null `val`s.
|
3442
|
+
*
|
3443
|
+
* @param {Mixed} val
|
3444
|
+
* @return {Mixed}
|
3445
|
+
* @api private
|
3446
|
+
*/
|
3447
|
+
|
3448
|
+
function nulls(val) {
|
3449
|
+
return val != null;
|
2951
3450
|
}
|
2952
3451
|
|
2953
3452
|
/**
|
2954
3453
|
* Render the given attributes object.
|
2955
3454
|
*
|
2956
3455
|
* @param {Object} obj
|
3456
|
+
* @param {Object} escaped
|
2957
3457
|
* @return {String}
|
2958
3458
|
* @api private
|
2959
3459
|
*/
|
2960
3460
|
|
2961
|
-
exports.attrs = function attrs(obj){
|
3461
|
+
exports.attrs = function attrs(obj, escaped){
|
2962
3462
|
var buf = []
|
2963
3463
|
, terse = obj.terse;
|
3464
|
+
|
2964
3465
|
delete obj.terse;
|
2965
3466
|
var keys = Object.keys(obj)
|
2966
3467
|
, len = keys.length;
|
3468
|
+
|
2967
3469
|
if (len) {
|
2968
3470
|
buf.push('');
|
2969
3471
|
for (var i = 0; i < len; ++i) {
|
2970
3472
|
var key = keys[i]
|
2971
3473
|
, val = obj[key];
|
3474
|
+
|
2972
3475
|
if ('boolean' == typeof val || null == val) {
|
2973
3476
|
if (val) {
|
2974
3477
|
terse
|
2975
3478
|
? buf.push(key)
|
2976
3479
|
: buf.push(key + '="' + key + '"');
|
2977
3480
|
}
|
3481
|
+
} else if (0 == key.indexOf('data') && 'string' != typeof val) {
|
3482
|
+
buf.push(key + "='" + JSON.stringify(val) + "'");
|
2978
3483
|
} else if ('class' == key && Array.isArray(val)) {
|
2979
3484
|
buf.push(key + '="' + exports.escape(val.join(' ')) + '"');
|
2980
|
-
} else {
|
3485
|
+
} else if (escaped && escaped[key]) {
|
2981
3486
|
buf.push(key + '="' + exports.escape(val) + '"');
|
3487
|
+
} else {
|
3488
|
+
buf.push(key + '="' + val + '"');
|
2982
3489
|
}
|
2983
3490
|
}
|
2984
3491
|
}
|
3492
|
+
|
2985
3493
|
return buf.join(' ');
|
2986
3494
|
};
|
2987
3495
|
|
@@ -2995,7 +3503,7 @@ exports.attrs = function attrs(obj){
|
|
2995
3503
|
|
2996
3504
|
exports.escape = function escape(html){
|
2997
3505
|
return String(html)
|
2998
|
-
.replace(/&(
|
3506
|
+
.replace(/&(?!(\w+|\#\d+);)/g, '&')
|
2999
3507
|
.replace(/</g, '<')
|
3000
3508
|
.replace(/>/g, '>')
|
3001
3509
|
.replace(/"/g, '"');
|
@@ -3018,7 +3526,7 @@ exports.rethrow = function rethrow(err, filename, lineno){
|
|
3018
3526
|
, str = require('fs').readFileSync(filename, 'utf8')
|
3019
3527
|
, lines = str.split('\n')
|
3020
3528
|
, start = Math.max(lineno - context, 0)
|
3021
|
-
, end = Math.min(lines.length, lineno + context);
|
3529
|
+
, end = Math.min(lines.length, lineno + context);
|
3022
3530
|
|
3023
3531
|
// Error context
|
3024
3532
|
var context = lines.slice(start, end).map(function(line, i){
|
@@ -3031,7 +3539,7 @@ exports.rethrow = function rethrow(err, filename, lineno){
|
|
3031
3539
|
|
3032
3540
|
// Alter exception message
|
3033
3541
|
err.path = filename;
|
3034
|
-
err.message = (filename || 'Jade') + ':' + lineno
|
3542
|
+
err.message = (filename || 'Jade') + ':' + lineno
|
3035
3543
|
+ '\n' + context + '\n\n' + err.message;
|
3036
3544
|
throw err;
|
3037
3545
|
};
|
@@ -3051,6 +3559,7 @@ module.exports = [
|
|
3051
3559
|
, 'img'
|
3052
3560
|
, 'link'
|
3053
3561
|
, 'input'
|
3562
|
+
, 'source'
|
3054
3563
|
, 'area'
|
3055
3564
|
, 'base'
|
3056
3565
|
, 'col'
|
@@ -3078,7 +3587,7 @@ require.register("utils.js", function(module, exports, require){
|
|
3078
3587
|
var interpolate = exports.interpolate = function(str){
|
3079
3588
|
return str.replace(/(\\)?([#!]){(.*?)}/g, function(str, escape, flag, code){
|
3080
3589
|
return escape
|
3081
|
-
? str
|
3590
|
+
? str.slice(1)
|
3082
3591
|
: "' + "
|
3083
3592
|
+ ('!' == flag ? '' : 'escape')
|
3084
3593
|
+ "((interp = " + code.replace(/\\'/g, "'")
|
@@ -3109,4 +3618,23 @@ var escape = exports.escape = function(str) {
|
|
3109
3618
|
exports.text = function(str){
|
3110
3619
|
return interpolate(escape(str));
|
3111
3620
|
};
|
3621
|
+
|
3622
|
+
/**
|
3623
|
+
* Merge `b` into `a`.
|
3624
|
+
*
|
3625
|
+
* @param {Object} a
|
3626
|
+
* @param {Object} b
|
3627
|
+
* @return {Object}
|
3628
|
+
* @api public
|
3629
|
+
*/
|
3630
|
+
|
3631
|
+
exports.merge = function(a, b) {
|
3632
|
+
for (var key in b) a[key] = b[key];
|
3633
|
+
return a;
|
3634
|
+
};
|
3635
|
+
|
3636
|
+
|
3112
3637
|
}); // module: utils.js
|
3638
|
+
|
3639
|
+
window.jade = require("jade");
|
3640
|
+
})();
|