jade-js-source 0.19.0 → 0.27.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
})();
|