Chromium Code Reviews| 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 44 CGStatement stmt = new CGStatement(elem, _indent, parentName, varName, | 44 CGStatement stmt = new CGStatement(elem, _indent, parentName, varName, |
| 45 exact, _inEach); | 45 exact, _inEach); |
| 46 _stmts.add(stmt); | 46 _stmts.add(stmt); |
| 47 | 47 |
| 48 return stmt; | 48 return stmt; |
| 49 } | 49 } |
| 50 | 50 |
| 51 void pop() { | 51 void pop() { |
| 52 _stmts.removeLast(); | 52 _stmts.removeLast(); |
| 53 } | 53 } |
| 54 | 54 |
|
Jacob
2012/04/05 18:06:01
unreleated to this change but perhaps emit final i
| |
| 55 void add(String value) { | 55 void add(String value) { |
| 56 if (_stmts.last() != null) { | 56 if (_stmts.last() != null) { |
| 57 _stmts.last().add(value); | 57 _stmts.last().add(value); |
| 58 } | 58 } |
| 59 } | 59 } |
| 60 | 60 |
| 61 CGStatement get last() => _stmts.last(); | 61 CGStatement get last() => _stmts.length > 0 ? _stmts.last() : null; |
| 62 | 62 |
| 63 /** | 63 /** |
| 64 * Returns mixed list of elements marked with the var attribute. If the | 64 * Returns mixed list of elements marked with the var attribute. If the |
| 65 * element is inside of a #each the name exposed is: | 65 * element is inside of a #each the name exposed is: |
| 66 * | 66 * |
| 67 * List varName; | 67 * List varName; |
| 68 * | 68 * |
| 69 * otherwise it's: | 69 * otherwise it's: |
| 70 * | 70 * |
| 71 * var varName; | 71 * var varName; |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 161 return ""; | 161 return ""; |
| 162 } | 162 } |
| 163 | 163 |
| 164 void add(String value) { | 164 void add(String value) { |
| 165 _buff.add(value); | 165 _buff.add(value); |
| 166 } | 166 } |
| 167 | 167 |
| 168 bool get isClosed() => _closed; | 168 bool get isClosed() => _closed; |
| 169 | 169 |
| 170 void close() { | 170 void close() { |
| 171 if (_elem is TemplateElement) { | 171 if (_elem is TemplateElement && _elem.scoped) { |
| 172 add("</${_elem.tagName}>"); | 172 add("</${_elem.tagName}>"); |
| 173 } | 173 } |
| 174 _closed = true; | 174 _closed = true; |
| 175 } | 175 } |
| 176 | 176 |
| 177 String emitDartStatement() { | 177 String emitDartStatement() { |
| 178 StringBuffer statement = new StringBuffer(); | 178 StringBuffer statement = new StringBuffer(); |
| 179 | 179 |
| 180 String spaces = Codegen.spaces(_indent); | 180 String spaces = Codegen.spaces(_indent); |
| 181 | 181 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 265 List<String> fileParts = filename.split('.'); | 265 List<String> fileParts = filename.split('.'); |
| 266 assert(fileParts.length == 2); | 266 assert(fileParts.length == 2); |
| 267 filename = fileParts[0]; | 267 filename = fileParts[0]; |
| 268 | 268 |
| 269 StringBuffer buff = new StringBuffer(); | 269 StringBuffer buff = new StringBuffer(); |
| 270 int injectId = 0; // Inject function id | 270 int injectId = 0; // Inject function id |
| 271 | 271 |
| 272 buff.add("// Generated Dart class from HTML template.\n"); | 272 buff.add("// Generated Dart class from HTML template.\n"); |
| 273 buff.add("// DO NOT EDIT.\n\n"); | 273 buff.add("// DO NOT EDIT.\n\n"); |
| 274 | 274 |
| 275 buff.add("String safeHTML(String html) {\n"); | |
| 276 buff.add(" // TODO(terry): Escaping for XSS vulnerabilities TBD.\n"); | |
| 277 buff.add(" return html;\n"); | |
| 278 buff.add("}\n\n"); | |
| 279 | |
| 280 String addStylesheetFuncName = "add_${filename}_templatesStyles"; | 275 String addStylesheetFuncName = "add_${filename}_templatesStyles"; |
| 281 | 276 |
| 282 for (final template in templates) { | 277 for (final template in templates) { |
| 283 // Emit the template class. | 278 // Emit the template class. |
| 284 TemplateSignature sig = template.signature; | 279 TemplateSignature sig = template.signature; |
| 285 buff.add(_emitClass(sig.name, sig.params, template.content, | 280 buff.add(_emitClass(sig.name, sig.params, template.content, |
| 286 addStylesheetFuncName)); | 281 addStylesheetFuncName)); |
| 287 } | 282 } |
| 288 | 283 |
| 289 // TODO(terry): Stylesheet aggregator should not be global needs to be | 284 // TODO(terry): Stylesheet aggregator should not be global needs to be |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 379 anyParams = true; | 374 anyParams = true; |
| 380 } | 375 } |
| 381 if (anyParams) buff.add("\n"); | 376 if (anyParams) buff.add("\n"); |
| 382 | 377 |
| 383 ElemCG ecg = new ElemCG(); | 378 ElemCG ecg = new ElemCG(); |
| 384 | 379 |
| 385 if (!ecg.pushBlock()) { | 380 if (!ecg.pushBlock()) { |
| 386 world.error("Error at ${content}"); | 381 world.error("Error at ${content}"); |
| 387 } | 382 } |
| 388 | 383 |
| 389 var root = content.html.children[0]; | 384 var root = content.html.children.length > 0 ? content.html.children[0] : |
| 385 content.html; | |
| 390 bool firstTime = true; | 386 bool firstTime = true; |
| 391 for (var child in root.children) { | 387 for (var child in root.children) { |
| 392 if (child is TemplateText) { | 388 if (child is TemplateText) { |
| 393 if (!firstTime) { | 389 if (!firstTime) { |
| 394 ecg.closeStatement(); | 390 ecg.closeStatement(); |
| 395 } | 391 } |
| 396 CGStatement stmt = ecg.pushStatement(child, "_fragment"); | 392 |
| 393 String textNodeValue = child.value.trim(); | |
| 394 if (textNodeValue.length > 0) { | |
| 395 CGStatement stmt = ecg.pushStatement(child, "_fragment"); | |
| 396 } | |
| 397 } | 397 } |
| 398 ecg.emitConstructHtml(child, "", "_fragment"); | 398 ecg.emitConstructHtml(child, "", "_fragment"); |
| 399 firstTime = false; | 399 firstTime = false; |
| 400 } | 400 } |
| 401 | 401 |
| 402 // Create all element names marked with var. | 402 // Create all element names marked with var. |
| 403 String decls = ecg.globalDeclarations; | 403 String decls = ecg.globalDeclarations; |
| 404 if (decls.length > 0) { | 404 if (decls.length > 0) { |
| 405 buff.add("\n // Elements bound to a variable:\n"); | 405 buff.add("\n // Elements bound to a variable:\n"); |
| 406 buff.add("${decls}\n"); | 406 buff.add("${decls}\n"); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 426 | 426 |
| 427 buff.add(" // Insure stylesheet for template exist in the document.\n"); | 427 buff.add(" // Insure stylesheet for template exist in the document.\n"); |
| 428 buff.add(" ${addStylesheetFuncName}();\n\n"); | 428 buff.add(" ${addStylesheetFuncName}();\n\n"); |
| 429 | 429 |
| 430 buff.add(" _fragment = new DocumentFragment();\n"); | 430 buff.add(" _fragment = new DocumentFragment();\n"); |
| 431 | 431 |
| 432 buff.add(ecg.codeBody); // HTML for constructor to build. | 432 buff.add(ecg.codeBody); // HTML for constructor to build. |
| 433 | 433 |
| 434 buff.add(" }\n\n"); // End constructor | 434 buff.add(" }\n\n"); // End constructor |
| 435 | 435 |
| 436 buff.add(emitGetters(content.getters)); | |
| 437 | |
| 436 buff.add(" Element get root() => _fragment;\n"); | 438 buff.add(" Element get root() => _fragment;\n"); |
| 437 | 439 |
| 438 // Emit all CSS class selectors: | 440 // Emit all CSS class selectors: |
| 439 buff.add(_emitCSSSelectors(content.css)); | 441 buff.add(_emitCSSSelectors(content.css)); |
| 440 | 442 |
| 441 // Emit the injection functions. | 443 // Emit the injection functions. |
| 442 buff.add("\n // Injection functions:"); | 444 buff.add("\n // Injection functions:"); |
| 443 for (final expr in ecg.expressions) { | 445 for (final expr in ecg.expressions) { |
| 444 buff.add("${expr}"); | 446 buff.add("${expr}"); |
| 445 } | 447 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 460 if (content.css != null) { | 462 if (content.css != null) { |
| 461 buff.add("\'\'\'\n ${content.css.toString()}\n"); | 463 buff.add("\'\'\'\n ${content.css.toString()}\n"); |
| 462 buff.add(" \'\'\';\n\n"); | 464 buff.add(" \'\'\';\n\n"); |
| 463 | 465 |
| 464 // TODO(terry): Emit all known selectors for this template. | 466 // TODO(terry): Emit all known selectors for this template. |
| 465 buff.add(" // Stylesheet class selectors:\n"); | 467 buff.add(" // Stylesheet class selectors:\n"); |
| 466 } else { | 468 } else { |
| 467 buff.add("\"\";\n"); | 469 buff.add("\"\";\n"); |
| 468 } | 470 } |
| 469 | 471 |
| 472 buff.add(" String safeHTML(String html) {\n"); | |
|
Jacob
2012/04/05 18:06:01
use multiline strings to make this cleaner
| |
| 473 buff.add(" // TODO(terry): Escaping for XSS vulnerabilities TBD.\n"); | |
| 474 buff.add(" return html;\n"); | |
| 475 buff.add(" }\n"); | |
| 476 | |
| 470 buff.add("}\n"); // End class | 477 buff.add("}\n"); // End class |
| 471 | 478 |
| 472 return buff.toString(); | 479 return buff.toString(); |
| 473 } | 480 } |
| 481 | |
| 482 // TODO(terry): Need to generate function to inject any TemplateExpressions | |
| 483 // to call SafeHTML wrapper. | |
| 484 static String emitGetters(List<TemplateGetter> getters) { | |
| 485 StringBuffer buff = new StringBuffer(); | |
| 486 for (final TemplateGetter getter in getters) { | |
| 487 buff.add(' String ${getter.getterSignatureAsString()} {\n'); | |
| 488 buff.add(' return \'\'\''); | |
| 489 var docFrag = getter.docFrag.children[0]; | |
| 490 for (final child in docFrag.children) { | |
| 491 buff.add(child.toString().trim()); | |
| 492 } | |
| 493 buff.add('\'\'\';\n'); | |
| 494 buff.add(' }\n\n'); | |
| 495 } | |
| 496 | |
| 497 return buff.toString(); | |
| 498 } | |
| 474 } | 499 } |
| 475 | 500 |
| 476 class ElemCG { | 501 class ElemCG { |
| 477 // List of identifiers and quoted strings (single and double quoted). | 502 // List of identifiers and quoted strings (single and double quoted). |
| 478 var identRe = const RegExp( | 503 var identRe = const RegExp( |
| 479 "\s*('\"\\'\\\"[^'\"\\'\\\"]+'\"\\'\\\"|[_A-Za-z][_A-Za-z0-9]*)"); | 504 "\s*('\"\\'\\\"[^'\"\\'\\\"]+'\"\\'\\\"|[_A-Za-z][_A-Za-z0-9]*)"); |
| 480 | 505 |
| 481 List<CGBlock> _cgBlocks; | 506 List<CGBlock> _cgBlocks; |
| 482 StringBuffer _globalDecls; // Global var declarations for all blocks. | 507 StringBuffer _globalDecls; // Global var declarations for all blocks. |
| 483 StringBuffer _globalInits; // Global List var initializtion for all | 508 StringBuffer _globalInits; // Global List var initializtion for all |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 593 } | 618 } |
| 594 | 619 |
| 595 CGStatement pushStatement(var elem, var parentName) { | 620 CGStatement pushStatement(var elem, var parentName) { |
| 596 return lastBlock.push(elem, parentName, false); | 621 return lastBlock.push(elem, parentName, false); |
| 597 } | 622 } |
| 598 | 623 |
| 599 CGStatement pushExactStatement(var elem, var parentName) { | 624 CGStatement pushExactStatement(var elem, var parentName) { |
| 600 return lastBlock.push(elem, parentName, true); | 625 return lastBlock.push(elem, parentName, true); |
| 601 } | 626 } |
| 602 | 627 |
| 603 bool get isClosedStatement() => lastBlock.last.isClosed; | 628 bool get isClosedStatement() { |
| 629 return (lastBlock != null && lastBlock.last != null) ? | |
| 630 lastBlock.last.isClosed : false; | |
| 631 } | |
| 604 | 632 |
| 605 void closeStatement() { | 633 void closeStatement() { |
| 606 if (lastBlock != null && lastBlock.last != null && | 634 if (lastBlock != null && lastBlock.last != null && |
| 607 !lastBlock.last.isClosed) { | 635 !lastBlock.last.isClosed) { |
| 608 lastBlock.last.close(); | 636 lastBlock.last.close(); |
| 609 } | 637 } |
| 610 } | 638 } |
| 611 | 639 |
| 612 String get lastVariableName() { | 640 String get lastVariableName() { |
| 613 if (lastBlock != null && lastBlock.last != null) { | 641 if (lastBlock != null && lastBlock.last != null) { |
| 614 return lastBlock.last.variableName; | 642 return lastBlock.last.variableName; |
| 615 } | 643 } |
| 616 } | 644 } |
| 617 | 645 |
| 646 String get lastParentName() { | |
| 647 if (lastBlock != null && lastBlock.last != null) { | |
| 648 return lastBlock.last.parentName; | |
| 649 } | |
| 650 } | |
| 651 | |
| 618 CGBlock get lastBlock() => _cgBlocks.length > 0 ? _cgBlocks.last() : null; | 652 CGBlock get lastBlock() => _cgBlocks.length > 0 ? _cgBlocks.last() : null; |
| 619 | 653 |
| 620 void add(String str) { | 654 void add(String str) { |
| 621 _cgBlocks.last().add(str); | 655 _cgBlocks.last().add(str); |
| 622 } | 656 } |
| 623 | 657 |
| 624 String get globalDeclarations() { | 658 String get globalDeclarations() { |
| 625 assert(_cgBlocks.length == 1); // Only constructor body should be left. | 659 assert(_cgBlocks.length == 1); // Only constructor body should be left. |
| 626 _globalDecls.add(lastBlock.globalDeclarations); | 660 _globalDecls.add(lastBlock.globalDeclarations); |
| 627 return _globalDecls.toString(); | 661 return _globalDecls.toString(); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 647 [String scopeName = "", | 681 [String scopeName = "", |
| 648 var parentVarOrIdx = 0, | 682 var parentVarOrIdx = 0, |
| 649 bool immediateNestedEach = false]) { | 683 bool immediateNestedEach = false]) { |
| 650 if (elem is TemplateElement) { | 684 if (elem is TemplateElement) { |
| 651 if (!elem.isFragment) { | 685 if (!elem.isFragment) { |
| 652 add("<${elem.tagName}${elem.attributesToString()}>"); | 686 add("<${elem.tagName}${elem.attributesToString()}>"); |
| 653 } | 687 } |
| 654 String prevParent = lastVariableName; | 688 String prevParent = lastVariableName; |
| 655 for (var childElem in elem.children) { | 689 for (var childElem in elem.children) { |
| 656 if (childElem is TemplateElement) { | 690 if (childElem is TemplateElement) { |
| 691 closeStatement(); | |
| 657 if (childElem.hasVar) { | 692 if (childElem.hasVar) { |
| 658 closeStatement(); | |
| 659 emitConstructHtml(childElem, scopeName, prevParent, | 693 emitConstructHtml(childElem, scopeName, prevParent, |
| 660 childElem.varName); | 694 childElem.varName); |
| 661 closeStatement(); | |
| 662 } else { | 695 } else { |
| 663 closeStatement(); | |
| 664 emitConstructHtml(childElem, scopeName, prevParent); | 696 emitConstructHtml(childElem, scopeName, prevParent); |
| 665 closeStatement(); | |
| 666 } | 697 } |
| 698 closeStatement(); | |
| 667 } else { | 699 } else { |
| 668 emitElement(childElem, scopeName, parentVarOrIdx); | 700 emitElement(childElem, scopeName, parentVarOrIdx); |
| 669 } | 701 } |
| 670 } | 702 } |
| 671 | 703 |
| 672 // Close this tag. | 704 // Close this tag. |
| 673 closeStatement(); | 705 closeStatement(); |
| 674 } else if (elem is TemplateText) { | 706 } else if (elem is TemplateText) { |
| 675 add("${elem.value}"); | 707 String outputValue = elem.value.trim(); |
| 708 if (outputValue.length > 0) { | |
| 709 bool emitTextNode = false; | |
| 710 if (isClosedStatement) { | |
| 711 String prevParent = lastParentName; | |
| 712 CGStatement stmt = pushStatement(elem, prevParent); | |
| 713 emitTextNode = true; | |
| 714 } | |
| 715 | |
| 716 // TODO(terry): Need to interpolate following: | |
| 717 // {sp} → space | |
| 718 // {nil} → empty string | |
| 719 // {\r} → carriage return | |
| 720 // {\n} → new line (line feed) | |
| 721 // {\t} → tab | |
| 722 // {lb} → left brace | |
| 723 // {rb} → right brace | |
| 724 | |
| 725 add("${outputValue}"); // remove leading/trailing whitespace. | |
| 726 | |
| 727 if (emitTextNode) { | |
| 728 closeStatement(); | |
| 729 } | |
| 730 } | |
| 676 } else if (elem is TemplateExpression) { | 731 } else if (elem is TemplateExpression) { |
| 677 emitExpressions(elem, scopeName); | 732 emitExpressions(elem, scopeName); |
| 678 } else if (elem is TemplateEachCommand) { | 733 } else if (elem is TemplateEachCommand) { |
| 679 // Signal to caller new block coming in, returns "each_" prefix | 734 // Signal to caller new block coming in, returns "each_" prefix |
| 680 emitEach(elem, "List", elem.listName.name, "parent", immediateNestedEach, | 735 emitEach(elem, "List", elem.listName.name, "parent", immediateNestedEach, |
| 681 elem.hasLoopItem ? elem.loopItem.name : null); | 736 elem.hasLoopItem ? elem.loopItem.name : null); |
| 682 } else if (elem is TemplateWithCommand) { | 737 } else if (elem is TemplateWithCommand) { |
| 683 // Signal to caller new block coming in, returns "each_" prefix | 738 // Signal to caller new block coming in, returns "each_" prefix |
| 684 emitWith(elem, "var", elem.objectName.name, "parent", | 739 emitWith(elem, "var", elem.objectName.name, "parent", |
| 685 elem.hasBlockItem ? elem.blockItem.name : null); | 740 elem.hasBlockItem ? elem.blockItem.name : null); |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 937 for (String name in names) { | 992 for (String name in names) { |
| 938 buff.add(" var ${name} = _scopes[\"${name}\"];\n"); | 993 buff.add(" var ${name} = _scopes[\"${name}\"];\n"); |
| 939 } | 994 } |
| 940 buff.add("\n"); | 995 buff.add("\n"); |
| 941 } | 996 } |
| 942 | 997 |
| 943 return buff.toString(); | 998 return buff.toString(); |
| 944 } | 999 } |
| 945 | 1000 |
| 946 } | 1001 } |
| OLD | NEW |