OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 class CGBlock { | 5 class CGBlock { |
6 int _blockType; // Code type of this block | 6 int _blockType; // Code type of this block |
7 int _indent; // Number of spaces to prefix for each statement | 7 int _indent; // Number of spaces to prefix for each statement |
8 bool _inEach; // This block or any currently active blocks is a | 8 bool _inEach; // This block or any currently active blocks is a |
9 // #each. If so then any element marked with a | 9 // #each. If so then any element marked with a |
10 // var attribute is repeated therefore the var | 10 // var attribute is repeated therefore the var |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 * | 71 * |
72 * var varName; | 72 * var varName; |
73 * | 73 * |
74 * TODO(terry): For scalars var varName should be Element tag type e.g., | 74 * TODO(terry): For scalars var varName should be Element tag type e.g., |
75 * | 75 * |
76 * DivElement varName; | 76 * DivElement varName; |
77 */ | 77 */ |
78 String get globalDeclarations { | 78 String get globalDeclarations { |
79 StringBuffer buff = new StringBuffer(); | 79 StringBuffer buff = new StringBuffer(); |
80 for (final CGStatement stmt in _stmts) { | 80 for (final CGStatement stmt in _stmts) { |
81 buff.add(stmt.globalDeclaration()); | 81 buff.write(stmt.globalDeclaration()); |
82 } | 82 } |
83 | 83 |
84 return buff.toString(); | 84 return buff.toString(); |
85 } | 85 } |
86 | 86 |
87 /** | 87 /** |
88 * List of statement constructors for each var inside a #each. | 88 * List of statement constructors for each var inside a #each. |
89 * | 89 * |
90 * ${#each products} | 90 * ${#each products} |
91 * <div var=myVar>...</div> | 91 * <div var=myVar>...</div> |
92 * ${/each} | 92 * ${/each} |
93 * | 93 * |
94 * returns: | 94 * returns: |
95 * | 95 * |
96 * myVar = []; | 96 * myVar = []; |
97 */ | 97 */ |
98 String get globalInitializers { | 98 String get globalInitializers { |
99 StringBuffer buff = new StringBuffer(); | 99 StringBuffer buff = new StringBuffer(); |
100 for (final CGStatement stmt in _stmts) { | 100 for (final CGStatement stmt in _stmts) { |
101 buff.add(stmt.globalInitializers()); | 101 buff.write(stmt.globalInitializers()); |
102 } | 102 } |
103 | 103 |
104 return buff.toString(); | 104 return buff.toString(); |
105 } | 105 } |
106 | 106 |
107 String get codeBody { | 107 String get codeBody { |
108 StringBuffer buff = new StringBuffer(); | 108 StringBuffer buff = new StringBuffer(); |
109 | 109 |
110 for (final CGStatement stmt in _stmts) { | 110 for (final CGStatement stmt in _stmts) { |
111 buff.add(stmt.emitDartStatement()); | 111 buff.write(stmt.emitDartStatement()); |
112 } | 112 } |
113 | 113 |
114 return buff.toString(); | 114 return buff.toString(); |
115 } | 115 } |
116 } | 116 } |
117 | 117 |
118 class CGStatement { | 118 class CGStatement { |
119 bool _exact; // If True not HTML construct instead exact stmt | 119 bool _exact; // If True not HTML construct instead exact stmt |
120 bool _repeating; // Stmt in a #each this block or nested block. | 120 bool _repeating; // Stmt in a #each this block or nested block. |
121 StringBuffer _buff; | 121 StringBuffer _buff; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 | 156 |
157 String globalInitializers() { | 157 String globalInitializers() { |
158 if (hasGlobalVariable && _repeating) { | 158 if (hasGlobalVariable && _repeating) { |
159 return " ${varName} = [];\n"; | 159 return " ${varName} = [];\n"; |
160 } | 160 } |
161 | 161 |
162 return ""; | 162 return ""; |
163 } | 163 } |
164 | 164 |
165 void add(String value) { | 165 void add(String value) { |
166 _buff.add(value); | 166 _buff.write(value); |
167 } | 167 } |
168 | 168 |
169 bool get isClosed => _closed; | 169 bool get isClosed => _closed; |
170 | 170 |
171 void close() { | 171 void close() { |
172 if (_elem is TemplateElement && _elem.scoped) { | 172 if (_elem is TemplateElement && _elem.scoped) { |
173 add("</${_elem.tagName}>"); | 173 add("</${_elem.tagName}>"); |
174 } | 174 } |
175 _closed = true; | 175 _closed = true; |
176 } | 176 } |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 // the HTML tree looking for a parent template prefix that | 263 // the HTML tree looking for a parent template prefix that |
264 // matches the CSS prefix. (more thinking needed). | 264 // matches the CSS prefix. (more thinking needed). |
265 static String generate(List<Template> templates, String filename) { | 265 static String generate(List<Template> templates, String filename) { |
266 List<String> fileParts = filename.split('.'); | 266 List<String> fileParts = filename.split('.'); |
267 assert(fileParts.length == 2); | 267 assert(fileParts.length == 2); |
268 filename = fileParts[0]; | 268 filename = fileParts[0]; |
269 | 269 |
270 StringBuffer buff = new StringBuffer(); | 270 StringBuffer buff = new StringBuffer(); |
271 int injectId = 0; // Inject function id | 271 int injectId = 0; // Inject function id |
272 | 272 |
273 buff.add("// Generated Dart class from HTML template.\n"); | 273 buff.write("// Generated Dart class from HTML template.\n"); |
274 buff.add("// DO NOT EDIT.\n\n"); | 274 buff.write("// DO NOT EDIT.\n\n"); |
275 | 275 |
276 String addStylesheetFuncName = "add_${filename}_templatesStyles"; | 276 String addStylesheetFuncName = "add_${filename}_templatesStyles"; |
277 | 277 |
278 for (final template in templates) { | 278 for (final template in templates) { |
279 // Emit the template class. | 279 // Emit the template class. |
280 TemplateSignature sig = template.signature; | 280 TemplateSignature sig = template.signature; |
281 buff.add(_emitClass(sig.name, sig.params, template.content, | 281 buff.write(_emitClass(sig.name, sig.params, template.content, |
282 addStylesheetFuncName)); | 282 addStylesheetFuncName)); |
283 } | 283 } |
284 | 284 |
285 // TODO(terry): Stylesheet aggregator should not be global needs to be | 285 // TODO(terry): Stylesheet aggregator should not be global needs to be |
286 // bound to this template file not global to the app. | 286 // bound to this template file not global to the app. |
287 | 287 |
288 // Emit the stylesheet aggregator. | 288 // Emit the stylesheet aggregator. |
289 buff.add("\n\n// Inject all templates stylesheet once into the head.\n"); | 289 buff.write("\n\n// Inject all templates stylesheet once into the head.\n"); |
290 buff.add("bool ${filename}_stylesheet_added = false;\n"); | 290 buff.write("bool ${filename}_stylesheet_added = false;\n"); |
291 buff.add("void ${addStylesheetFuncName}() {\n"); | 291 buff.write("void ${addStylesheetFuncName}() {\n"); |
292 buff.add(" if (!${filename}_stylesheet_added) {\n"); | 292 buff.write(" if (!${filename}_stylesheet_added) {\n"); |
293 buff.add(" StringBuffer styles = new StringBuffer();\n\n"); | 293 buff.write(" StringBuffer styles = new StringBuffer();\n\n"); |
294 | 294 |
295 buff.add(" // All templates stylesheet.\n"); | 295 buff.write(" // All templates stylesheet.\n"); |
296 | 296 |
297 for (final template in templates) { | 297 for (final template in templates) { |
298 TemplateSignature sig = template.signature; | 298 TemplateSignature sig = template.signature; |
299 buff.add(" styles.add(${sig.name}.stylesheet);\n"); | 299 buff.write(" styles.add(${sig.name}.stylesheet);\n"); |
300 } | 300 } |
301 | 301 |
302 buff.add("\n ${filename}_stylesheet_added = true;\n"); | 302 buff.write("\n ${filename}_stylesheet_added = true;\n"); |
303 | 303 |
304 buff.add(" document.head.elements.add(new Element.html('<style>" | 304 buff.write(" document.head.elements.add(new Element.html('<style>" |
305 "\${styles.toString()}</style>'));\n"); | 305 "\${styles.toString()}</style>'));\n"); |
306 buff.add(" }\n"); | 306 buff.write(" }\n"); |
307 buff.add("}\n"); | 307 buff.write("}\n"); |
308 | 308 |
309 return buff.toString(); | 309 return buff.toString(); |
310 } | 310 } |
311 | 311 |
312 static String _emitCSSSelectors(css.Stylesheet stylesheet) { | 312 static String _emitCSSSelectors(css.Stylesheet stylesheet) { |
313 if (stylesheet == null) { | 313 if (stylesheet == null) { |
314 return ""; | 314 return ""; |
315 } | 315 } |
316 | 316 |
317 List<String> classes = []; | 317 List<String> classes = []; |
(...skipping 22 matching lines...) Expand all Loading... |
340 // Character between 'a'..'z' mapped to 'A'..'Z' | 340 // Character between 'a'..'z' mapped to 'A'..'Z' |
341 dartName.add("${part[0].toUpperCase()}${part.substring(1)}"); | 341 dartName.add("${part[0].toUpperCase()}${part.substring(1)}"); |
342 } | 342 } |
343 dartNames.add(dartName.toString()); | 343 dartNames.add(dartName.toString()); |
344 } | 344 } |
345 } | 345 } |
346 | 346 |
347 StringBuffer buff = new StringBuffer(); | 347 StringBuffer buff = new StringBuffer(); |
348 if (classes.length > 0) { | 348 if (classes.length > 0) { |
349 assert(classes.length == dartNames.length); | 349 assert(classes.length == dartNames.length); |
350 buff.add("\n // CSS class selectors for this template.\n"); | 350 buff.write("\n // CSS class selectors for this template.\n"); |
351 for (int i = 0; i < classes.length; i++) { | 351 for (int i = 0; i < classes.length; i++) { |
352 buff.add( | 352 buff.write( |
353 " static String get ${dartNames[i]} => \"${classes[i]}\";\n"); | 353 " static String get ${dartNames[i]} => \"${classes[i]}\";\n"); |
354 } | 354 } |
355 } | 355 } |
356 | 356 |
357 return buff.toString(); | 357 return buff.toString(); |
358 } | 358 } |
359 | 359 |
360 static String _emitClass(String className, | 360 static String _emitClass(String className, |
361 List<Map<Identifier, Identifier>> params, | 361 List<Map<Identifier, Identifier>> params, |
362 TemplateContent content, | 362 TemplateContent content, |
363 String addStylesheetFuncName) { | 363 String addStylesheetFuncName) { |
364 StringBuffer buff = new StringBuffer(); | 364 StringBuffer buff = new StringBuffer(); |
365 | 365 |
366 // Emit the template class. | 366 // Emit the template class. |
367 buff.add("class ${className} {\n"); | 367 buff.write("class ${className} {\n"); |
368 | 368 |
369 buff.add(" Map<String, Object> _scopes;\n"); | 369 buff.write(" Map<String, Object> _scopes;\n"); |
370 buff.add(" Element _fragment;\n\n"); | 370 buff.write(" Element _fragment;\n\n"); |
371 | 371 |
372 bool anyParams = false; | 372 bool anyParams = false; |
373 for (final param in params) { | 373 for (final param in params) { |
374 buff.add(" ${param['type']} ${param['name']};\n"); | 374 buff.write(" ${param['type']} ${param['name']};\n"); |
375 anyParams = true; | 375 anyParams = true; |
376 } | 376 } |
377 if (anyParams) buff.add("\n"); | 377 if (anyParams) buff.write("\n"); |
378 | 378 |
379 ElemCG ecg = new ElemCG(); | 379 ElemCG ecg = new ElemCG(); |
380 | 380 |
381 if (!ecg.pushBlock()) { | 381 if (!ecg.pushBlock()) { |
382 world.error("Error at ${content}"); | 382 world.error("Error at ${content}"); |
383 } | 383 } |
384 | 384 |
385 var root = content.html.children.length > 0 ? content.html.children[0] : | 385 var root = content.html.children.length > 0 ? content.html.children[0] : |
386 content.html; | 386 content.html; |
387 bool firstTime = true; | 387 bool firstTime = true; |
388 for (var child in root.children) { | 388 for (var child in root.children) { |
389 if (child is TemplateText) { | 389 if (child is TemplateText) { |
390 if (!firstTime) { | 390 if (!firstTime) { |
391 ecg.closeStatement(); | 391 ecg.closeStatement(); |
392 } | 392 } |
393 | 393 |
394 String textNodeValue = child.value.trim(); | 394 String textNodeValue = child.value.trim(); |
395 if (textNodeValue.length > 0) { | 395 if (textNodeValue.length > 0) { |
396 CGStatement stmt = ecg.pushStatement(child, "_fragment"); | 396 CGStatement stmt = ecg.pushStatement(child, "_fragment"); |
397 } | 397 } |
398 } | 398 } |
399 ecg.emitConstructHtml(child, "", "_fragment"); | 399 ecg.emitConstructHtml(child, "", "_fragment"); |
400 firstTime = false; | 400 firstTime = false; |
401 } | 401 } |
402 | 402 |
403 // Create all element names marked with var. | 403 // Create all element names marked with var. |
404 String decls = ecg.globalDeclarations; | 404 String decls = ecg.globalDeclarations; |
405 if (decls.length > 0) { | 405 if (decls.length > 0) { |
406 buff.add("\n // Elements bound to a variable:\n"); | 406 buff.write("\n // Elements bound to a variable:\n"); |
407 buff.add("${decls}\n"); | 407 buff.write("${decls}\n"); |
408 } | 408 } |
409 | 409 |
410 // Create the constructor. | 410 // Create the constructor. |
411 buff.add(" ${className}("); | 411 buff.write(" ${className}("); |
412 bool firstParam = true; | 412 bool firstParam = true; |
413 for (final param in params) { | 413 for (final param in params) { |
414 if (!firstParam) { | 414 if (!firstParam) { |
415 buff.add(", "); | 415 buff.write(", "); |
416 } | 416 } |
417 buff.add("this.${param['name']}"); | 417 buff.write("this.${param['name']}"); |
418 firstParam = false; | 418 firstParam = false; |
419 } | 419 } |
420 buff.add(") : _scopes = new Map<String, Object>() {\n"); | 420 buff.write(") : _scopes = new Map<String, Object>() {\n"); |
421 | 421 |
422 String initializers = ecg.globalInitializers; | 422 String initializers = ecg.globalInitializers; |
423 if (initializers.length > 0) { | 423 if (initializers.length > 0) { |
424 buff.add(" //Global initializers.\n"); | 424 buff.write(" //Global initializers.\n"); |
425 buff.add("${initializers}\n"); | 425 buff.write("${initializers}\n"); |
426 } | 426 } |
427 | 427 |
428 buff.add(" // Insure stylesheet for template exist in the document.\n"); | 428 buff.write(" // Insure stylesheet for template exist in the document.\n")
; |
429 buff.add(" ${addStylesheetFuncName}();\n\n"); | 429 buff.write(" ${addStylesheetFuncName}();\n\n"); |
430 | 430 |
431 buff.add(" _fragment = new DocumentFragment();\n"); | 431 buff.write(" _fragment = new DocumentFragment();\n"); |
432 | 432 |
433 buff.add(ecg.codeBody); // HTML for constructor to build. | 433 buff.write(ecg.codeBody); // HTML for constructor to build. |
434 | 434 |
435 buff.add(" }\n\n"); // End constructor | 435 buff.write(" }\n\n"); // End constructor |
436 | 436 |
437 buff.add(emitGetters(content.getters)); | 437 buff.write(emitGetters(content.getters)); |
438 | 438 |
439 buff.add(" Element get root => _fragment;\n"); | 439 buff.write(" Element get root => _fragment;\n"); |
440 | 440 |
441 // Emit all CSS class selectors: | 441 // Emit all CSS class selectors: |
442 buff.add(_emitCSSSelectors(content.css)); | 442 buff.write(_emitCSSSelectors(content.css)); |
443 | 443 |
444 // Emit the injection functions. | 444 // Emit the injection functions. |
445 buff.add("\n // Injection functions:"); | 445 buff.write("\n // Injection functions:"); |
446 for (final expr in ecg.expressions) { | 446 for (final expr in ecg.expressions) { |
447 buff.add("${expr}"); | 447 buff.write("${expr}"); |
448 } | 448 } |
449 | 449 |
450 buff.add("\n // Each functions:\n"); | 450 buff.write("\n // Each functions:\n"); |
451 for (var eachFunc in ecg.eachs) { | 451 for (var eachFunc in ecg.eachs) { |
452 buff.add("${eachFunc}\n"); | 452 buff.write("${eachFunc}\n"); |
453 } | 453 } |
454 | 454 |
455 buff.add("\n // With functions:\n"); | 455 buff.write("\n // With functions:\n"); |
456 for (var withFunc in ecg.withs) { | 456 for (var withFunc in ecg.withs) { |
457 buff.add("${withFunc}\n"); | 457 buff.write("${withFunc}\n"); |
458 } | 458 } |
459 | 459 |
460 buff.add("\n // CSS for this template.\n"); | 460 buff.write("\n // CSS for this template.\n"); |
461 buff.add(" static const String stylesheet = "); | 461 buff.write(" static const String stylesheet = "); |
462 | 462 |
463 if (content.css != null) { | 463 if (content.css != null) { |
464 buff.add("\'\'\'\n ${content.css.toString()}\n"); | 464 buff.write("\'\'\'\n ${content.css.toString()}\n"); |
465 buff.add(" \'\'\';\n\n"); | 465 buff.write(" \'\'\';\n\n"); |
466 | 466 |
467 // TODO(terry): Emit all known selectors for this template. | 467 // TODO(terry): Emit all known selectors for this template. |
468 buff.add(" // Stylesheet class selectors:\n"); | 468 buff.write(" // Stylesheet class selectors:\n"); |
469 } else { | 469 } else { |
470 buff.add("\"\";\n"); | 470 buff.write("\"\";\n"); |
471 } | 471 } |
472 | 472 |
473 buff.add(" String safeHTML(String html) {\n"); | 473 buff.write(" String safeHTML(String html) {\n"); |
474 buff.add(" // TODO(terry): Escaping for XSS vulnerabilities TBD.\n"); | 474 buff.write(" // TODO(terry): Escaping for XSS vulnerabilities TBD.\n"); |
475 buff.add(" return html;\n"); | 475 buff.write(" return html;\n"); |
476 buff.add(" }\n"); | 476 buff.write(" }\n"); |
477 | 477 |
478 buff.add("}\n"); // End class | 478 buff.write("}\n"); // End class |
479 | 479 |
480 return buff.toString(); | 480 return buff.toString(); |
481 } | 481 } |
482 | 482 |
483 // TODO(terry): Need to generate function to inject any TemplateExpressions | 483 // TODO(terry): Need to generate function to inject any TemplateExpressions |
484 // to call SafeHTML wrapper. | 484 // to call SafeHTML wrapper. |
485 static String emitGetters(List<TemplateGetter> getters) { | 485 static String emitGetters(List<TemplateGetter> getters) { |
486 StringBuffer buff = new StringBuffer(); | 486 StringBuffer buff = new StringBuffer(); |
487 for (final TemplateGetter getter in getters) { | 487 for (final TemplateGetter getter in getters) { |
488 buff.add(' String ${getter.getterSignatureAsString()} {\n'); | 488 buff.write(' String ${getter.getterSignatureAsString()} {\n'); |
489 buff.add(' return \'\'\''); | 489 buff.write(' return \'\'\''); |
490 var docFrag = getter.docFrag.children[0]; | 490 var docFrag = getter.docFrag.children[0]; |
491 for (final child in docFrag.children) { | 491 for (final child in docFrag.children) { |
492 buff.add(child.toString().trim()); | 492 buff.write(child.toString().trim()); |
493 } | 493 } |
494 buff.add('\'\'\';\n'); | 494 buff.write('\'\'\';\n'); |
495 buff.add(' }\n\n'); | 495 buff.write(' }\n\n'); |
496 } | 496 } |
497 | 497 |
498 return buff.toString(); | 498 return buff.toString(); |
499 } | 499 } |
500 } | 500 } |
501 | 501 |
502 class ElemCG { | 502 class ElemCG { |
503 // List of identifiers and quoted strings (single and double quoted). | 503 // List of identifiers and quoted strings (single and double quoted). |
504 var identRe = new RegExp( | 504 var identRe = new RegExp( |
505 "\s*('\"\\'\\\"[^'\"\\'\\\"]+'\"\\'\\\"|[_A-Za-z][_A-Za-z0-9]*)"); | 505 "\s*('\"\\'\\\"[^'\"\\'\\\"]+'\"\\'\\\"|[_A-Za-z][_A-Za-z0-9]*)"); |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
975 | 975 |
976 return (name == null) ? "_item" : name; | 976 return (name == null) ? "_item" : name; |
977 } | 977 } |
978 | 978 |
979 addScope(int indent, StringBuffer buff, String item) { | 979 addScope(int indent, StringBuffer buff, String item) { |
980 String spaces = Codegen.spaces(indent); | 980 String spaces = Codegen.spaces(indent); |
981 | 981 |
982 if (item == null) { | 982 if (item == null) { |
983 item = "_item"; | 983 item = "_item"; |
984 } | 984 } |
985 buff.add("${spaces}_scopes[\"${item}\"] = ${item};\n"); | 985 buff.write("${spaces}_scopes[\"${item}\"] = ${item};\n"); |
986 } | 986 } |
987 | 987 |
988 removeScope(int indent, StringBuffer buff, String item) { | 988 removeScope(int indent, StringBuffer buff, String item) { |
989 String spaces = Codegen.spaces(indent); | 989 String spaces = Codegen.spaces(indent); |
990 | 990 |
991 if (item == null) { | 991 if (item == null) { |
992 item = "_item"; | 992 item = "_item"; |
993 } | 993 } |
994 buff.add("${spaces}_scopes.remove(\"${item}\");\n"); | 994 buff.write("${spaces}_scopes.remove(\"${item}\");\n"); |
995 } | 995 } |
996 | 996 |
997 String defineScopes() { | 997 String defineScopes() { |
998 StringBuffer buff = new StringBuffer(); | 998 StringBuffer buff = new StringBuffer(); |
999 | 999 |
1000 // Construct the active scope names for name resolution. | 1000 // Construct the active scope names for name resolution. |
1001 List<String> names = activeBlocksLocalNames(); | 1001 List<String> names = activeBlocksLocalNames(); |
1002 if (names.length > 0) { | 1002 if (names.length > 0) { |
1003 buff.add(" // Local scoped block names.\n"); | 1003 buff.write(" // Local scoped block names.\n"); |
1004 for (String name in names) { | 1004 for (String name in names) { |
1005 buff.add(" var ${name} = _scopes[\"${name}\"];\n"); | 1005 buff.write(" var ${name} = _scopes[\"${name}\"];\n"); |
1006 } | 1006 } |
1007 buff.add("\n"); | 1007 buff.write("\n"); |
1008 } | 1008 } |
1009 | 1009 |
1010 return buff.toString(); | 1010 return buff.toString(); |
1011 } | 1011 } |
1012 | 1012 |
1013 } | 1013 } |
OLD | NEW |