rails-hamljs 0.0.1
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/LICENSE +23 -0
- data/README.md +50 -0
- data/lib/rails-hamljs.rb +109 -0
- data/lib/rails-hamljs/engine.rb +4 -0
- data/lib/rails-hamljs/version.rb +3 -0
- data/vendor/assets/javascripts/creationix-haml-js/haml.js +703 -0
- data/vendor/assets/javascripts/uglyog-haml-js/ext/coffee-script.js +8 -0
- data/vendor/assets/javascripts/uglyog-haml-js/ext/jquery-1.7.1.js +9266 -0
- data/vendor/assets/javascripts/uglyog-haml-js/ext/json2.js +480 -0
- data/vendor/assets/javascripts/uglyog-haml-js/ext/underscore.js +807 -0
- data/vendor/assets/javascripts/uglyog-haml-js/ext/underscore.string.js +331 -0
- data/vendor/assets/javascripts/uglyog-haml-js/haml.js +2058 -0
- data/vendor/assets/javascripts/uglyog-haml-js/haml.min.js +8 -0
- metadata +140 -0
@@ -0,0 +1,331 @@
|
|
1
|
+
// Underscore.string
|
2
|
+
// (c) 2010 Esa-Matti Suuronen <esa-matti aet suuronen dot org>
|
3
|
+
// Underscore.strings is freely distributable under the terms of the MIT license.
|
4
|
+
// Documentation: https://github.com/edtsech/underscore.string
|
5
|
+
// Some code is borrowed from MooTools and Alexandru Marasteanu.
|
6
|
+
|
7
|
+
// Version 1.1.4
|
8
|
+
|
9
|
+
(function(){
|
10
|
+
// ------------------------- Baseline setup ---------------------------------
|
11
|
+
|
12
|
+
// Establish the root object, "window" in the browser, or "global" on the server.
|
13
|
+
var root = this;
|
14
|
+
|
15
|
+
var nativeTrim = String.prototype.trim;
|
16
|
+
|
17
|
+
var parseNumber = function(source) { return source * 1 || 0; };
|
18
|
+
|
19
|
+
function str_repeat(i, m) {
|
20
|
+
for (var o = []; m > 0; o[--m] = i);
|
21
|
+
return o.join('');
|
22
|
+
}
|
23
|
+
|
24
|
+
function defaultToWhiteSpace(characters){
|
25
|
+
if (characters) {
|
26
|
+
return _s.escapeRegExp(characters);
|
27
|
+
}
|
28
|
+
return '\\s';
|
29
|
+
}
|
30
|
+
|
31
|
+
var _s = {
|
32
|
+
|
33
|
+
isBlank: function(str){
|
34
|
+
return !!str.match(/^\s*$/);
|
35
|
+
},
|
36
|
+
|
37
|
+
capitalize : function(str) {
|
38
|
+
return str.charAt(0).toUpperCase() + str.substring(1).toLowerCase();
|
39
|
+
},
|
40
|
+
|
41
|
+
chop: function(str, step){
|
42
|
+
step = step || str.length;
|
43
|
+
var arr = [];
|
44
|
+
for (var i = 0; i < str.length;) {
|
45
|
+
arr.push(str.slice(i,i + step));
|
46
|
+
i = i + step;
|
47
|
+
}
|
48
|
+
return arr;
|
49
|
+
},
|
50
|
+
|
51
|
+
clean: function(str){
|
52
|
+
return _s.strip(str.replace(/\s+/g, ' '));
|
53
|
+
},
|
54
|
+
|
55
|
+
count: function(str, substr){
|
56
|
+
var count = 0, index;
|
57
|
+
for (var i=0; i < str.length;) {
|
58
|
+
index = str.indexOf(substr, i);
|
59
|
+
index >= 0 && count++;
|
60
|
+
i = i + (index >= 0 ? index : 0) + substr.length;
|
61
|
+
}
|
62
|
+
return count;
|
63
|
+
},
|
64
|
+
|
65
|
+
chars: function(str) {
|
66
|
+
return str.split('');
|
67
|
+
},
|
68
|
+
|
69
|
+
escapeHTML: function(str) {
|
70
|
+
return String(str||'').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')
|
71
|
+
.replace(/"/g, '"').replace(/'/g, "'");
|
72
|
+
},
|
73
|
+
|
74
|
+
unescapeHTML: function(str) {
|
75
|
+
return String(str||'').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
76
|
+
.replace(/"/g, '"').replace(/'/g, "'");
|
77
|
+
},
|
78
|
+
|
79
|
+
escapeRegExp: function(str){
|
80
|
+
// From MooTools core 1.2.4
|
81
|
+
return String(str||'').replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
|
82
|
+
},
|
83
|
+
|
84
|
+
insert: function(str, i, substr){
|
85
|
+
var arr = str.split('');
|
86
|
+
arr.splice(i, 0, substr);
|
87
|
+
return arr.join('');
|
88
|
+
},
|
89
|
+
|
90
|
+
includes: function(str, needle){
|
91
|
+
return str.indexOf(needle) !== -1;
|
92
|
+
},
|
93
|
+
|
94
|
+
join: function(sep) {
|
95
|
+
// TODO: Could this be faster by converting
|
96
|
+
// arguments to Array and using array.join(sep)?
|
97
|
+
sep = String(sep);
|
98
|
+
var str = "";
|
99
|
+
for (var i=1; i < arguments.length; i += 1) {
|
100
|
+
str += String(arguments[i]);
|
101
|
+
if ( i !== arguments.length-1 ) {
|
102
|
+
str += sep;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
return str;
|
106
|
+
},
|
107
|
+
|
108
|
+
lines: function(str) {
|
109
|
+
return str.split("\n");
|
110
|
+
},
|
111
|
+
|
112
|
+
// reverse: function(str){
|
113
|
+
// return Array.prototype.reverse.apply(str.split('')).join('');
|
114
|
+
// },
|
115
|
+
|
116
|
+
splice: function(str, i, howmany, substr){
|
117
|
+
var arr = str.split('');
|
118
|
+
arr.splice(i, howmany, substr);
|
119
|
+
return arr.join('');
|
120
|
+
},
|
121
|
+
|
122
|
+
startsWith: function(str, starts){
|
123
|
+
return str.length >= starts.length && str.substring(0, starts.length) === starts;
|
124
|
+
},
|
125
|
+
|
126
|
+
endsWith: function(str, ends){
|
127
|
+
return str.length >= ends.length && str.substring(str.length - ends.length) === ends;
|
128
|
+
},
|
129
|
+
|
130
|
+
succ: function(str){
|
131
|
+
var arr = str.split('');
|
132
|
+
arr.splice(str.length-1, 1, String.fromCharCode(str.charCodeAt(str.length-1) + 1));
|
133
|
+
return arr.join('');
|
134
|
+
},
|
135
|
+
|
136
|
+
titleize: function(str){
|
137
|
+
var arr = str.split(' '),
|
138
|
+
word;
|
139
|
+
for (var i=0; i < arr.length; i++) {
|
140
|
+
word = arr[i].split('');
|
141
|
+
if(typeof word[0] !== 'undefined') word[0] = word[0].toUpperCase();
|
142
|
+
i+1 === arr.length ? arr[i] = word.join('') : arr[i] = word.join('') + ' ';
|
143
|
+
}
|
144
|
+
return arr.join('');
|
145
|
+
},
|
146
|
+
|
147
|
+
camelize: function(str){
|
148
|
+
return _s.trim(str).replace(/(\-|_|\s)+(.)?/g, function(match, separator, chr) {
|
149
|
+
return chr ? chr.toUpperCase() : '';
|
150
|
+
});
|
151
|
+
},
|
152
|
+
|
153
|
+
underscored: function(str){
|
154
|
+
return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/\-|\s+/g, '_').toLowerCase();
|
155
|
+
},
|
156
|
+
|
157
|
+
dasherize: function(str){
|
158
|
+
return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1-$2').replace(/^([A-Z]+)/, '-$1').replace(/\_|\s+/g, '-').toLowerCase();
|
159
|
+
},
|
160
|
+
|
161
|
+
trim: function(str, characters){
|
162
|
+
if (!characters && nativeTrim) {
|
163
|
+
return nativeTrim.call(str);
|
164
|
+
}
|
165
|
+
characters = defaultToWhiteSpace(characters);
|
166
|
+
return str.replace(new RegExp('\^[' + characters + ']+|[' + characters + ']+$', 'g'), '');
|
167
|
+
},
|
168
|
+
|
169
|
+
ltrim: function(str, characters){
|
170
|
+
characters = defaultToWhiteSpace(characters);
|
171
|
+
return str.replace(new RegExp('\^[' + characters + ']+', 'g'), '');
|
172
|
+
},
|
173
|
+
|
174
|
+
rtrim: function(str, characters){
|
175
|
+
characters = defaultToWhiteSpace(characters);
|
176
|
+
return str.replace(new RegExp('[' + characters + ']+$', 'g'), '');
|
177
|
+
},
|
178
|
+
|
179
|
+
truncate: function(str, length, truncateStr){
|
180
|
+
truncateStr = truncateStr || '...';
|
181
|
+
return str.slice(0,length) + truncateStr;
|
182
|
+
},
|
183
|
+
|
184
|
+
words: function(str, delimiter) {
|
185
|
+
delimiter = delimiter || " ";
|
186
|
+
return str.split(delimiter);
|
187
|
+
},
|
188
|
+
|
189
|
+
|
190
|
+
pad: function(str, length, padStr, type) {
|
191
|
+
|
192
|
+
var padding = '';
|
193
|
+
var padlen = 0;
|
194
|
+
|
195
|
+
if (!padStr) { padStr = ' '; }
|
196
|
+
else if (padStr.length > 1) { padStr = padStr[0]; }
|
197
|
+
switch(type) {
|
198
|
+
case "right":
|
199
|
+
padlen = (length - str.length);
|
200
|
+
padding = str_repeat(padStr, padlen);
|
201
|
+
str = str+padding;
|
202
|
+
break;
|
203
|
+
case "both":
|
204
|
+
padlen = (length - str.length);
|
205
|
+
padding = {
|
206
|
+
'left' : str_repeat(padStr, Math.ceil(padlen/2)),
|
207
|
+
'right': str_repeat(padStr, Math.floor(padlen/2))
|
208
|
+
};
|
209
|
+
str = padding.left+str+padding.right;
|
210
|
+
break;
|
211
|
+
default: // "left"
|
212
|
+
padlen = (length - str.length);
|
213
|
+
padding = str_repeat(padStr, padlen);;
|
214
|
+
str = padding+str;
|
215
|
+
}
|
216
|
+
return str;
|
217
|
+
},
|
218
|
+
|
219
|
+
lpad: function(str, length, padStr) {
|
220
|
+
return _s.pad(str, length, padStr);
|
221
|
+
},
|
222
|
+
|
223
|
+
rpad: function(str, length, padStr) {
|
224
|
+
return _s.pad(str, length, padStr, 'right');
|
225
|
+
},
|
226
|
+
|
227
|
+
lrpad: function(str, length, padStr) {
|
228
|
+
return _s.pad(str, length, padStr, 'both');
|
229
|
+
},
|
230
|
+
|
231
|
+
|
232
|
+
/**
|
233
|
+
* Credits for this function goes to
|
234
|
+
* http://www.diveintojavascript.com/projects/sprintf-for-javascript
|
235
|
+
*
|
236
|
+
* Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
|
237
|
+
* All rights reserved.
|
238
|
+
* */
|
239
|
+
sprintf: function(){
|
240
|
+
|
241
|
+
var i = 0, a, f = arguments[i++], o = [], m, p, c, x, s = '';
|
242
|
+
while (f) {
|
243
|
+
if (m = /^[^\x25]+/.exec(f)) {
|
244
|
+
o.push(m[0]);
|
245
|
+
}
|
246
|
+
else if (m = /^\x25{2}/.exec(f)) {
|
247
|
+
o.push('%');
|
248
|
+
}
|
249
|
+
else if (m = /^\x25(?:(\d+)\$)?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(f)) {
|
250
|
+
if (((a = arguments[m[1] || i++]) == null) || (a == undefined)) {
|
251
|
+
throw('Too few arguments.');
|
252
|
+
}
|
253
|
+
if (/[^s]/.test(m[7]) && (typeof(a) != 'number')) {
|
254
|
+
throw('Expecting number but found ' + typeof(a));
|
255
|
+
}
|
256
|
+
switch (m[7]) {
|
257
|
+
case 'b': a = a.toString(2); break;
|
258
|
+
case 'c': a = String.fromCharCode(a); break;
|
259
|
+
case 'd': a = parseInt(a); break;
|
260
|
+
case 'e': a = m[6] ? a.toExponential(m[6]) : a.toExponential(); break;
|
261
|
+
case 'f': a = m[6] ? parseFloat(a).toFixed(m[6]) : parseFloat(a); break;
|
262
|
+
case 'o': a = a.toString(8); break;
|
263
|
+
case 's': a = ((a = String(a)) && m[6] ? a.substring(0, m[6]) : a); break;
|
264
|
+
case 'u': a = Math.abs(a); break;
|
265
|
+
case 'x': a = a.toString(16); break;
|
266
|
+
case 'X': a = a.toString(16).toUpperCase(); break;
|
267
|
+
}
|
268
|
+
a = (/[def]/.test(m[7]) && m[2] && a >= 0 ? '+'+ a : a);
|
269
|
+
c = m[3] ? m[3] == '0' ? '0' : m[3].charAt(1) : ' ';
|
270
|
+
x = m[5] - String(a).length - s.length;
|
271
|
+
p = m[5] ? str_repeat(c, x) : '';
|
272
|
+
o.push(s + (m[4] ? a + p : p + a));
|
273
|
+
}
|
274
|
+
else {
|
275
|
+
throw('Huh ?!');
|
276
|
+
}
|
277
|
+
f = f.substring(m[0].length);
|
278
|
+
}
|
279
|
+
return o.join('');
|
280
|
+
},
|
281
|
+
|
282
|
+
toNumber: function(str, decimals) {
|
283
|
+
return parseNumber(parseNumber(str).toFixed(parseNumber(decimals)));
|
284
|
+
},
|
285
|
+
|
286
|
+
strRight: function(sourceStr, sep){
|
287
|
+
var pos = (!sep) ? -1 : sourceStr.indexOf(sep);
|
288
|
+
return (pos != -1) ? sourceStr.slice(pos+sep.length, sourceStr.length) : sourceStr;
|
289
|
+
},
|
290
|
+
|
291
|
+
strRightBack: function(sourceStr, sep){
|
292
|
+
var pos = (!sep) ? -1 : sourceStr.lastIndexOf(sep);
|
293
|
+
return (pos != -1) ? sourceStr.slice(pos+sep.length, sourceStr.length) : sourceStr;
|
294
|
+
},
|
295
|
+
|
296
|
+
strLeft: function(sourceStr, sep){
|
297
|
+
var pos = (!sep) ? -1 : sourceStr.indexOf(sep);
|
298
|
+
return (pos != -1) ? sourceStr.slice(0, pos) : sourceStr;
|
299
|
+
},
|
300
|
+
|
301
|
+
strLeftBack: function(sourceStr, sep){
|
302
|
+
var pos = sourceStr.lastIndexOf(sep);
|
303
|
+
return (pos != -1) ? sourceStr.slice(0, pos) : sourceStr;
|
304
|
+
}
|
305
|
+
|
306
|
+
};
|
307
|
+
|
308
|
+
// Aliases
|
309
|
+
|
310
|
+
_s.strip = _s.trim;
|
311
|
+
_s.lstrip = _s.ltrim;
|
312
|
+
_s.rstrip = _s.rtrim;
|
313
|
+
_s.center = _s.lrpad;
|
314
|
+
_s.ljust = _s.lpad;
|
315
|
+
_s.rjust = _s.rpad;
|
316
|
+
|
317
|
+
// CommonJS module is defined
|
318
|
+
if (typeof window === 'undefined' && typeof module !== 'undefined') {
|
319
|
+
// Export module
|
320
|
+
module.exports = _s;
|
321
|
+
|
322
|
+
// Integrate with Underscore.js
|
323
|
+
} else if (typeof root._ !== 'undefined') {
|
324
|
+
root._.mixin(_s);
|
325
|
+
|
326
|
+
// Or define it
|
327
|
+
} else {
|
328
|
+
root._ = _s;
|
329
|
+
}
|
330
|
+
|
331
|
+
}());
|
@@ -0,0 +1,2058 @@
|
|
1
|
+
// Generated by CoffeeScript 1.3.3
|
2
|
+
|
3
|
+
/*
|
4
|
+
clientside HAML compiler for Javascript and Coffeescript (Version 5)
|
5
|
+
|
6
|
+
Copyright 2011-12, Ronald Holshausen (https://github.com/uglyog)
|
7
|
+
Released under the MIT License (http://www.opensource.org/licenses/MIT)
|
8
|
+
*/
|
9
|
+
|
10
|
+
|
11
|
+
(function() {
|
12
|
+
var Buffer, CodeGenerator, CoffeeCodeGenerator, HamlRuntime, JsCodeGenerator, ProductionJsCodeGenerator, Tokeniser, filters, root,
|
13
|
+
__hasProp = {}.hasOwnProperty,
|
14
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
15
|
+
|
16
|
+
root = this;
|
17
|
+
|
18
|
+
/*
|
19
|
+
Haml runtime functions. These are used both by the compiler and the generated template functions
|
20
|
+
*/
|
21
|
+
|
22
|
+
|
23
|
+
HamlRuntime = {
|
24
|
+
/*
|
25
|
+
Taken from underscore.string.js escapeHTML, and replace the apos entity with character 39 so that it renders
|
26
|
+
correctly in IE7
|
27
|
+
*/
|
28
|
+
|
29
|
+
escapeHTML: function(str) {
|
30
|
+
return String(str || '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'");
|
31
|
+
},
|
32
|
+
/*
|
33
|
+
Provides the implementation to preserve the whitespace as per the HAML reference
|
34
|
+
*/
|
35
|
+
|
36
|
+
perserveWhitespace: function(str) {
|
37
|
+
var i, out, re, result;
|
38
|
+
re = /<[a-zA-Z]+>[^<]*<\/[a-zA-Z]+>/g;
|
39
|
+
out = '';
|
40
|
+
i = 0;
|
41
|
+
result = re.exec(str);
|
42
|
+
if (result) {
|
43
|
+
while (result) {
|
44
|
+
out += str.substring(i, result.index);
|
45
|
+
out += result[0].replace(/\n/g, '
');
|
46
|
+
i = result.index + result[0].length;
|
47
|
+
result = re.exec(str);
|
48
|
+
}
|
49
|
+
out += str.substring(i);
|
50
|
+
} else {
|
51
|
+
out = str;
|
52
|
+
}
|
53
|
+
return out;
|
54
|
+
},
|
55
|
+
/*
|
56
|
+
Generates a error message including the current line in the source where the error occurred
|
57
|
+
*/
|
58
|
+
|
59
|
+
templateError: function(lineNumber, characterNumber, currentLine, error) {
|
60
|
+
var i, message;
|
61
|
+
message = error + " at line " + lineNumber + " and character " + characterNumber + ":\n" + currentLine + '\n';
|
62
|
+
i = 0;
|
63
|
+
while (i < characterNumber - 1) {
|
64
|
+
message += '-';
|
65
|
+
i++;
|
66
|
+
}
|
67
|
+
message += '^';
|
68
|
+
return message;
|
69
|
+
},
|
70
|
+
/*
|
71
|
+
Generates the attributes for the element by combining all the various sources together
|
72
|
+
*/
|
73
|
+
|
74
|
+
generateElementAttributes: function(context, id, classes, objRefFn, attrList, attrFunction, lineNumber, characterNumber, currentLine) {
|
75
|
+
var attr, attributes, className, dataAttr, dataAttributes, hash, html, object, objectId;
|
76
|
+
attributes = {};
|
77
|
+
attributes = this.combineAttributes(attributes, 'id', id);
|
78
|
+
if (classes.length > 0 && classes[0].length > 0) {
|
79
|
+
attributes = this.combineAttributes(attributes, 'class', classes);
|
80
|
+
}
|
81
|
+
if (attrList) {
|
82
|
+
for (attr in attrList) {
|
83
|
+
if (!__hasProp.call(attrList, attr)) continue;
|
84
|
+
attributes = this.combineAttributes(attributes, attr, attrList[attr]);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
if (objRefFn) {
|
88
|
+
try {
|
89
|
+
object = objRefFn.call(context, context);
|
90
|
+
if (object) {
|
91
|
+
objectId = null;
|
92
|
+
if (object.id) {
|
93
|
+
objectId = object.id;
|
94
|
+
} else if (object.get) {
|
95
|
+
objectId = object.get('id');
|
96
|
+
}
|
97
|
+
attributes = this.combineAttributes(attributes, 'id', objectId);
|
98
|
+
className = null;
|
99
|
+
if (object['class']) {
|
100
|
+
className = object['class'];
|
101
|
+
} else if (object.get) {
|
102
|
+
className = object.get('class');
|
103
|
+
}
|
104
|
+
attributes = this.combineAttributes(attributes, 'class', className);
|
105
|
+
}
|
106
|
+
} catch (e) {
|
107
|
+
throw haml.HamlRuntime.templateError(lineNumber, characterNumber, currentLine, "Error evaluating object reference - " + e);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
if (attrFunction) {
|
111
|
+
try {
|
112
|
+
hash = attrFunction.call(context, context);
|
113
|
+
if (hash) {
|
114
|
+
for (attr in hash) {
|
115
|
+
if (!__hasProp.call(hash, attr)) continue;
|
116
|
+
if (attr === 'data') {
|
117
|
+
dataAttributes = hash[attr];
|
118
|
+
for (dataAttr in dataAttributes) {
|
119
|
+
if (!__hasProp.call(dataAttributes, dataAttr)) continue;
|
120
|
+
attributes = this.combineAttributes(attributes, 'data-' + dataAttr, dataAttributes[dataAttr]);
|
121
|
+
}
|
122
|
+
} else {
|
123
|
+
attributes = this.combineAttributes(attributes, attr, hash[attr]);
|
124
|
+
}
|
125
|
+
}
|
126
|
+
}
|
127
|
+
} catch (ex) {
|
128
|
+
throw haml.HamlRuntime.templateError(lineNumber, characterNumber, currentLine, "Error evaluating attribute hash - " + ex);
|
129
|
+
}
|
130
|
+
}
|
131
|
+
html = '';
|
132
|
+
if (attributes) {
|
133
|
+
for (attr in attributes) {
|
134
|
+
if (!__hasProp.call(attributes, attr)) continue;
|
135
|
+
if (haml.hasValue(attributes[attr])) {
|
136
|
+
if ((attr === 'id' || attr === 'for') && attributes[attr] instanceof Array) {
|
137
|
+
html += ' ' + attr + '="' + _(attributes[attr]).flatten().join('-') + '"';
|
138
|
+
} else if (attr === 'class' && attributes[attr] instanceof Array) {
|
139
|
+
html += ' ' + attr + '="' + _(attributes[attr]).flatten().join(' ') + '"';
|
140
|
+
} else {
|
141
|
+
html += ' ' + attr + '="' + haml.attrValue(attr, attributes[attr]) + '"';
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}
|
145
|
+
}
|
146
|
+
return html;
|
147
|
+
},
|
148
|
+
/*
|
149
|
+
Returns a white space string with a length of indent * 2
|
150
|
+
*/
|
151
|
+
|
152
|
+
indentText: function(indent) {
|
153
|
+
var i, text;
|
154
|
+
text = '';
|
155
|
+
i = 0;
|
156
|
+
while (i < indent) {
|
157
|
+
text += ' ';
|
158
|
+
i++;
|
159
|
+
}
|
160
|
+
return text;
|
161
|
+
},
|
162
|
+
/*
|
163
|
+
Combines the attributes in the attributres hash with the given attribute and value
|
164
|
+
ID, FOR and CLASS attributes will expand to arrays when multiple values are provided
|
165
|
+
*/
|
166
|
+
|
167
|
+
combineAttributes: function(attributes, attrName, attrValue) {
|
168
|
+
var classes;
|
169
|
+
if (haml.hasValue(attrValue)) {
|
170
|
+
if (attrName === 'id' && attrValue.toString().length > 0) {
|
171
|
+
if (attributes && attributes.id instanceof Array) {
|
172
|
+
attributes.id.unshift(attrValue);
|
173
|
+
} else if (attributes && attributes.id) {
|
174
|
+
attributes.id = [attributes.id, attrValue];
|
175
|
+
} else if (attributes) {
|
176
|
+
attributes.id = attrValue;
|
177
|
+
} else {
|
178
|
+
attributes = {
|
179
|
+
id: attrValue
|
180
|
+
};
|
181
|
+
}
|
182
|
+
} else if (attrName === 'for' && attrValue.toString().length > 0) {
|
183
|
+
if (attributes && attributes['for'] instanceof Array) {
|
184
|
+
attributes['for'].unshift(attrValue);
|
185
|
+
} else if (attributes && attributes['for']) {
|
186
|
+
attributes['for'] = [attributes['for'], attrValue];
|
187
|
+
} else if (attributes) {
|
188
|
+
attributes['for'] = attrValue;
|
189
|
+
} else {
|
190
|
+
attributes = {
|
191
|
+
'for': attrValue
|
192
|
+
};
|
193
|
+
}
|
194
|
+
} else if (attrName === 'class') {
|
195
|
+
classes = [];
|
196
|
+
if (attrValue instanceof Array) {
|
197
|
+
classes = classes.concat(attrValue);
|
198
|
+
} else {
|
199
|
+
classes.push(attrValue);
|
200
|
+
}
|
201
|
+
if (attributes && attributes['class']) {
|
202
|
+
attributes['class'] = attributes['class'].concat(classes);
|
203
|
+
} else if (attributes) {
|
204
|
+
attributes['class'] = classes;
|
205
|
+
} else {
|
206
|
+
attributes = {
|
207
|
+
'class': classes
|
208
|
+
};
|
209
|
+
}
|
210
|
+
} else if (attrName !== 'id') {
|
211
|
+
attributes || (attributes = {});
|
212
|
+
attributes[attrName] = attrValue;
|
213
|
+
}
|
214
|
+
}
|
215
|
+
return attributes;
|
216
|
+
}
|
217
|
+
};
|
218
|
+
|
219
|
+
/*
|
220
|
+
HAML Tokiniser: This class is responsible for parsing the haml source into tokens
|
221
|
+
*/
|
222
|
+
|
223
|
+
|
224
|
+
Tokeniser = (function() {
|
225
|
+
|
226
|
+
Tokeniser.prototype.currentLineMatcher = /[^\n]*/g;
|
227
|
+
|
228
|
+
Tokeniser.prototype.tokenMatchers = {
|
229
|
+
whitespace: /[ \t]+/g,
|
230
|
+
element: /%[a-zA-Z][a-zA-Z0-9]*/g,
|
231
|
+
idSelector: /#[a-zA-Z_\-][a-zA-Z0-9_\-]*/g,
|
232
|
+
classSelector: /\.[a-zA-Z0-9_\-]+/g,
|
233
|
+
identifier: /[a-zA-Z][a-zA-Z0-9\-]*/g,
|
234
|
+
quotedString: /[\'][^\'\n]*[\']/g,
|
235
|
+
quotedString2: /[\"][^\"\n]*[\"]/g,
|
236
|
+
comment: /\-#/g,
|
237
|
+
escapeHtml: /\&=/g,
|
238
|
+
unescapeHtml: /\!=/g,
|
239
|
+
objectReference: /\[[a-zA-Z_@][a-zA-Z0-9_]*\]/g,
|
240
|
+
doctype: /!!!/g,
|
241
|
+
continueLine: /\|\s*\n/g,
|
242
|
+
filter: /:\w+/g
|
243
|
+
};
|
244
|
+
|
245
|
+
function Tokeniser(options) {
|
246
|
+
var errorFn, successFn, template,
|
247
|
+
_this = this;
|
248
|
+
this.buffer = null;
|
249
|
+
this.bufferIndex = null;
|
250
|
+
this.prevToken = null;
|
251
|
+
this.token = null;
|
252
|
+
if (options.templateId != null) {
|
253
|
+
template = document.getElementById(options.templateId);
|
254
|
+
if (template) {
|
255
|
+
this.buffer = template.text;
|
256
|
+
this.bufferIndex = 0;
|
257
|
+
} else {
|
258
|
+
throw "Did not find a template with ID '" + options.templateId + "'";
|
259
|
+
}
|
260
|
+
} else if (options.template != null) {
|
261
|
+
this.buffer = options.template;
|
262
|
+
this.bufferIndex = 0;
|
263
|
+
} else if (options.templateUrl != null) {
|
264
|
+
errorFn = function(jqXHR, textStatus, errorThrown) {
|
265
|
+
throw "Failed to fetch haml template at URL " + options.templateUrl + ": " + textStatus + " " + errorThrown;
|
266
|
+
};
|
267
|
+
successFn = function(data) {
|
268
|
+
_this.buffer = data;
|
269
|
+
return _this.bufferIndex = 0;
|
270
|
+
};
|
271
|
+
jQuery.ajax({
|
272
|
+
url: options.templateUrl,
|
273
|
+
success: successFn,
|
274
|
+
error: errorFn,
|
275
|
+
dataType: 'text',
|
276
|
+
async: false,
|
277
|
+
beforeSend: function(xhr) {
|
278
|
+
return xhr.withCredentials = true;
|
279
|
+
}
|
280
|
+
});
|
281
|
+
}
|
282
|
+
}
|
283
|
+
|
284
|
+
/*
|
285
|
+
Try to match a token with the given regexp
|
286
|
+
*/
|
287
|
+
|
288
|
+
|
289
|
+
Tokeniser.prototype.matchToken = function(matcher) {
|
290
|
+
var result;
|
291
|
+
matcher.lastIndex = this.bufferIndex;
|
292
|
+
result = matcher.exec(this.buffer);
|
293
|
+
if ((result != null ? result.index : void 0) === this.bufferIndex) {
|
294
|
+
return result[0];
|
295
|
+
}
|
296
|
+
};
|
297
|
+
|
298
|
+
/*
|
299
|
+
Match a multi-character token
|
300
|
+
*/
|
301
|
+
|
302
|
+
|
303
|
+
Tokeniser.prototype.matchMultiCharToken = function(matcher, token, tokenStr) {
|
304
|
+
var matched, _ref;
|
305
|
+
if (!this.token) {
|
306
|
+
matched = this.matchToken(matcher);
|
307
|
+
if (matched) {
|
308
|
+
this.token = token;
|
309
|
+
this.token.tokenString = (_ref = typeof tokenStr === "function" ? tokenStr(matched) : void 0) != null ? _ref : matched;
|
310
|
+
this.token.matched = matched;
|
311
|
+
return this.advanceCharsInBuffer(matched.length);
|
312
|
+
}
|
313
|
+
}
|
314
|
+
};
|
315
|
+
|
316
|
+
/*
|
317
|
+
Match a single character token
|
318
|
+
*/
|
319
|
+
|
320
|
+
|
321
|
+
Tokeniser.prototype.matchSingleCharToken = function(ch, token) {
|
322
|
+
if (!this.token && this.buffer.charAt(this.bufferIndex) === ch) {
|
323
|
+
this.token = token;
|
324
|
+
this.token.tokenString = ch;
|
325
|
+
this.token.matched = ch;
|
326
|
+
return this.advanceCharsInBuffer(1);
|
327
|
+
}
|
328
|
+
};
|
329
|
+
|
330
|
+
/*
|
331
|
+
Match and return the next token in the input buffer
|
332
|
+
*/
|
333
|
+
|
334
|
+
|
335
|
+
Tokeniser.prototype.getNextToken = function() {
|
336
|
+
var braceCount, ch, ch1, characterNumberStart, i, lineNumberStart, str;
|
337
|
+
if (isNaN(this.bufferIndex)) {
|
338
|
+
throw haml.HamlRuntime.templateError(this.lineNumber, this.characterNumber, this.currentLine, "An internal parser error has occurred in the HAML parser");
|
339
|
+
}
|
340
|
+
this.prevToken = this.token;
|
341
|
+
this.token = null;
|
342
|
+
if (this.buffer === null || this.buffer.length === this.bufferIndex) {
|
343
|
+
this.token = {
|
344
|
+
eof: true,
|
345
|
+
token: 'EOF'
|
346
|
+
};
|
347
|
+
} else {
|
348
|
+
this.initLine();
|
349
|
+
if (!this.token) {
|
350
|
+
ch = this.buffer.charCodeAt(this.bufferIndex);
|
351
|
+
ch1 = this.buffer.charCodeAt(this.bufferIndex + 1);
|
352
|
+
if (ch === 10 || (ch === 13 && ch1 === 10)) {
|
353
|
+
this.token = {
|
354
|
+
eol: true,
|
355
|
+
token: 'EOL'
|
356
|
+
};
|
357
|
+
if (ch === 13 && ch1 === 10) {
|
358
|
+
this.advanceCharsInBuffer(2);
|
359
|
+
this.token.matched = String.fromCharCode(ch) + String.fromCharCode(ch1);
|
360
|
+
} else {
|
361
|
+
this.advanceCharsInBuffer(1);
|
362
|
+
this.token.matched = String.fromCharCode(ch);
|
363
|
+
}
|
364
|
+
this.characterNumber = 0;
|
365
|
+
this.currentLine = this.getCurrentLine();
|
366
|
+
}
|
367
|
+
}
|
368
|
+
this.matchMultiCharToken(this.tokenMatchers.whitespace, {
|
369
|
+
ws: true,
|
370
|
+
token: 'WS'
|
371
|
+
});
|
372
|
+
this.matchMultiCharToken(this.tokenMatchers.continueLine, {
|
373
|
+
continueLine: true,
|
374
|
+
token: 'CONTINUELINE'
|
375
|
+
});
|
376
|
+
this.matchMultiCharToken(this.tokenMatchers.element, {
|
377
|
+
element: true,
|
378
|
+
token: 'ELEMENT'
|
379
|
+
}, function(matched) {
|
380
|
+
return matched.substring(1);
|
381
|
+
});
|
382
|
+
this.matchMultiCharToken(this.tokenMatchers.idSelector, {
|
383
|
+
idSelector: true,
|
384
|
+
token: 'ID'
|
385
|
+
}, function(matched) {
|
386
|
+
return matched.substring(1);
|
387
|
+
});
|
388
|
+
this.matchMultiCharToken(this.tokenMatchers.classSelector, {
|
389
|
+
classSelector: true,
|
390
|
+
token: 'CLASS'
|
391
|
+
}, function(matched) {
|
392
|
+
return matched.substring(1);
|
393
|
+
});
|
394
|
+
this.matchMultiCharToken(this.tokenMatchers.identifier, {
|
395
|
+
identifier: true,
|
396
|
+
token: 'IDENTIFIER'
|
397
|
+
});
|
398
|
+
this.matchMultiCharToken(this.tokenMatchers.doctype, {
|
399
|
+
doctype: true,
|
400
|
+
token: 'DOCTYPE'
|
401
|
+
});
|
402
|
+
this.matchMultiCharToken(this.tokenMatchers.filter, {
|
403
|
+
filter: true,
|
404
|
+
token: 'FILTER'
|
405
|
+
}, function(matched) {
|
406
|
+
return matched.substring(1);
|
407
|
+
});
|
408
|
+
if (!this.token) {
|
409
|
+
str = this.matchToken(this.tokenMatchers.quotedString);
|
410
|
+
if (!str) {
|
411
|
+
str = this.matchToken(this.tokenMatchers.quotedString2);
|
412
|
+
}
|
413
|
+
if (str) {
|
414
|
+
this.token = {
|
415
|
+
string: true,
|
416
|
+
token: 'STRING',
|
417
|
+
tokenString: str.substring(1, str.length - 1),
|
418
|
+
matched: str
|
419
|
+
};
|
420
|
+
this.advanceCharsInBuffer(str.length);
|
421
|
+
}
|
422
|
+
}
|
423
|
+
this.matchMultiCharToken(this.tokenMatchers.comment, {
|
424
|
+
comment: true,
|
425
|
+
token: 'COMMENT'
|
426
|
+
});
|
427
|
+
this.matchMultiCharToken(this.tokenMatchers.escapeHtml, {
|
428
|
+
escapeHtml: true,
|
429
|
+
token: 'ESCAPEHTML'
|
430
|
+
});
|
431
|
+
this.matchMultiCharToken(this.tokenMatchers.unescapeHtml, {
|
432
|
+
unescapeHtml: true,
|
433
|
+
token: 'UNESCAPEHTML'
|
434
|
+
});
|
435
|
+
this.matchMultiCharToken(this.tokenMatchers.objectReference, {
|
436
|
+
objectReference: true,
|
437
|
+
token: 'OBJECTREFERENCE'
|
438
|
+
}, function(matched) {
|
439
|
+
return matched.substring(1, matched.length - 1);
|
440
|
+
});
|
441
|
+
if (!this.token) {
|
442
|
+
if (this.buffer && this.buffer.charAt(this.bufferIndex) === '{') {
|
443
|
+
i = this.bufferIndex + 1;
|
444
|
+
characterNumberStart = this.characterNumber;
|
445
|
+
lineNumberStart = this.lineNumber;
|
446
|
+
braceCount = 1;
|
447
|
+
while (i < this.buffer.length && (braceCount > 1 || this.buffer.charAt(i) !== '}')) {
|
448
|
+
if (this.buffer.charAt(i) === '{') {
|
449
|
+
braceCount++;
|
450
|
+
} else if (this.buffer.charAt(i) === '}') {
|
451
|
+
braceCount--;
|
452
|
+
}
|
453
|
+
i++;
|
454
|
+
}
|
455
|
+
if (i === this.buffer.length) {
|
456
|
+
this.characterNumber = characterNumberStart + 1;
|
457
|
+
this.lineNumber = lineNumberStart;
|
458
|
+
throw this.parseError('Error parsing attribute hash - Did not find a terminating "}"');
|
459
|
+
} else {
|
460
|
+
this.token = {
|
461
|
+
attributeHash: true,
|
462
|
+
token: 'ATTRHASH',
|
463
|
+
tokenString: this.buffer.substring(this.bufferIndex, i + 1),
|
464
|
+
matched: this.buffer.substring(this.bufferIndex, i + 1)
|
465
|
+
};
|
466
|
+
this.advanceCharsInBuffer(i - this.bufferIndex + 1);
|
467
|
+
}
|
468
|
+
}
|
469
|
+
}
|
470
|
+
this.matchSingleCharToken('(', {
|
471
|
+
openBracket: true,
|
472
|
+
token: 'OPENBRACKET'
|
473
|
+
});
|
474
|
+
this.matchSingleCharToken(')', {
|
475
|
+
closeBracket: true,
|
476
|
+
token: 'CLOSEBRACKET'
|
477
|
+
});
|
478
|
+
this.matchSingleCharToken('=', {
|
479
|
+
equal: true,
|
480
|
+
token: 'EQUAL'
|
481
|
+
});
|
482
|
+
this.matchSingleCharToken('/', {
|
483
|
+
slash: true,
|
484
|
+
token: 'SLASH'
|
485
|
+
});
|
486
|
+
this.matchSingleCharToken('!', {
|
487
|
+
exclamation: true,
|
488
|
+
token: 'EXCLAMATION'
|
489
|
+
});
|
490
|
+
this.matchSingleCharToken('-', {
|
491
|
+
minus: true,
|
492
|
+
token: 'MINUS'
|
493
|
+
});
|
494
|
+
this.matchSingleCharToken('&', {
|
495
|
+
amp: true,
|
496
|
+
token: 'AMP'
|
497
|
+
});
|
498
|
+
this.matchSingleCharToken('<', {
|
499
|
+
lt: true,
|
500
|
+
token: 'LT'
|
501
|
+
});
|
502
|
+
this.matchSingleCharToken('>', {
|
503
|
+
gt: true,
|
504
|
+
token: 'GT'
|
505
|
+
});
|
506
|
+
this.matchSingleCharToken('~', {
|
507
|
+
tilde: true,
|
508
|
+
token: 'TILDE'
|
509
|
+
});
|
510
|
+
if (this.token === null) {
|
511
|
+
this.token = {
|
512
|
+
unknown: true,
|
513
|
+
token: 'UNKNOWN'
|
514
|
+
};
|
515
|
+
}
|
516
|
+
}
|
517
|
+
return this.token;
|
518
|
+
};
|
519
|
+
|
520
|
+
/*
|
521
|
+
Look ahead a number of tokens and return the token found
|
522
|
+
*/
|
523
|
+
|
524
|
+
|
525
|
+
Tokeniser.prototype.lookAhead = function(numberOfTokens) {
|
526
|
+
var bufferIndex, characterNumber, currentLine, currentToken, i, lineNumber, prevToken, token;
|
527
|
+
token = null;
|
528
|
+
if (numberOfTokens > 0) {
|
529
|
+
currentToken = this.token;
|
530
|
+
prevToken = this.prevToken;
|
531
|
+
currentLine = this.currentLine;
|
532
|
+
lineNumber = this.lineNumber;
|
533
|
+
characterNumber = this.characterNumber;
|
534
|
+
bufferIndex = this.bufferIndex;
|
535
|
+
i = 0;
|
536
|
+
while (i++ < numberOfTokens) {
|
537
|
+
token = this.getNextToken();
|
538
|
+
}
|
539
|
+
this.token = currentToken;
|
540
|
+
this.prevToken = prevToken;
|
541
|
+
this.currentLine = currentLine;
|
542
|
+
this.lineNumber = lineNumber;
|
543
|
+
this.characterNumber = characterNumber;
|
544
|
+
this.bufferIndex = bufferIndex;
|
545
|
+
}
|
546
|
+
return token;
|
547
|
+
};
|
548
|
+
|
549
|
+
/*
|
550
|
+
Initilise the line and character counters
|
551
|
+
*/
|
552
|
+
|
553
|
+
|
554
|
+
Tokeniser.prototype.initLine = function() {
|
555
|
+
if (!this.currentLine && this.currentLine !== "") {
|
556
|
+
this.currentLine = this.getCurrentLine();
|
557
|
+
this.lineNumber = 1;
|
558
|
+
return this.characterNumber = 0;
|
559
|
+
}
|
560
|
+
};
|
561
|
+
|
562
|
+
/*
|
563
|
+
Returns the current line in the input buffer
|
564
|
+
*/
|
565
|
+
|
566
|
+
|
567
|
+
Tokeniser.prototype.getCurrentLine = function(index) {
|
568
|
+
var line;
|
569
|
+
this.currentLineMatcher.lastIndex = this.bufferIndex + (index != null ? index : 0);
|
570
|
+
line = this.currentLineMatcher.exec(this.buffer);
|
571
|
+
if (line) {
|
572
|
+
return line[0];
|
573
|
+
} else {
|
574
|
+
return '';
|
575
|
+
}
|
576
|
+
};
|
577
|
+
|
578
|
+
/*
|
579
|
+
Returns an error string filled out with the line and character counters
|
580
|
+
*/
|
581
|
+
|
582
|
+
|
583
|
+
Tokeniser.prototype.parseError = function(error) {
|
584
|
+
return haml.HamlRuntime.templateError(this.lineNumber, this.characterNumber, this.currentLine, error);
|
585
|
+
};
|
586
|
+
|
587
|
+
/*
|
588
|
+
Skips to the end of the line and returns the string that was skipped
|
589
|
+
*/
|
590
|
+
|
591
|
+
|
592
|
+
Tokeniser.prototype.skipToEOLorEOF = function() {
|
593
|
+
var contents, line, text;
|
594
|
+
text = '';
|
595
|
+
if (!(this.token.eof || this.token.eol)) {
|
596
|
+
if (!this.token.unknown) {
|
597
|
+
text += this.token.matched;
|
598
|
+
}
|
599
|
+
this.currentLineMatcher.lastIndex = this.bufferIndex;
|
600
|
+
line = this.currentLineMatcher.exec(this.buffer);
|
601
|
+
if (line && line.index === this.bufferIndex) {
|
602
|
+
contents = (_.str || _).rtrim(line[0]);
|
603
|
+
if ((_.str || _).endsWith(contents, '|')) {
|
604
|
+
text += contents.substring(0, contents.length - 1);
|
605
|
+
this.advanceCharsInBuffer(contents.length - 1);
|
606
|
+
this.getNextToken();
|
607
|
+
text += this.parseMultiLine();
|
608
|
+
} else {
|
609
|
+
text += line[0];
|
610
|
+
this.advanceCharsInBuffer(line[0].length);
|
611
|
+
this.getNextToken();
|
612
|
+
}
|
613
|
+
}
|
614
|
+
}
|
615
|
+
return text;
|
616
|
+
};
|
617
|
+
|
618
|
+
/*
|
619
|
+
Parses a multiline code block and returns the parsed text
|
620
|
+
*/
|
621
|
+
|
622
|
+
|
623
|
+
Tokeniser.prototype.parseMultiLine = function() {
|
624
|
+
var contents, line, text;
|
625
|
+
text = '';
|
626
|
+
while (this.token.continueLine) {
|
627
|
+
this.currentLineMatcher.lastIndex = this.bufferIndex;
|
628
|
+
line = this.currentLineMatcher.exec(this.buffer);
|
629
|
+
if (line && line.index === this.bufferIndex) {
|
630
|
+
contents = (_.str || _).rtrim(line[0]);
|
631
|
+
if ((_.str || _).endsWith(contents, '|')) {
|
632
|
+
text += contents.substring(0, contents.length - 1);
|
633
|
+
this.advanceCharsInBuffer(contents.length - 1);
|
634
|
+
}
|
635
|
+
this.getNextToken();
|
636
|
+
}
|
637
|
+
}
|
638
|
+
return text;
|
639
|
+
};
|
640
|
+
|
641
|
+
/*
|
642
|
+
Advances the input buffer pointer by a number of characters, updating the line and character counters
|
643
|
+
*/
|
644
|
+
|
645
|
+
|
646
|
+
Tokeniser.prototype.advanceCharsInBuffer = function(numChars) {
|
647
|
+
var ch, ch1, i;
|
648
|
+
i = 0;
|
649
|
+
while (i < numChars) {
|
650
|
+
ch = this.buffer.charCodeAt(this.bufferIndex + i);
|
651
|
+
ch1 = this.buffer.charCodeAt(this.bufferIndex + i + 1);
|
652
|
+
if (ch === 13 && ch1 === 10) {
|
653
|
+
this.lineNumber++;
|
654
|
+
this.characterNumber = 0;
|
655
|
+
this.currentLine = this.getCurrentLine(i);
|
656
|
+
i++;
|
657
|
+
} else if (ch === 10) {
|
658
|
+
this.lineNumber++;
|
659
|
+
this.characterNumber = 0;
|
660
|
+
this.currentLine = this.getCurrentLine(i);
|
661
|
+
} else {
|
662
|
+
this.characterNumber++;
|
663
|
+
}
|
664
|
+
i++;
|
665
|
+
}
|
666
|
+
return this.bufferIndex += numChars;
|
667
|
+
};
|
668
|
+
|
669
|
+
/*
|
670
|
+
Returns the current line and character counters
|
671
|
+
*/
|
672
|
+
|
673
|
+
|
674
|
+
Tokeniser.prototype.currentParsePoint = function() {
|
675
|
+
return {
|
676
|
+
lineNumber: this.lineNumber,
|
677
|
+
characterNumber: this.characterNumber,
|
678
|
+
currentLine: this.currentLine
|
679
|
+
};
|
680
|
+
};
|
681
|
+
|
682
|
+
/*
|
683
|
+
Pushes back the current token onto the front of the input buffer
|
684
|
+
*/
|
685
|
+
|
686
|
+
|
687
|
+
Tokeniser.prototype.pushBackToken = function() {
|
688
|
+
if (!this.token.unknown && !this.token.eof) {
|
689
|
+
this.bufferIndex -= this.token.matched.length;
|
690
|
+
return this.token = this.prevToken;
|
691
|
+
}
|
692
|
+
};
|
693
|
+
|
694
|
+
/*
|
695
|
+
Is the current token an end of line or end of input buffer
|
696
|
+
*/
|
697
|
+
|
698
|
+
|
699
|
+
Tokeniser.prototype.isEolOrEof = function() {
|
700
|
+
return this.token.eol || this.token.eof;
|
701
|
+
};
|
702
|
+
|
703
|
+
return Tokeniser;
|
704
|
+
|
705
|
+
})();
|
706
|
+
|
707
|
+
/*
|
708
|
+
Provides buffering between the generated javascript and html contents
|
709
|
+
*/
|
710
|
+
|
711
|
+
|
712
|
+
Buffer = (function() {
|
713
|
+
|
714
|
+
function Buffer(generator) {
|
715
|
+
this.generator = generator;
|
716
|
+
this.buffer = '';
|
717
|
+
this.outputBuffer = '';
|
718
|
+
}
|
719
|
+
|
720
|
+
Buffer.prototype.append = function(str) {
|
721
|
+
if (this.buffer.length === 0) {
|
722
|
+
this.generator.mark();
|
723
|
+
}
|
724
|
+
if (str && str.length > 0) {
|
725
|
+
return this.buffer += str;
|
726
|
+
}
|
727
|
+
};
|
728
|
+
|
729
|
+
Buffer.prototype.appendToOutputBuffer = function(str) {
|
730
|
+
if (str && str.length > 0) {
|
731
|
+
this.flush();
|
732
|
+
return this.outputBuffer += str;
|
733
|
+
}
|
734
|
+
};
|
735
|
+
|
736
|
+
Buffer.prototype.flush = function() {
|
737
|
+
if (this.buffer && this.buffer.length > 0) {
|
738
|
+
this.outputBuffer += this.generator.generateFlush(this.buffer);
|
739
|
+
}
|
740
|
+
return this.buffer = '';
|
741
|
+
};
|
742
|
+
|
743
|
+
Buffer.prototype.output = function() {
|
744
|
+
return this.outputBuffer;
|
745
|
+
};
|
746
|
+
|
747
|
+
Buffer.prototype.trimWhitespace = function() {
|
748
|
+
var ch, i;
|
749
|
+
if (this.buffer.length > 0) {
|
750
|
+
i = this.buffer.length - 1;
|
751
|
+
while (i > 0) {
|
752
|
+
ch = this.buffer.charAt(i);
|
753
|
+
if (ch === ' ' || ch === '\t' || ch === '\n') {
|
754
|
+
i--;
|
755
|
+
} else if (i > 1 && (ch === 'n' || ch === 't') && (this.buffer.charAt(i - 1) === '\\')) {
|
756
|
+
i -= 2;
|
757
|
+
} else {
|
758
|
+
break;
|
759
|
+
}
|
760
|
+
}
|
761
|
+
if (i > 0 && i < this.buffer.length - 1) {
|
762
|
+
return this.buffer = this.buffer.substring(0, i + 1);
|
763
|
+
} else if (i === 0) {
|
764
|
+
return this.buffer = '';
|
765
|
+
}
|
766
|
+
}
|
767
|
+
};
|
768
|
+
|
769
|
+
return Buffer;
|
770
|
+
|
771
|
+
})();
|
772
|
+
|
773
|
+
/*
|
774
|
+
Common code shared across all code generators
|
775
|
+
*/
|
776
|
+
|
777
|
+
|
778
|
+
CodeGenerator = (function() {
|
779
|
+
|
780
|
+
function CodeGenerator() {}
|
781
|
+
|
782
|
+
CodeGenerator.prototype.embeddedCodeBlockMatcher = /#{([^}]*)}/g;
|
783
|
+
|
784
|
+
return CodeGenerator;
|
785
|
+
|
786
|
+
})();
|
787
|
+
|
788
|
+
/*
|
789
|
+
Code generator that generates a Javascript function body
|
790
|
+
*/
|
791
|
+
|
792
|
+
|
793
|
+
JsCodeGenerator = (function(_super) {
|
794
|
+
|
795
|
+
__extends(JsCodeGenerator, _super);
|
796
|
+
|
797
|
+
function JsCodeGenerator() {
|
798
|
+
this.outputBuffer = new haml.Buffer(this);
|
799
|
+
}
|
800
|
+
|
801
|
+
/*
|
802
|
+
Append a line with embedded javascript code
|
803
|
+
*/
|
804
|
+
|
805
|
+
|
806
|
+
JsCodeGenerator.prototype.appendEmbeddedCode = function(indentText, expression, escapeContents, perserveWhitespace, currentParsePoint) {
|
807
|
+
this.outputBuffer.flush();
|
808
|
+
this.outputBuffer.appendToOutputBuffer(indentText + 'try {\n');
|
809
|
+
this.outputBuffer.appendToOutputBuffer(indentText + ' var value = eval("' + (_.str || _).trim(expression).replace(/"/g, '\\"').replace(/\\n/g, '\\\\n') + '");\n');
|
810
|
+
this.outputBuffer.appendToOutputBuffer(indentText + ' value = value === null ? "" : value;');
|
811
|
+
if (escapeContents) {
|
812
|
+
this.outputBuffer.appendToOutputBuffer(indentText + ' html.push(haml.HamlRuntime.escapeHTML(String(value)));\n');
|
813
|
+
} else if (perserveWhitespace) {
|
814
|
+
this.outputBuffer.appendToOutputBuffer(indentText + ' html.push(haml.HamlRuntime.perserveWhitespace(String(value)));\n');
|
815
|
+
} else {
|
816
|
+
this.outputBuffer.appendToOutputBuffer(indentText + ' html.push(String(value));\n');
|
817
|
+
}
|
818
|
+
this.outputBuffer.appendToOutputBuffer(indentText + '} catch (e) {\n');
|
819
|
+
this.outputBuffer.appendToOutputBuffer(indentText + ' throw new Error(haml.HamlRuntime.templateError(' + currentParsePoint.lineNumber + ', ' + currentParsePoint.characterNumber + ', "' + this.escapeCode(currentParsePoint.currentLine) + '",\n');
|
820
|
+
this.outputBuffer.appendToOutputBuffer(indentText + ' "Error evaluating expression - " + e));\n');
|
821
|
+
return this.outputBuffer.appendToOutputBuffer(indentText + '}\n');
|
822
|
+
};
|
823
|
+
|
824
|
+
/*
|
825
|
+
Initilising the output buffer with any variables or code
|
826
|
+
*/
|
827
|
+
|
828
|
+
|
829
|
+
JsCodeGenerator.prototype.initOutput = function() {
|
830
|
+
return this.outputBuffer.appendToOutputBuffer(' var html = [];\n' + ' var hashFunction = null, hashObject = null, objRef = null, objRefFn = null;\n with (context || {}) {\n');
|
831
|
+
};
|
832
|
+
|
833
|
+
/*
|
834
|
+
Flush and close the output buffer and return the contents
|
835
|
+
*/
|
836
|
+
|
837
|
+
|
838
|
+
JsCodeGenerator.prototype.closeAndReturnOutput = function() {
|
839
|
+
this.outputBuffer.flush();
|
840
|
+
return this.outputBuffer.output() + ' }\n return html.join("");\n';
|
841
|
+
};
|
842
|
+
|
843
|
+
/*
|
844
|
+
Append a line of code to the output buffer
|
845
|
+
*/
|
846
|
+
|
847
|
+
|
848
|
+
JsCodeGenerator.prototype.appendCodeLine = function(line, eol) {
|
849
|
+
this.outputBuffer.flush();
|
850
|
+
this.outputBuffer.appendToOutputBuffer(HamlRuntime.indentText(this.indent));
|
851
|
+
this.outputBuffer.appendToOutputBuffer(line);
|
852
|
+
return this.outputBuffer.appendToOutputBuffer(eol);
|
853
|
+
};
|
854
|
+
|
855
|
+
/*
|
856
|
+
Does the current line end with a function declaration?
|
857
|
+
*/
|
858
|
+
|
859
|
+
|
860
|
+
JsCodeGenerator.prototype.lineMatchesStartFunctionBlock = function(line) {
|
861
|
+
return line.match(/function\s*\((,?\s*\w+)*\)\s*\{\s*$/);
|
862
|
+
};
|
863
|
+
|
864
|
+
/*
|
865
|
+
Does the current line end with a starting code block
|
866
|
+
*/
|
867
|
+
|
868
|
+
|
869
|
+
JsCodeGenerator.prototype.lineMatchesStartBlock = function(line) {
|
870
|
+
return line.match(/\{\s*$/);
|
871
|
+
};
|
872
|
+
|
873
|
+
/*
|
874
|
+
Generate the code to close off a code block
|
875
|
+
*/
|
876
|
+
|
877
|
+
|
878
|
+
JsCodeGenerator.prototype.closeOffCodeBlock = function(tokeniser) {
|
879
|
+
if (!(tokeniser.token.minus && tokeniser.matchToken(/\s*\}/g))) {
|
880
|
+
this.outputBuffer.flush();
|
881
|
+
return this.outputBuffer.appendToOutputBuffer(HamlRuntime.indentText(this.indent) + '}\n');
|
882
|
+
}
|
883
|
+
};
|
884
|
+
|
885
|
+
/*
|
886
|
+
Generate the code to close off a function parameter
|
887
|
+
*/
|
888
|
+
|
889
|
+
|
890
|
+
JsCodeGenerator.prototype.closeOffFunctionBlock = function(tokeniser) {
|
891
|
+
if (!(tokeniser.token.minus && tokeniser.matchToken(/\s*\}/g))) {
|
892
|
+
this.outputBuffer.flush();
|
893
|
+
return this.outputBuffer.appendToOutputBuffer(HamlRuntime.indentText(this.indent) + '});\n');
|
894
|
+
}
|
895
|
+
};
|
896
|
+
|
897
|
+
/*
|
898
|
+
Generate the code for dynamic attributes ({} form)
|
899
|
+
*/
|
900
|
+
|
901
|
+
|
902
|
+
JsCodeGenerator.prototype.generateCodeForDynamicAttributes = function(id, classes, attributeList, attributeHash, objectRef, currentParsePoint) {
|
903
|
+
this.outputBuffer.flush();
|
904
|
+
if (attributeHash.length > 0) {
|
905
|
+
attributeHash = this.replaceReservedWordsInHash(attributeHash);
|
906
|
+
this.outputBuffer.appendToOutputBuffer(' hashFunction = function () { return eval("hashObject = ' + attributeHash.replace(/"/g, '\\"').replace(/\n/g, '\\n') + '"); };\n');
|
907
|
+
}
|
908
|
+
if (objectRef.length > 0) {
|
909
|
+
this.outputBuffer.appendToOutputBuffer(' objRefFn = function () { return eval("objRef = ' + objectRef.replace(/"/g, '\\"') + '"); };\n');
|
910
|
+
}
|
911
|
+
return this.outputBuffer.appendToOutputBuffer(' html.push(haml.HamlRuntime.generateElementAttributes(context, "' + id + '", ["' + classes.join('","') + '"], objRefFn, ' + JSON.stringify(attributeList) + ', hashFunction, ' + currentParsePoint.lineNumber + ', ' + currentParsePoint.characterNumber + ', "' + this.escapeCode(currentParsePoint.currentLine) + '"));\n');
|
912
|
+
};
|
913
|
+
|
914
|
+
/*
|
915
|
+
Clean any reserved words in the given hash
|
916
|
+
*/
|
917
|
+
|
918
|
+
|
919
|
+
JsCodeGenerator.prototype.replaceReservedWordsInHash = function(hash) {
|
920
|
+
var reservedWord, resultHash, _i, _len, _ref;
|
921
|
+
resultHash = hash;
|
922
|
+
_ref = ['class', 'for'];
|
923
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
924
|
+
reservedWord = _ref[_i];
|
925
|
+
resultHash = resultHash.replace(reservedWord + ':', '"' + reservedWord + '":');
|
926
|
+
}
|
927
|
+
return resultHash;
|
928
|
+
};
|
929
|
+
|
930
|
+
/*
|
931
|
+
Escape the line so it is safe to put into a javascript string
|
932
|
+
*/
|
933
|
+
|
934
|
+
|
935
|
+
JsCodeGenerator.prototype.escapeCode = function(jsStr) {
|
936
|
+
return jsStr.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r');
|
937
|
+
};
|
938
|
+
|
939
|
+
/*
|
940
|
+
Generate a function from the function body
|
941
|
+
*/
|
942
|
+
|
943
|
+
|
944
|
+
JsCodeGenerator.prototype.generateJsFunction = function(functionBody) {
|
945
|
+
try {
|
946
|
+
return new Function('context', functionBody);
|
947
|
+
} catch (e) {
|
948
|
+
throw "Incorrect embedded code has resulted in an invalid Haml function - " + e + "\nGenerated Function:\n" + functionBody;
|
949
|
+
}
|
950
|
+
};
|
951
|
+
|
952
|
+
/*
|
953
|
+
Generate the code required to support a buffer flush
|
954
|
+
*/
|
955
|
+
|
956
|
+
|
957
|
+
JsCodeGenerator.prototype.generateFlush = function(bufferStr) {
|
958
|
+
return ' html.push("' + this.escapeCode(bufferStr) + '");\n';
|
959
|
+
};
|
960
|
+
|
961
|
+
/*
|
962
|
+
Set the current indent level
|
963
|
+
*/
|
964
|
+
|
965
|
+
|
966
|
+
JsCodeGenerator.prototype.setIndent = function(indent) {
|
967
|
+
return this.indent = indent;
|
968
|
+
};
|
969
|
+
|
970
|
+
/*
|
971
|
+
Save the current indent level if required
|
972
|
+
*/
|
973
|
+
|
974
|
+
|
975
|
+
JsCodeGenerator.prototype.mark = function() {};
|
976
|
+
|
977
|
+
/*
|
978
|
+
Append the text contents to the buffer, expanding any embedded code
|
979
|
+
*/
|
980
|
+
|
981
|
+
|
982
|
+
JsCodeGenerator.prototype.appendTextContents = function(text, shouldInterpolate, currentParsePoint, options) {
|
983
|
+
if (options == null) {
|
984
|
+
options = {};
|
985
|
+
}
|
986
|
+
if (shouldInterpolate && text.match(/#{[^}]*}/)) {
|
987
|
+
return this.interpolateString(text, currentParsePoint, options);
|
988
|
+
} else {
|
989
|
+
return this.outputBuffer.append(this.processText(text, options));
|
990
|
+
}
|
991
|
+
};
|
992
|
+
|
993
|
+
/*
|
994
|
+
Interpolate any embedded code in the text
|
995
|
+
*/
|
996
|
+
|
997
|
+
|
998
|
+
JsCodeGenerator.prototype.interpolateString = function(text, currentParsePoint, options) {
|
999
|
+
var index, precheedingChar, precheedingChar2, result;
|
1000
|
+
index = 0;
|
1001
|
+
result = this.embeddedCodeBlockMatcher.exec(text);
|
1002
|
+
while (result) {
|
1003
|
+
if (result.index > 0) {
|
1004
|
+
precheedingChar = text.charAt(result.index - 1);
|
1005
|
+
}
|
1006
|
+
if (result.index > 1) {
|
1007
|
+
precheedingChar2 = text.charAt(result.index - 2);
|
1008
|
+
}
|
1009
|
+
if (precheedingChar === '\\' && precheedingChar2 !== '\\') {
|
1010
|
+
if (result.index !== 0) {
|
1011
|
+
this.outputBuffer.append(this.processText(text.substring(index, result.index - 1), options));
|
1012
|
+
}
|
1013
|
+
this.outputBuffer.append(this.processText(result[0]), options);
|
1014
|
+
} else {
|
1015
|
+
this.outputBuffer.append(this.processText(text.substring(index, result.index)), options);
|
1016
|
+
this.appendEmbeddedCode(HamlRuntime.indentText(this.indent + 1), result[1], options.escapeHTML, options.perserveWhitespace, currentParsePoint);
|
1017
|
+
}
|
1018
|
+
index = this.embeddedCodeBlockMatcher.lastIndex;
|
1019
|
+
result = this.embeddedCodeBlockMatcher.exec(text);
|
1020
|
+
}
|
1021
|
+
if (index < text.length) {
|
1022
|
+
return this.outputBuffer.append(this.processText(text.substring(index), options));
|
1023
|
+
}
|
1024
|
+
};
|
1025
|
+
|
1026
|
+
/*
|
1027
|
+
process text based on escape and preserve flags
|
1028
|
+
*/
|
1029
|
+
|
1030
|
+
|
1031
|
+
JsCodeGenerator.prototype.processText = function(text, options) {
|
1032
|
+
if (options != null ? options.escapeHTML : void 0) {
|
1033
|
+
return haml.HamlRuntime.escapeHTML(text);
|
1034
|
+
} else if (options != null ? options.perserveWhitespace : void 0) {
|
1035
|
+
return haml.HamlRuntime.perserveWhitespace(text);
|
1036
|
+
} else {
|
1037
|
+
return text;
|
1038
|
+
}
|
1039
|
+
};
|
1040
|
+
|
1041
|
+
return JsCodeGenerator;
|
1042
|
+
|
1043
|
+
})(CodeGenerator);
|
1044
|
+
|
1045
|
+
/*
|
1046
|
+
Code generator that generates javascript code without runtime evaluation
|
1047
|
+
*/
|
1048
|
+
|
1049
|
+
|
1050
|
+
ProductionJsCodeGenerator = (function(_super) {
|
1051
|
+
|
1052
|
+
__extends(ProductionJsCodeGenerator, _super);
|
1053
|
+
|
1054
|
+
function ProductionJsCodeGenerator() {
|
1055
|
+
return ProductionJsCodeGenerator.__super__.constructor.apply(this, arguments);
|
1056
|
+
}
|
1057
|
+
|
1058
|
+
/*
|
1059
|
+
Append a line with embedded javascript code
|
1060
|
+
*/
|
1061
|
+
|
1062
|
+
|
1063
|
+
ProductionJsCodeGenerator.prototype.appendEmbeddedCode = function(indentText, expression, escapeContents, perserveWhitespace, currentParsePoint) {
|
1064
|
+
this.outputBuffer.flush();
|
1065
|
+
this.outputBuffer.appendToOutputBuffer(indentText + ' value = ' + (_.str || _).trim(expression) + ';\n');
|
1066
|
+
this.outputBuffer.appendToOutputBuffer(indentText + ' value = value === null ? "" : value;');
|
1067
|
+
if (escapeContents) {
|
1068
|
+
return this.outputBuffer.appendToOutputBuffer(indentText + ' html.push(haml.HamlRuntime.escapeHTML(String(value)));\n');
|
1069
|
+
} else if (perserveWhitespace) {
|
1070
|
+
return this.outputBuffer.appendToOutputBuffer(indentText + ' html.push(haml.HamlRuntime.perserveWhitespace(String(value)));\n');
|
1071
|
+
} else {
|
1072
|
+
return this.outputBuffer.appendToOutputBuffer(indentText + ' html.push(String(value));\n');
|
1073
|
+
}
|
1074
|
+
};
|
1075
|
+
|
1076
|
+
/*
|
1077
|
+
Generate the code for dynamic attributes ({} form)
|
1078
|
+
*/
|
1079
|
+
|
1080
|
+
|
1081
|
+
ProductionJsCodeGenerator.prototype.generateCodeForDynamicAttributes = function(id, classes, attributeList, attributeHash, objectRef, currentParsePoint) {
|
1082
|
+
this.outputBuffer.flush();
|
1083
|
+
if (attributeHash.length > 0) {
|
1084
|
+
attributeHash = this.replaceReservedWordsInHash(attributeHash);
|
1085
|
+
this.outputBuffer.appendToOutputBuffer(' hashFunction = function () { return ' + attributeHash + '; };\n');
|
1086
|
+
}
|
1087
|
+
if (objectRef.length > 0) {
|
1088
|
+
this.outputBuffer.appendToOutputBuffer(' objRefFn = function () { return ' + objectRef + '; };\n');
|
1089
|
+
}
|
1090
|
+
return this.outputBuffer.appendToOutputBuffer(' html.push(haml.HamlRuntime.generateElementAttributes(context, "' + id + '", ["' + classes.join('","') + '"], objRefFn, ' + JSON.stringify(attributeList) + ', hashFunction, ' + currentParsePoint.lineNumber + ', ' + currentParsePoint.characterNumber + ', "' + this.escapeCode(currentParsePoint.currentLine) + '"));\n');
|
1091
|
+
};
|
1092
|
+
|
1093
|
+
/*
|
1094
|
+
Initilising the output buffer with any variables or code
|
1095
|
+
*/
|
1096
|
+
|
1097
|
+
|
1098
|
+
ProductionJsCodeGenerator.prototype.initOutput = function() {
|
1099
|
+
return this.outputBuffer.appendToOutputBuffer(' var html = [];\n' + ' var hashFunction = null, hashObject = null, objRef = null, objRefFn = null, value= null;\n with (context || {}) {\n');
|
1100
|
+
};
|
1101
|
+
|
1102
|
+
return ProductionJsCodeGenerator;
|
1103
|
+
|
1104
|
+
})(JsCodeGenerator);
|
1105
|
+
|
1106
|
+
/*
|
1107
|
+
Code generator that generates a coffeescript function body
|
1108
|
+
*/
|
1109
|
+
|
1110
|
+
|
1111
|
+
CoffeeCodeGenerator = (function(_super) {
|
1112
|
+
|
1113
|
+
__extends(CoffeeCodeGenerator, _super);
|
1114
|
+
|
1115
|
+
function CoffeeCodeGenerator() {
|
1116
|
+
this.outputBuffer = new haml.Buffer(this);
|
1117
|
+
}
|
1118
|
+
|
1119
|
+
CoffeeCodeGenerator.prototype.appendEmbeddedCode = function(indentText, expression, escapeContents, perserveWhitespace, currentParsePoint) {
|
1120
|
+
var indent;
|
1121
|
+
this.outputBuffer.flush();
|
1122
|
+
indent = this.calcCodeIndent();
|
1123
|
+
this.outputBuffer.appendToOutputBuffer(indent + "try\n");
|
1124
|
+
this.outputBuffer.appendToOutputBuffer(indent + " exp = CoffeeScript.compile('" + expression.replace(/'/g, "\\'").replace(/\\n/g, '\\\\n') + "', bare: true)\n");
|
1125
|
+
this.outputBuffer.appendToOutputBuffer(indent + " value = eval(exp)\n");
|
1126
|
+
this.outputBuffer.appendToOutputBuffer(indent + " value ?= ''\n");
|
1127
|
+
if (escapeContents) {
|
1128
|
+
this.outputBuffer.appendToOutputBuffer(indent + " html.push(haml.HamlRuntime.escapeHTML(String(value)))\n");
|
1129
|
+
} else if (perserveWhitespace) {
|
1130
|
+
this.outputBuffer.appendToOutputBuffer(indent + " html.push(haml.HamlRuntime.perserveWhitespace(String(value)))\n");
|
1131
|
+
} else {
|
1132
|
+
this.outputBuffer.appendToOutputBuffer(indent + " html.push(String(value))\n");
|
1133
|
+
}
|
1134
|
+
this.outputBuffer.appendToOutputBuffer(indent + "catch e \n");
|
1135
|
+
this.outputBuffer.appendToOutputBuffer(indent + " throw new Error(haml.HamlRuntime.templateError(" + currentParsePoint.lineNumber + ", " + currentParsePoint.characterNumber + ", '" + this.escapeCode(currentParsePoint.currentLine) + "',\n");
|
1136
|
+
return this.outputBuffer.appendToOutputBuffer(indent + " 'Error evaluating expression - ' + e))\n");
|
1137
|
+
};
|
1138
|
+
|
1139
|
+
CoffeeCodeGenerator.prototype.initOutput = function() {
|
1140
|
+
return this.outputBuffer.appendToOutputBuffer('html = []\n');
|
1141
|
+
};
|
1142
|
+
|
1143
|
+
CoffeeCodeGenerator.prototype.closeAndReturnOutput = function() {
|
1144
|
+
this.outputBuffer.flush();
|
1145
|
+
return this.outputBuffer.output() + 'return html.join("")\n';
|
1146
|
+
};
|
1147
|
+
|
1148
|
+
CoffeeCodeGenerator.prototype.appendCodeLine = function(line, eol) {
|
1149
|
+
this.outputBuffer.flush();
|
1150
|
+
this.outputBuffer.appendToOutputBuffer(this.calcCodeIndent());
|
1151
|
+
this.outputBuffer.appendToOutputBuffer((_.str || _).trim(line));
|
1152
|
+
this.outputBuffer.appendToOutputBuffer(eol);
|
1153
|
+
return this.prevCodeIndent = this.indent;
|
1154
|
+
};
|
1155
|
+
|
1156
|
+
CoffeeCodeGenerator.prototype.lineMatchesStartFunctionBlock = function(line) {
|
1157
|
+
return line.match(/\) [\-=]>\s*$/);
|
1158
|
+
};
|
1159
|
+
|
1160
|
+
CoffeeCodeGenerator.prototype.lineMatchesStartBlock = function(line) {
|
1161
|
+
return true;
|
1162
|
+
};
|
1163
|
+
|
1164
|
+
CoffeeCodeGenerator.prototype.closeOffCodeBlock = function(tokeniser) {
|
1165
|
+
return this.outputBuffer.flush();
|
1166
|
+
};
|
1167
|
+
|
1168
|
+
CoffeeCodeGenerator.prototype.closeOffFunctionBlock = function(tokeniser) {
|
1169
|
+
return this.outputBuffer.flush();
|
1170
|
+
};
|
1171
|
+
|
1172
|
+
CoffeeCodeGenerator.prototype.generateCodeForDynamicAttributes = function(id, classes, attributeList, attributeHash, objectRef, currentParsePoint) {
|
1173
|
+
var indent;
|
1174
|
+
this.outputBuffer.flush();
|
1175
|
+
indent = this.calcCodeIndent();
|
1176
|
+
if (attributeHash.length > 0) {
|
1177
|
+
attributeHash = this.replaceReservedWordsInHash(attributeHash);
|
1178
|
+
this.outputBuffer.appendToOutputBuffer(indent + "hashFunction = () -> s = CoffeeScript.compile('" + attributeHash.replace(/'/g, "\\'").replace(/\n/g, '\\n') + "', bare: true); eval 'hashObject = ' + s\n");
|
1179
|
+
}
|
1180
|
+
if (objectRef.length > 0) {
|
1181
|
+
this.outputBuffer.appendToOutputBuffer(indent + "objRefFn = () -> s = CoffeeScript.compile('" + objectRef.replace(/'/g, "\\'") + "', bare: true); eval 'objRef = ' + s\n");
|
1182
|
+
}
|
1183
|
+
return this.outputBuffer.appendToOutputBuffer(indent + "html.push(haml.HamlRuntime.generateElementAttributes(this, '" + id + "', ['" + classes.join("','") + "'], objRefFn ? null, " + JSON.stringify(attributeList) + ", hashFunction ? null, " + currentParsePoint.lineNumber + ", " + currentParsePoint.characterNumber + ", '" + this.escapeCode(currentParsePoint.currentLine) + "'))\n");
|
1184
|
+
};
|
1185
|
+
|
1186
|
+
CoffeeCodeGenerator.prototype.replaceReservedWordsInHash = function(hash) {
|
1187
|
+
var reservedWord, resultHash, _i, _len, _ref;
|
1188
|
+
resultHash = hash;
|
1189
|
+
_ref = ['class', 'for'];
|
1190
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
1191
|
+
reservedWord = _ref[_i];
|
1192
|
+
resultHash = resultHash.replace(reservedWord + ':', "'" + reservedWord + "':");
|
1193
|
+
}
|
1194
|
+
return resultHash;
|
1195
|
+
};
|
1196
|
+
|
1197
|
+
/*
|
1198
|
+
Escapes the string for insertion into the generated code. Embedded code blocks in strings must not be escaped
|
1199
|
+
*/
|
1200
|
+
|
1201
|
+
|
1202
|
+
CoffeeCodeGenerator.prototype.escapeCode = function(str) {
|
1203
|
+
var index, outString, precheedingChar, precheedingChar2, result;
|
1204
|
+
outString = '';
|
1205
|
+
index = 0;
|
1206
|
+
result = this.embeddedCodeBlockMatcher.exec(str);
|
1207
|
+
while (result) {
|
1208
|
+
if (result.index > 0) {
|
1209
|
+
precheedingChar = str.charAt(result.index - 1);
|
1210
|
+
}
|
1211
|
+
if (result.index > 1) {
|
1212
|
+
precheedingChar2 = str.charAt(result.index - 2);
|
1213
|
+
}
|
1214
|
+
if (precheedingChar === '\\' && precheedingChar2 !== '\\') {
|
1215
|
+
if (result.index !== 0) {
|
1216
|
+
outString += this._escapeText(str.substring(index, result.index - 1));
|
1217
|
+
}
|
1218
|
+
outString += this._escapeText('\\' + result[0]);
|
1219
|
+
} else {
|
1220
|
+
outString += this._escapeText(str.substring(index, result.index));
|
1221
|
+
outString += result[0];
|
1222
|
+
}
|
1223
|
+
index = this.embeddedCodeBlockMatcher.lastIndex;
|
1224
|
+
result = this.embeddedCodeBlockMatcher.exec(str);
|
1225
|
+
}
|
1226
|
+
if (index < str.length) {
|
1227
|
+
outString += this._escapeText(str.substring(index));
|
1228
|
+
}
|
1229
|
+
return outString;
|
1230
|
+
};
|
1231
|
+
|
1232
|
+
CoffeeCodeGenerator.prototype._escapeText = function(text) {
|
1233
|
+
return text.replace(/\\/g, '\\\\').replace(/'/g, '\\\'').replace(/"/g, '\\\"').replace(/\n/g, '\\n').replace(/(^|[^\\]{2})\\\\#{/g, '$1\\#{');
|
1234
|
+
};
|
1235
|
+
|
1236
|
+
/*
|
1237
|
+
Generates the javascript function by compiling the given code with coffeescript compiler
|
1238
|
+
*/
|
1239
|
+
|
1240
|
+
|
1241
|
+
CoffeeCodeGenerator.prototype.generateJsFunction = function(functionBody) {
|
1242
|
+
var fn;
|
1243
|
+
try {
|
1244
|
+
fn = CoffeeScript.compile(functionBody, {
|
1245
|
+
bare: true
|
1246
|
+
});
|
1247
|
+
return new Function(fn);
|
1248
|
+
} catch (e) {
|
1249
|
+
throw "Incorrect embedded code has resulted in an invalid Haml function - " + e + "\nGenerated Function:\n" + fn;
|
1250
|
+
}
|
1251
|
+
};
|
1252
|
+
|
1253
|
+
CoffeeCodeGenerator.prototype.generateFlush = function(bufferStr) {
|
1254
|
+
return this.calcCodeIndent() + "html.push('" + this.escapeCode(bufferStr) + "')\n";
|
1255
|
+
};
|
1256
|
+
|
1257
|
+
CoffeeCodeGenerator.prototype.setIndent = function(indent) {
|
1258
|
+
return this.indent = indent;
|
1259
|
+
};
|
1260
|
+
|
1261
|
+
CoffeeCodeGenerator.prototype.mark = function() {
|
1262
|
+
return this.prevIndent = this.indent;
|
1263
|
+
};
|
1264
|
+
|
1265
|
+
CoffeeCodeGenerator.prototype.calcCodeIndent = function() {
|
1266
|
+
var codeIndent, i, _i, _ref, _ref1, _ref2;
|
1267
|
+
codeIndent = 0;
|
1268
|
+
for (i = _i = 0, _ref = this.indent; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
|
1269
|
+
if (((_ref1 = this.elementStack[i]) != null ? _ref1.block : void 0) || ((_ref2 = this.elementStack[i]) != null ? _ref2.fnBlock : void 0)) {
|
1270
|
+
codeIndent += 1;
|
1271
|
+
}
|
1272
|
+
}
|
1273
|
+
return HamlRuntime.indentText(codeIndent);
|
1274
|
+
};
|
1275
|
+
|
1276
|
+
/*
|
1277
|
+
Append the text contents to the buffer (interpolating embedded code not required for coffeescript)
|
1278
|
+
*/
|
1279
|
+
|
1280
|
+
|
1281
|
+
CoffeeCodeGenerator.prototype.appendTextContents = function(text, shouldInterpolate, currentParsePoint, options) {
|
1282
|
+
var prefix, suffix;
|
1283
|
+
if (shouldInterpolate && text.match(/#{[^}]*}/)) {
|
1284
|
+
this.outputBuffer.flush();
|
1285
|
+
prefix = suffix = '';
|
1286
|
+
if (options != null ? options.escapeHTML : void 0) {
|
1287
|
+
prefix = 'haml.HamlRuntime.escapeHTML(';
|
1288
|
+
suffix = ')';
|
1289
|
+
} else if (options != null ? options.perserveWhitespace : void 0) {
|
1290
|
+
prefix = 'haml.HamlRuntime.perserveWhitespace(';
|
1291
|
+
suffix = ')';
|
1292
|
+
}
|
1293
|
+
return this.outputBuffer.appendToOutputBuffer(this.calcCodeIndent() + 'html.push(' + prefix + '"' + this.escapeCode(text) + '"' + suffix + ')\n');
|
1294
|
+
} else {
|
1295
|
+
if (options != null ? options.escapeHTML : void 0) {
|
1296
|
+
text = haml.HamlRuntime.escapeHTML(text);
|
1297
|
+
}
|
1298
|
+
if (options != null ? options.perserveWhitespace : void 0) {
|
1299
|
+
text = haml.HamlRuntime.perserveWhitespace(text);
|
1300
|
+
}
|
1301
|
+
return this.outputBuffer.append(text);
|
1302
|
+
}
|
1303
|
+
};
|
1304
|
+
|
1305
|
+
return CoffeeCodeGenerator;
|
1306
|
+
|
1307
|
+
})(CodeGenerator);
|
1308
|
+
|
1309
|
+
/*
|
1310
|
+
HAML filters are functions that take 3 parameters
|
1311
|
+
contents: The contents block for the filter an array of lines of text
|
1312
|
+
generator: The current generator for the compiled function
|
1313
|
+
indentText: A whitespace string specifying the current indent level
|
1314
|
+
currentParsePoint: line and character counters for the current parse point in the input buffer
|
1315
|
+
*/
|
1316
|
+
|
1317
|
+
|
1318
|
+
filters = {
|
1319
|
+
/*
|
1320
|
+
Plain filter, just renders the text in the block
|
1321
|
+
*/
|
1322
|
+
|
1323
|
+
plain: function(contents, generator, indentText, currentParsePoint) {
|
1324
|
+
var line, _i, _len;
|
1325
|
+
for (_i = 0, _len = contents.length; _i < _len; _i++) {
|
1326
|
+
line = contents[_i];
|
1327
|
+
generator.appendTextContents(indentText + line + '\n', true, currentParsePoint);
|
1328
|
+
}
|
1329
|
+
return true;
|
1330
|
+
},
|
1331
|
+
/*
|
1332
|
+
Wraps the filter block in a javascript tag
|
1333
|
+
*/
|
1334
|
+
|
1335
|
+
javascript: function(contents, generator, indentText, currentParsePoint) {
|
1336
|
+
var line, _i, _len;
|
1337
|
+
generator.outputBuffer.append(indentText + "<script type=\"text/javascript\">\n");
|
1338
|
+
generator.outputBuffer.append(indentText + "//<![CDATA[\n");
|
1339
|
+
for (_i = 0, _len = contents.length; _i < _len; _i++) {
|
1340
|
+
line = contents[_i];
|
1341
|
+
generator.appendTextContents(indentText + line + '\n', true, currentParsePoint);
|
1342
|
+
}
|
1343
|
+
generator.outputBuffer.append(indentText + "//]]>\n");
|
1344
|
+
return generator.outputBuffer.append(indentText + "</script>\n");
|
1345
|
+
},
|
1346
|
+
/*
|
1347
|
+
Wraps the filter block in a style tag
|
1348
|
+
*/
|
1349
|
+
|
1350
|
+
css: function(contents, generator, indentText, currentParsePoint) {
|
1351
|
+
var line, _i, _len;
|
1352
|
+
generator.outputBuffer.append(indentText + "<style type=\"text/css\">\n");
|
1353
|
+
generator.outputBuffer.append(indentText + "/*<![CDATA[*/\n");
|
1354
|
+
for (_i = 0, _len = contents.length; _i < _len; _i++) {
|
1355
|
+
line = contents[_i];
|
1356
|
+
generator.appendTextContents(indentText + line + '\n', true, currentParsePoint);
|
1357
|
+
}
|
1358
|
+
generator.outputBuffer.append(indentText + "/*]]>*/\n");
|
1359
|
+
return generator.outputBuffer.append(indentText + "</style>\n");
|
1360
|
+
},
|
1361
|
+
/*
|
1362
|
+
Wraps the filter block in a CDATA tag
|
1363
|
+
*/
|
1364
|
+
|
1365
|
+
cdata: function(contents, generator, indentText, currentParsePoint) {
|
1366
|
+
var line, _i, _len;
|
1367
|
+
generator.outputBuffer.append(indentText + "<![CDATA[\n");
|
1368
|
+
for (_i = 0, _len = contents.length; _i < _len; _i++) {
|
1369
|
+
line = contents[_i];
|
1370
|
+
generator.appendTextContents(indentText + line + '\n', true, currentParsePoint);
|
1371
|
+
}
|
1372
|
+
return generator.outputBuffer.append(indentText + "]]>\n");
|
1373
|
+
},
|
1374
|
+
/*
|
1375
|
+
Preserve filter, preserved blocks of text aren't indented, and newlines are replaced with the HTML escape code for newlines
|
1376
|
+
*/
|
1377
|
+
|
1378
|
+
preserve: function(contents, generator, indentText, currentParsePoint) {
|
1379
|
+
return generator.appendTextContents(contents.join('\n') + '\n', true, currentParsePoint, {
|
1380
|
+
perserveWhitespace: true
|
1381
|
+
});
|
1382
|
+
},
|
1383
|
+
/*
|
1384
|
+
Escape filter, renders the text in the block with html escaped
|
1385
|
+
*/
|
1386
|
+
|
1387
|
+
escape: function(contents, generator, indentText, currentParsePoint) {
|
1388
|
+
var line, _i, _len;
|
1389
|
+
for (_i = 0, _len = contents.length; _i < _len; _i++) {
|
1390
|
+
line = contents[_i];
|
1391
|
+
generator.appendTextContents(indentText + line + '\n', true, currentParsePoint, {
|
1392
|
+
escapeHTML: true
|
1393
|
+
});
|
1394
|
+
}
|
1395
|
+
return true;
|
1396
|
+
}
|
1397
|
+
};
|
1398
|
+
|
1399
|
+
/*
|
1400
|
+
Main haml compiler implemtation
|
1401
|
+
*/
|
1402
|
+
|
1403
|
+
|
1404
|
+
root.haml = {
|
1405
|
+
/*
|
1406
|
+
Compiles the haml provided in the parameters to a Javascipt function
|
1407
|
+
|
1408
|
+
Parameter:
|
1409
|
+
String: Looks for a haml template in dom with this ID
|
1410
|
+
Option Hash: The following options determines how haml sources and compiles the template
|
1411
|
+
source - This contains the template in string form
|
1412
|
+
sourceId - This contains the element ID in the dom which contains the haml source
|
1413
|
+
sourceUrl - This contains the URL where the template can be fetched from
|
1414
|
+
outputFormat - This determines what is returned, and has the following values:
|
1415
|
+
string - The javascript source code
|
1416
|
+
function - A javascript function (default)
|
1417
|
+
generator - Which code generator to use
|
1418
|
+
javascript (default)
|
1419
|
+
coffeescript
|
1420
|
+
productionjavascript
|
1421
|
+
|
1422
|
+
Returns a javascript function
|
1423
|
+
*/
|
1424
|
+
|
1425
|
+
compileHaml: function(options) {
|
1426
|
+
var codeGenerator, result, tokinser;
|
1427
|
+
if (typeof options === 'string') {
|
1428
|
+
return this._compileHamlTemplate(options, new haml.JsCodeGenerator());
|
1429
|
+
} else {
|
1430
|
+
codeGenerator = (function() {
|
1431
|
+
switch (options.generator) {
|
1432
|
+
case 'coffeescript':
|
1433
|
+
return new haml.CoffeeCodeGenerator();
|
1434
|
+
case 'productionjavascript':
|
1435
|
+
return new haml.ProductionJsCodeGenerator();
|
1436
|
+
default:
|
1437
|
+
return new haml.JsCodeGenerator();
|
1438
|
+
}
|
1439
|
+
})();
|
1440
|
+
if (options.source != null) {
|
1441
|
+
tokinser = new haml.Tokeniser({
|
1442
|
+
template: options.source
|
1443
|
+
});
|
1444
|
+
} else if (options.sourceId != null) {
|
1445
|
+
tokinser = new haml.Tokeniser({
|
1446
|
+
templateId: options.sourceId
|
1447
|
+
});
|
1448
|
+
} else if (options.sourceUrl != null) {
|
1449
|
+
tokinser = new haml.Tokeniser({
|
1450
|
+
templateUrl: options.sourceUrl
|
1451
|
+
});
|
1452
|
+
} else {
|
1453
|
+
throw "No template source specified for compileHaml. You need to provide a source, sourceId or sourceUrl option";
|
1454
|
+
}
|
1455
|
+
result = this._compileHamlToJs(tokinser, codeGenerator);
|
1456
|
+
if (options.outputFormat !== 'string') {
|
1457
|
+
return codeGenerator.generateJsFunction(result);
|
1458
|
+
} else {
|
1459
|
+
return "function (context) {\n" + result + "}\n";
|
1460
|
+
}
|
1461
|
+
}
|
1462
|
+
},
|
1463
|
+
/*
|
1464
|
+
Compiles the haml in the script block with ID templateId using the coffeescript generator
|
1465
|
+
Returns a javascript function
|
1466
|
+
*/
|
1467
|
+
|
1468
|
+
compileCoffeeHaml: function(templateId) {
|
1469
|
+
return this._compileHamlTemplate(templateId, new haml.CoffeeCodeGenerator());
|
1470
|
+
},
|
1471
|
+
/*
|
1472
|
+
Compiles the haml in the passed in string
|
1473
|
+
Returns a javascript function
|
1474
|
+
*/
|
1475
|
+
|
1476
|
+
compileStringToJs: function(string) {
|
1477
|
+
var codeGenerator, result;
|
1478
|
+
codeGenerator = new haml.JsCodeGenerator();
|
1479
|
+
result = this._compileHamlToJs(new haml.Tokeniser({
|
1480
|
+
template: string
|
1481
|
+
}), codeGenerator);
|
1482
|
+
return codeGenerator.generateJsFunction(result);
|
1483
|
+
},
|
1484
|
+
/*
|
1485
|
+
Compiles the haml in the passed in string using the coffeescript generator
|
1486
|
+
Returns a javascript function
|
1487
|
+
*/
|
1488
|
+
|
1489
|
+
compileCoffeeHamlFromString: function(string) {
|
1490
|
+
var codeGenerator, result;
|
1491
|
+
codeGenerator = new haml.CoffeeCodeGenerator();
|
1492
|
+
result = this._compileHamlToJs(new haml.Tokeniser({
|
1493
|
+
template: string
|
1494
|
+
}), codeGenerator);
|
1495
|
+
return codeGenerator.generateJsFunction(result);
|
1496
|
+
},
|
1497
|
+
/*
|
1498
|
+
Compiles the haml in the passed in string
|
1499
|
+
Returns the javascript function source
|
1500
|
+
|
1501
|
+
This is mainly used for precompiling the haml templates so they can be packaged.
|
1502
|
+
*/
|
1503
|
+
|
1504
|
+
compileHamlToJsString: function(string) {
|
1505
|
+
var result;
|
1506
|
+
result = 'function (context) {\n';
|
1507
|
+
result += this._compileHamlToJs(new haml.Tokeniser({
|
1508
|
+
template: string
|
1509
|
+
}), new haml.JsCodeGenerator());
|
1510
|
+
return result += '}\n';
|
1511
|
+
},
|
1512
|
+
_compileHamlTemplate: function(templateId, codeGenerator) {
|
1513
|
+
var fn, result;
|
1514
|
+
haml.cache || (haml.cache = {});
|
1515
|
+
if (haml.cache[templateId]) {
|
1516
|
+
return haml.cache[templateId];
|
1517
|
+
}
|
1518
|
+
result = this._compileHamlToJs(new haml.Tokeniser({
|
1519
|
+
templateId: templateId
|
1520
|
+
}), codeGenerator);
|
1521
|
+
fn = codeGenerator.generateJsFunction(result);
|
1522
|
+
haml.cache[templateId] = fn;
|
1523
|
+
return fn;
|
1524
|
+
},
|
1525
|
+
_compileHamlToJs: function(tokeniser, generator) {
|
1526
|
+
var indent;
|
1527
|
+
generator.elementStack = [];
|
1528
|
+
generator.initOutput();
|
1529
|
+
tokeniser.getNextToken();
|
1530
|
+
while (!tokeniser.token.eof) {
|
1531
|
+
if (!tokeniser.token.eol) {
|
1532
|
+
indent = this._whitespace(tokeniser);
|
1533
|
+
generator.setIndent(indent);
|
1534
|
+
if (tokeniser.token.eol) {
|
1535
|
+
generator.outputBuffer.append(HamlRuntime.indentText(indent) + tokeniser.token.matched);
|
1536
|
+
tokeniser.getNextToken();
|
1537
|
+
} else if (tokeniser.token.doctype) {
|
1538
|
+
this._doctype(tokeniser, indent, generator);
|
1539
|
+
} else if (tokeniser.token.exclamation) {
|
1540
|
+
this._ignoredLine(tokeniser, indent, generator.elementStack, generator);
|
1541
|
+
} else if (tokeniser.token.equal || tokeniser.token.escapeHtml || tokeniser.token.unescapeHtml || tokeniser.token.tilde) {
|
1542
|
+
this._embeddedJs(tokeniser, indent, generator.elementStack, {
|
1543
|
+
innerWhitespace: true
|
1544
|
+
}, generator);
|
1545
|
+
} else if (tokeniser.token.minus) {
|
1546
|
+
this._jsLine(tokeniser, indent, generator.elementStack, generator);
|
1547
|
+
} else if (tokeniser.token.comment || tokeniser.token.slash) {
|
1548
|
+
this._commentLine(tokeniser, indent, generator.elementStack, generator);
|
1549
|
+
} else if (tokeniser.token.amp) {
|
1550
|
+
this._escapedLine(tokeniser, indent, generator.elementStack, generator);
|
1551
|
+
} else if (tokeniser.token.filter) {
|
1552
|
+
this._filter(tokeniser, indent, generator);
|
1553
|
+
} else {
|
1554
|
+
this._templateLine(tokeniser, generator.elementStack, indent, generator);
|
1555
|
+
}
|
1556
|
+
} else {
|
1557
|
+
generator.outputBuffer.append(tokeniser.token.matched);
|
1558
|
+
tokeniser.getNextToken();
|
1559
|
+
}
|
1560
|
+
}
|
1561
|
+
this._closeElements(0, generator.elementStack, tokeniser, generator);
|
1562
|
+
return generator.closeAndReturnOutput();
|
1563
|
+
},
|
1564
|
+
_doctype: function(tokeniser, indent, generator) {
|
1565
|
+
var contents, params;
|
1566
|
+
if (tokeniser.token.doctype) {
|
1567
|
+
generator.outputBuffer.append(HamlRuntime.indentText(indent));
|
1568
|
+
tokeniser.getNextToken();
|
1569
|
+
if (tokeniser.token.ws) {
|
1570
|
+
tokeniser.getNextToken();
|
1571
|
+
}
|
1572
|
+
contents = tokeniser.skipToEOLorEOF();
|
1573
|
+
if (contents && contents.length > 0) {
|
1574
|
+
params = contents.split(/\s+/);
|
1575
|
+
switch (params[0]) {
|
1576
|
+
case 'XML':
|
1577
|
+
if (params.length > 1) {
|
1578
|
+
generator.outputBuffer.append("<?xml version='1.0' encoding='" + params[1] + "' ?>");
|
1579
|
+
} else {
|
1580
|
+
generator.outputBuffer.append("<?xml version='1.0' encoding='utf-8' ?>");
|
1581
|
+
}
|
1582
|
+
break;
|
1583
|
+
case 'Strict':
|
1584
|
+
generator.outputBuffer.append('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">');
|
1585
|
+
break;
|
1586
|
+
case 'Frameset':
|
1587
|
+
generator.outputBuffer.append('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">');
|
1588
|
+
break;
|
1589
|
+
case '5':
|
1590
|
+
generator.outputBuffer.append('<!DOCTYPE html>');
|
1591
|
+
break;
|
1592
|
+
case '1.1':
|
1593
|
+
generator.outputBuffer.append('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">');
|
1594
|
+
break;
|
1595
|
+
case 'Basic':
|
1596
|
+
generator.outputBuffer.append('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">');
|
1597
|
+
break;
|
1598
|
+
case 'Mobile':
|
1599
|
+
generator.outputBuffer.append('<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">');
|
1600
|
+
break;
|
1601
|
+
case 'RDFa':
|
1602
|
+
generator.outputBuffer.append('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">');
|
1603
|
+
}
|
1604
|
+
} else {
|
1605
|
+
generator.outputBuffer.append('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');
|
1606
|
+
}
|
1607
|
+
generator.outputBuffer.append(this._newline(tokeniser));
|
1608
|
+
return tokeniser.getNextToken();
|
1609
|
+
}
|
1610
|
+
},
|
1611
|
+
_filter: function(tokeniser, indent, generator) {
|
1612
|
+
var filter, filterBlock, i, line;
|
1613
|
+
if (tokeniser.token.filter) {
|
1614
|
+
filter = tokeniser.token.tokenString;
|
1615
|
+
if (!haml.filters[filter]) {
|
1616
|
+
throw tokeniser.parseError("Filter '" + filter + "' not registered. Filter functions need to be added to 'haml.filters'.");
|
1617
|
+
}
|
1618
|
+
tokeniser.skipToEOLorEOF();
|
1619
|
+
tokeniser.getNextToken();
|
1620
|
+
i = haml._whitespace(tokeniser);
|
1621
|
+
filterBlock = [];
|
1622
|
+
while (!tokeniser.token.eof && i > indent) {
|
1623
|
+
line = tokeniser.skipToEOLorEOF();
|
1624
|
+
filterBlock.push(haml.HamlRuntime.indentText(i - indent - 1) + line);
|
1625
|
+
tokeniser.getNextToken();
|
1626
|
+
i = haml._whitespace(tokeniser);
|
1627
|
+
}
|
1628
|
+
haml.filters[filter](filterBlock, generator, haml.HamlRuntime.indentText(indent), tokeniser.currentParsePoint());
|
1629
|
+
return tokeniser.pushBackToken();
|
1630
|
+
}
|
1631
|
+
},
|
1632
|
+
_commentLine: function(tokeniser, indent, elementStack, generator) {
|
1633
|
+
var contents, i;
|
1634
|
+
if (tokeniser.token.comment) {
|
1635
|
+
tokeniser.skipToEOLorEOF();
|
1636
|
+
tokeniser.getNextToken();
|
1637
|
+
i = this._whitespace(tokeniser);
|
1638
|
+
while (!tokeniser.token.eof && i > indent) {
|
1639
|
+
tokeniser.skipToEOLorEOF();
|
1640
|
+
tokeniser.getNextToken();
|
1641
|
+
i = this._whitespace(tokeniser);
|
1642
|
+
}
|
1643
|
+
if (i > 0) {
|
1644
|
+
return tokeniser.pushBackToken();
|
1645
|
+
}
|
1646
|
+
} else if (tokeniser.token.slash) {
|
1647
|
+
haml._closeElements(indent, elementStack, tokeniser, generator);
|
1648
|
+
generator.outputBuffer.append(HamlRuntime.indentText(indent));
|
1649
|
+
generator.outputBuffer.append("<!--");
|
1650
|
+
tokeniser.getNextToken();
|
1651
|
+
contents = tokeniser.skipToEOLorEOF();
|
1652
|
+
if (contents && contents.length > 0) {
|
1653
|
+
generator.outputBuffer.append(contents);
|
1654
|
+
}
|
1655
|
+
if (contents && (_.str || _).startsWith(contents, '[') && contents.match(/\]\s*$/)) {
|
1656
|
+
elementStack[indent] = {
|
1657
|
+
htmlConditionalComment: true,
|
1658
|
+
eol: this._newline(tokeniser)
|
1659
|
+
};
|
1660
|
+
generator.outputBuffer.append(">");
|
1661
|
+
} else {
|
1662
|
+
elementStack[indent] = {
|
1663
|
+
htmlComment: true,
|
1664
|
+
eol: this._newline(tokeniser)
|
1665
|
+
};
|
1666
|
+
}
|
1667
|
+
if (haml._tagHasContents(indent, tokeniser)) {
|
1668
|
+
generator.outputBuffer.append("\n");
|
1669
|
+
}
|
1670
|
+
return tokeniser.getNextToken();
|
1671
|
+
}
|
1672
|
+
},
|
1673
|
+
_escapedLine: function(tokeniser, indent, elementStack, generator) {
|
1674
|
+
var contents;
|
1675
|
+
if (tokeniser.token.amp) {
|
1676
|
+
haml._closeElements(indent, elementStack, tokeniser, generator);
|
1677
|
+
generator.outputBuffer.append(HamlRuntime.indentText(indent));
|
1678
|
+
tokeniser.getNextToken();
|
1679
|
+
contents = tokeniser.skipToEOLorEOF();
|
1680
|
+
if (contents && contents.length > 0) {
|
1681
|
+
generator.outputBuffer.append(haml.HamlRuntime.escapeHTML(contents));
|
1682
|
+
}
|
1683
|
+
generator.outputBuffer.append(this._newline(tokeniser));
|
1684
|
+
return tokeniser.getNextToken();
|
1685
|
+
}
|
1686
|
+
},
|
1687
|
+
_ignoredLine: function(tokeniser, indent, elementStack, generator) {
|
1688
|
+
var contents;
|
1689
|
+
if (tokeniser.token.exclamation) {
|
1690
|
+
tokeniser.getNextToken();
|
1691
|
+
if (tokeniser.token.ws) {
|
1692
|
+
indent += haml._whitespace(tokeniser);
|
1693
|
+
}
|
1694
|
+
haml._closeElements(indent, elementStack, tokeniser, generator);
|
1695
|
+
contents = tokeniser.skipToEOLorEOF();
|
1696
|
+
return generator.outputBuffer.append(HamlRuntime.indentText(indent) + contents);
|
1697
|
+
}
|
1698
|
+
},
|
1699
|
+
_embeddedJs: function(tokeniser, indent, elementStack, tagOptions, generator) {
|
1700
|
+
var currentParsePoint, escapeHtml, expression, indentText, perserveWhitespace;
|
1701
|
+
if (elementStack) {
|
1702
|
+
haml._closeElements(indent, elementStack, tokeniser, generator);
|
1703
|
+
}
|
1704
|
+
if (tokeniser.token.equal || tokeniser.token.escapeHtml || tokeniser.token.unescapeHtml || tokeniser.token.tilde) {
|
1705
|
+
escapeHtml = tokeniser.token.escapeHtml || tokeniser.token.equal;
|
1706
|
+
perserveWhitespace = tokeniser.token.tilde;
|
1707
|
+
currentParsePoint = tokeniser.currentParsePoint();
|
1708
|
+
tokeniser.getNextToken();
|
1709
|
+
expression = tokeniser.skipToEOLorEOF();
|
1710
|
+
indentText = HamlRuntime.indentText(indent);
|
1711
|
+
if (!tagOptions || tagOptions.innerWhitespace) {
|
1712
|
+
generator.outputBuffer.append(indentText);
|
1713
|
+
}
|
1714
|
+
generator.appendEmbeddedCode(indentText, expression, escapeHtml, perserveWhitespace, currentParsePoint);
|
1715
|
+
if (!tagOptions || tagOptions.innerWhitespace) {
|
1716
|
+
generator.outputBuffer.append(this._newline(tokeniser));
|
1717
|
+
if (tokeniser.token.eol) {
|
1718
|
+
return tokeniser.getNextToken();
|
1719
|
+
}
|
1720
|
+
}
|
1721
|
+
}
|
1722
|
+
},
|
1723
|
+
_jsLine: function(tokeniser, indent, elementStack, generator) {
|
1724
|
+
var line;
|
1725
|
+
if (tokeniser.token.minus) {
|
1726
|
+
haml._closeElements(indent, elementStack, tokeniser, generator);
|
1727
|
+
tokeniser.getNextToken();
|
1728
|
+
line = tokeniser.skipToEOLorEOF();
|
1729
|
+
generator.setIndent(indent);
|
1730
|
+
generator.appendCodeLine(line, this._newline(tokeniser));
|
1731
|
+
if (tokeniser.token.eol) {
|
1732
|
+
tokeniser.getNextToken();
|
1733
|
+
}
|
1734
|
+
if (generator.lineMatchesStartFunctionBlock(line)) {
|
1735
|
+
return elementStack[indent] = {
|
1736
|
+
fnBlock: true
|
1737
|
+
};
|
1738
|
+
} else if (generator.lineMatchesStartBlock(line)) {
|
1739
|
+
return elementStack[indent] = {
|
1740
|
+
block: true
|
1741
|
+
};
|
1742
|
+
}
|
1743
|
+
}
|
1744
|
+
},
|
1745
|
+
_templateLine: function(tokeniser, elementStack, indent, generator) {
|
1746
|
+
var attrList, attributesHash, classes, contents, currentParsePoint, hasContents, id, identifier, indentText, lineHasElement, objectRef, shouldInterpolate, tagOptions;
|
1747
|
+
if (!tokeniser.token.eol) {
|
1748
|
+
this._closeElements(indent, elementStack, tokeniser, generator);
|
1749
|
+
}
|
1750
|
+
identifier = this._element(tokeniser);
|
1751
|
+
id = this._idSelector(tokeniser);
|
1752
|
+
classes = this._classSelector(tokeniser);
|
1753
|
+
objectRef = this._objectReference(tokeniser);
|
1754
|
+
attrList = this._attributeList(tokeniser);
|
1755
|
+
currentParsePoint = tokeniser.currentParsePoint();
|
1756
|
+
attributesHash = this._attributeHash(tokeniser);
|
1757
|
+
tagOptions = {
|
1758
|
+
selfClosingTag: false,
|
1759
|
+
innerWhitespace: true,
|
1760
|
+
outerWhitespace: true
|
1761
|
+
};
|
1762
|
+
lineHasElement = this._lineHasElement(identifier, id, classes);
|
1763
|
+
if (tokeniser.token.slash) {
|
1764
|
+
tagOptions.selfClosingTag = true;
|
1765
|
+
tokeniser.getNextToken();
|
1766
|
+
}
|
1767
|
+
if (tokeniser.token.gt && lineHasElement) {
|
1768
|
+
tagOptions.outerWhitespace = false;
|
1769
|
+
tokeniser.getNextToken();
|
1770
|
+
}
|
1771
|
+
if (tokeniser.token.lt && lineHasElement) {
|
1772
|
+
tagOptions.innerWhitespace = false;
|
1773
|
+
tokeniser.getNextToken();
|
1774
|
+
}
|
1775
|
+
if (lineHasElement) {
|
1776
|
+
if (!tagOptions.selfClosingTag) {
|
1777
|
+
tagOptions.selfClosingTag = haml._isSelfClosingTag(identifier) && !haml._tagHasContents(indent, tokeniser);
|
1778
|
+
}
|
1779
|
+
this._openElement(currentParsePoint, indent, identifier, id, classes, objectRef, attrList, attributesHash, elementStack, tagOptions, generator);
|
1780
|
+
}
|
1781
|
+
hasContents = false;
|
1782
|
+
if (tokeniser.token.ws) {
|
1783
|
+
tokeniser.getNextToken();
|
1784
|
+
}
|
1785
|
+
if (tokeniser.token.equal || tokeniser.token.escapeHtml || tokeniser.token.unescapeHtml) {
|
1786
|
+
this._embeddedJs(tokeniser, indent + 1, null, tagOptions, generator);
|
1787
|
+
hasContents = true;
|
1788
|
+
} else {
|
1789
|
+
contents = '';
|
1790
|
+
shouldInterpolate = false;
|
1791
|
+
if (tokeniser.token.exclamation) {
|
1792
|
+
tokeniser.getNextToken();
|
1793
|
+
contents = tokeniser.skipToEOLorEOF();
|
1794
|
+
} else {
|
1795
|
+
contents = tokeniser.skipToEOLorEOF();
|
1796
|
+
if (contents.match(/^\\/)) {
|
1797
|
+
contents = contents.substring(1);
|
1798
|
+
}
|
1799
|
+
shouldInterpolate = true;
|
1800
|
+
}
|
1801
|
+
hasContents = contents.length > 0;
|
1802
|
+
if (hasContents) {
|
1803
|
+
if (tagOptions.innerWhitespace && lineHasElement || (!lineHasElement && haml._parentInnerWhitespace(elementStack, indent))) {
|
1804
|
+
indentText = HamlRuntime.indentText(identifier.length > 0 ? indent + 1 : indent);
|
1805
|
+
} else {
|
1806
|
+
indentText = '';
|
1807
|
+
contents = (_.str || _).trim(contents);
|
1808
|
+
}
|
1809
|
+
generator.appendTextContents(indentText + contents, shouldInterpolate, currentParsePoint);
|
1810
|
+
generator.outputBuffer.append(this._newline(tokeniser));
|
1811
|
+
}
|
1812
|
+
this._eolOrEof(tokeniser);
|
1813
|
+
}
|
1814
|
+
if (tagOptions.selfClosingTag && hasContents) {
|
1815
|
+
throw haml.HamlRuntime.templateError(currentParsePoint.lineNumber, currentParsePoint.characterNumber, currentParsePoint.currentLine, "A self-closing tag can not have any contents");
|
1816
|
+
}
|
1817
|
+
},
|
1818
|
+
_attributeHash: function(tokeniser) {
|
1819
|
+
var attr;
|
1820
|
+
attr = '';
|
1821
|
+
if (tokeniser.token.attributeHash) {
|
1822
|
+
attr = tokeniser.token.tokenString;
|
1823
|
+
tokeniser.getNextToken();
|
1824
|
+
}
|
1825
|
+
return attr;
|
1826
|
+
},
|
1827
|
+
_objectReference: function(tokeniser) {
|
1828
|
+
var attr;
|
1829
|
+
attr = '';
|
1830
|
+
if (tokeniser.token.objectReference) {
|
1831
|
+
attr = tokeniser.token.tokenString;
|
1832
|
+
tokeniser.getNextToken();
|
1833
|
+
}
|
1834
|
+
return attr;
|
1835
|
+
},
|
1836
|
+
_attributeList: function(tokeniser) {
|
1837
|
+
var attr, attrList;
|
1838
|
+
attrList = {};
|
1839
|
+
if (tokeniser.token.openBracket) {
|
1840
|
+
tokeniser.getNextToken();
|
1841
|
+
while (!tokeniser.token.closeBracket) {
|
1842
|
+
attr = haml._attribute(tokeniser);
|
1843
|
+
if (attr) {
|
1844
|
+
attrList[attr.name] = attr.value;
|
1845
|
+
} else {
|
1846
|
+
tokeniser.getNextToken();
|
1847
|
+
}
|
1848
|
+
if (tokeniser.token.ws || tokeniser.token.eol) {
|
1849
|
+
tokeniser.getNextToken();
|
1850
|
+
} else if (!tokeniser.token.closeBracket && !tokeniser.token.identifier) {
|
1851
|
+
throw tokeniser.parseError("Expecting either an attribute name to continue the attibutes or a closing " + "bracket to end");
|
1852
|
+
}
|
1853
|
+
}
|
1854
|
+
tokeniser.getNextToken();
|
1855
|
+
}
|
1856
|
+
return attrList;
|
1857
|
+
},
|
1858
|
+
_attribute: function(tokeniser) {
|
1859
|
+
var attr, name;
|
1860
|
+
attr = null;
|
1861
|
+
if (tokeniser.token.identifier) {
|
1862
|
+
name = tokeniser.token.tokenString;
|
1863
|
+
tokeniser.getNextToken();
|
1864
|
+
haml._whitespace(tokeniser);
|
1865
|
+
if (!tokeniser.token.equal) {
|
1866
|
+
throw tokeniser.parseError("Expected '=' after attribute name");
|
1867
|
+
}
|
1868
|
+
tokeniser.getNextToken();
|
1869
|
+
haml._whitespace(tokeniser);
|
1870
|
+
if (!tokeniser.token.string && !tokeniser.token.identifier) {
|
1871
|
+
throw tokeniser.parseError("Expected a quoted string or an identifier for the attribute value");
|
1872
|
+
}
|
1873
|
+
attr = {
|
1874
|
+
name: name,
|
1875
|
+
value: tokeniser.token.tokenString
|
1876
|
+
};
|
1877
|
+
tokeniser.getNextToken();
|
1878
|
+
}
|
1879
|
+
return attr;
|
1880
|
+
},
|
1881
|
+
_closeElement: function(indent, elementStack, tokeniser, generator) {
|
1882
|
+
var innerWhitespace, outerWhitespace;
|
1883
|
+
if (elementStack[indent]) {
|
1884
|
+
generator.setIndent(indent);
|
1885
|
+
if (elementStack[indent].htmlComment) {
|
1886
|
+
generator.outputBuffer.append(HamlRuntime.indentText(indent) + '-->' + elementStack[indent].eol);
|
1887
|
+
} else if (elementStack[indent].htmlConditionalComment) {
|
1888
|
+
generator.outputBuffer.append(HamlRuntime.indentText(indent) + '<![endif]-->' + elementStack[indent].eol);
|
1889
|
+
} else if (elementStack[indent].block) {
|
1890
|
+
generator.closeOffCodeBlock(tokeniser);
|
1891
|
+
} else if (elementStack[indent].fnBlock) {
|
1892
|
+
generator.closeOffFunctionBlock(tokeniser);
|
1893
|
+
} else {
|
1894
|
+
innerWhitespace = !elementStack[indent].tagOptions || elementStack[indent].tagOptions.innerWhitespace;
|
1895
|
+
if (innerWhitespace) {
|
1896
|
+
generator.outputBuffer.append(HamlRuntime.indentText(indent));
|
1897
|
+
} else {
|
1898
|
+
generator.outputBuffer.trimWhitespace();
|
1899
|
+
}
|
1900
|
+
generator.outputBuffer.append('</' + elementStack[indent].tag + '>');
|
1901
|
+
outerWhitespace = !elementStack[indent].tagOptions || elementStack[indent].tagOptions.outerWhitespace;
|
1902
|
+
if (haml._parentInnerWhitespace(elementStack, indent) && outerWhitespace) {
|
1903
|
+
generator.outputBuffer.append('\n');
|
1904
|
+
}
|
1905
|
+
}
|
1906
|
+
elementStack[indent] = null;
|
1907
|
+
return generator.mark();
|
1908
|
+
}
|
1909
|
+
},
|
1910
|
+
_closeElements: function(indent, elementStack, tokeniser, generator) {
|
1911
|
+
var i, _results;
|
1912
|
+
i = elementStack.length - 1;
|
1913
|
+
_results = [];
|
1914
|
+
while (i >= indent) {
|
1915
|
+
_results.push(this._closeElement(i--, elementStack, tokeniser, generator));
|
1916
|
+
}
|
1917
|
+
return _results;
|
1918
|
+
},
|
1919
|
+
_openElement: function(currentParsePoint, indent, identifier, id, classes, objectRef, attributeList, attributeHash, elementStack, tagOptions, generator) {
|
1920
|
+
var element, parentInnerWhitespace, tagOuterWhitespace;
|
1921
|
+
element = identifier.length === 0 ? "div" : identifier;
|
1922
|
+
parentInnerWhitespace = this._parentInnerWhitespace(elementStack, indent);
|
1923
|
+
tagOuterWhitespace = !tagOptions || tagOptions.outerWhitespace;
|
1924
|
+
if (!tagOuterWhitespace) {
|
1925
|
+
generator.outputBuffer.trimWhitespace();
|
1926
|
+
}
|
1927
|
+
if (indent > 0 && parentInnerWhitespace && tagOuterWhitespace) {
|
1928
|
+
generator.outputBuffer.append(HamlRuntime.indentText(indent));
|
1929
|
+
}
|
1930
|
+
generator.outputBuffer.append('<' + element);
|
1931
|
+
if (attributeHash.length > 0 || objectRef.length > 0) {
|
1932
|
+
generator.generateCodeForDynamicAttributes(id, classes, attributeList, attributeHash, objectRef, currentParsePoint);
|
1933
|
+
} else {
|
1934
|
+
generator.outputBuffer.append(HamlRuntime.generateElementAttributes(null, id, classes, null, attributeList, null, currentParsePoint.lineNumber, currentParsePoint.characterNumber, currentParsePoint.currentLine));
|
1935
|
+
}
|
1936
|
+
if (tagOptions.selfClosingTag) {
|
1937
|
+
generator.outputBuffer.append("/>");
|
1938
|
+
if (tagOptions.outerWhitespace) {
|
1939
|
+
return generator.outputBuffer.append("\n");
|
1940
|
+
}
|
1941
|
+
} else {
|
1942
|
+
generator.outputBuffer.append(">");
|
1943
|
+
elementStack[indent] = {
|
1944
|
+
tag: element,
|
1945
|
+
tagOptions: tagOptions
|
1946
|
+
};
|
1947
|
+
if (tagOptions.innerWhitespace) {
|
1948
|
+
return generator.outputBuffer.append("\n");
|
1949
|
+
}
|
1950
|
+
}
|
1951
|
+
},
|
1952
|
+
_isSelfClosingTag: function(tag) {
|
1953
|
+
return tag === 'meta' || tag === 'img' || tag === 'link' || tag === 'script' || tag === 'br' || tag === 'hr';
|
1954
|
+
},
|
1955
|
+
_tagHasContents: function(indent, tokeniser) {
|
1956
|
+
var nextToken;
|
1957
|
+
if (!tokeniser.isEolOrEof()) {
|
1958
|
+
return true;
|
1959
|
+
} else {
|
1960
|
+
nextToken = tokeniser.lookAhead(1);
|
1961
|
+
return nextToken.ws && nextToken.tokenString.length / 2 > indent;
|
1962
|
+
}
|
1963
|
+
},
|
1964
|
+
_parentInnerWhitespace: function(elementStack, indent) {
|
1965
|
+
return indent === 0 || (!elementStack[indent - 1] || !elementStack[indent - 1].tagOptions || elementStack[indent - 1].tagOptions.innerWhitespace);
|
1966
|
+
},
|
1967
|
+
_lineHasElement: function(identifier, id, classes) {
|
1968
|
+
return identifier.length > 0 || id.length > 0 || classes.length > 0;
|
1969
|
+
},
|
1970
|
+
hasValue: function(value) {
|
1971
|
+
return (value != null) && value !== false;
|
1972
|
+
},
|
1973
|
+
attrValue: function(attr, value) {
|
1974
|
+
if (attr === 'selected' || attr === 'checked' || attr === 'disabled') {
|
1975
|
+
return attr;
|
1976
|
+
} else {
|
1977
|
+
return value;
|
1978
|
+
}
|
1979
|
+
},
|
1980
|
+
_whitespace: function(tokeniser) {
|
1981
|
+
var i, indent, whitespace;
|
1982
|
+
indent = 0;
|
1983
|
+
if (tokeniser.token.ws) {
|
1984
|
+
i = 0;
|
1985
|
+
whitespace = tokeniser.token.tokenString;
|
1986
|
+
while (i < whitespace.length) {
|
1987
|
+
if (whitespace.charCodeAt(i) === 9 && i % 2 === 0) {
|
1988
|
+
indent += 2;
|
1989
|
+
} else {
|
1990
|
+
indent++;
|
1991
|
+
}
|
1992
|
+
i++;
|
1993
|
+
}
|
1994
|
+
indent = Math.floor((indent + 1) / 2);
|
1995
|
+
tokeniser.getNextToken();
|
1996
|
+
}
|
1997
|
+
return indent;
|
1998
|
+
},
|
1999
|
+
_element: function(tokeniser) {
|
2000
|
+
var identifier;
|
2001
|
+
identifier = '';
|
2002
|
+
if (tokeniser.token.element) {
|
2003
|
+
identifier = tokeniser.token.tokenString;
|
2004
|
+
tokeniser.getNextToken();
|
2005
|
+
}
|
2006
|
+
return identifier;
|
2007
|
+
},
|
2008
|
+
_eolOrEof: function(tokeniser) {
|
2009
|
+
if (tokeniser.token.eol || tokeniser.token.continueLine) {
|
2010
|
+
return tokeniser.getNextToken();
|
2011
|
+
} else if (!tokeniser.token.eof) {
|
2012
|
+
throw tokeniser.parseError("Expected EOL or EOF");
|
2013
|
+
}
|
2014
|
+
},
|
2015
|
+
_idSelector: function(tokeniser) {
|
2016
|
+
var id;
|
2017
|
+
id = '';
|
2018
|
+
if (tokeniser.token.idSelector) {
|
2019
|
+
id = tokeniser.token.tokenString;
|
2020
|
+
tokeniser.getNextToken();
|
2021
|
+
}
|
2022
|
+
return id;
|
2023
|
+
},
|
2024
|
+
_classSelector: function(tokeniser) {
|
2025
|
+
var classes;
|
2026
|
+
classes = [];
|
2027
|
+
while (tokeniser.token.classSelector) {
|
2028
|
+
classes.push(tokeniser.token.tokenString);
|
2029
|
+
tokeniser.getNextToken();
|
2030
|
+
}
|
2031
|
+
return classes;
|
2032
|
+
},
|
2033
|
+
_newline: function(tokeniser) {
|
2034
|
+
if (tokeniser.token.eol) {
|
2035
|
+
return tokeniser.token.matched;
|
2036
|
+
} else if (tokeniser.token.continueLine) {
|
2037
|
+
return tokeniser.token.matched.substring(1);
|
2038
|
+
} else {
|
2039
|
+
return "\n";
|
2040
|
+
}
|
2041
|
+
}
|
2042
|
+
};
|
2043
|
+
|
2044
|
+
root.haml.Tokeniser = Tokeniser;
|
2045
|
+
|
2046
|
+
root.haml.Buffer = Buffer;
|
2047
|
+
|
2048
|
+
root.haml.JsCodeGenerator = JsCodeGenerator;
|
2049
|
+
|
2050
|
+
root.haml.ProductionJsCodeGenerator = ProductionJsCodeGenerator;
|
2051
|
+
|
2052
|
+
root.haml.CoffeeCodeGenerator = CoffeeCodeGenerator;
|
2053
|
+
|
2054
|
+
root.haml.HamlRuntime = HamlRuntime;
|
2055
|
+
|
2056
|
+
root.haml.filters = filters;
|
2057
|
+
|
2058
|
+
}).call(this);
|