Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(322)

Side by Side Diff: lib/src/html_css_fixup.dart

Issue 19497002: Reducing the amount of code we generate in the compiler: We still continue (Closed) Base URL: git@github.com:dart-lang/web-ui.git@master
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 library html_css_fixup; 5 library html_css_fixup;
6 6
7 import 'dart:json' as json; 7 import 'dart:json' as json;
8 8
9 import 'package:csslib/parser.dart' as css; 9 import 'package:csslib/parser.dart' as css;
10 import 'package:csslib/visitor.dart'; 10 import 'package:csslib/visitor.dart';
11 import 'package:html5lib/dom.dart'; 11 import 'package:html5lib/dom.dart';
12 import 'package:html5lib/dom_parsing.dart'; 12 import 'package:html5lib/dom_parsing.dart';
13 13
14 import 'compiler.dart'; 14 import 'compiler.dart';
15 import 'emitters.dart'; 15 import 'emitters.dart';
16 import 'info.dart'; 16 import 'info.dart';
17 import 'messages.dart'; 17 import 'messages.dart';
18 import 'options.dart'; 18 import 'options.dart';
19 import 'paths.dart'; 19 import 'paths.dart';
20 import 'utils.dart'; 20 import 'utils.dart';
21 21
22 /** 22 // TODO(terry): Replace with enum when supported.
Jennifer Messerly 2013/07/18 23:56:04 remove TODO?
Siggi Cherem (dart-lang) 2013/07/19 22:52:52 Done.
23 * Helper function returns [true] if CSS polyfill is on and component has a 23 /** Enum for type of polyfills supported. */
24 * scoped style tag. 24 class CssPolyfillKind {
25 */ 25 final index;
26 bool useCssPolyfill(CompilerOptions opts, ComponentInfo component) => 26 const CssPolyfillKind(this.index);
27 opts.processCss && component.scoped; 27
28 /** Emit CSS selectors as seen (no polyfill). */
29 static const NO_POLYFILL = const CssPolyfillKind(0);
30
31 /** Emit CSS selectors scoped to the "is" attribute of the component. */
32 static const SCOPED_POLYFILL = const CssPolyfillKind(1);
33
34 /** Emit CSS selectors mangled. */
35 static const MANGLED_POLYFILL = const CssPolyfillKind(2);
36
37 static CssPolyfillKind of(CompilerOptions options, ComponentInfo component) {
38 if (!options.processCss || !component.scoped) return NO_POLYFILL;
39 if (options.mangleCss) return MANGLED_POLYFILL;
40 if (!component.hasAuthorStyles && !hasCssReset) return MANGLED_POLYFILL;
41 return SCOPED_POLYFILL;
42 }
43 }
44
28 45
29 /** 46 /**
30 * If processCss is enabled, prefix any component's HTML attributes for id or 47 * If processCss is enabled, prefix any component's HTML attributes for id or
31 * class to reference the mangled CSS class name or id. 48 * class to reference the mangled CSS class name or id.
32 */ 49 */
33 void fixupHtmlCss(FileInfo fileInfo, CompilerOptions options, 50 void fixupHtmlCss(FileInfo fileInfo, CompilerOptions options) {
34 CssPolyfillKind polyfillKind(ComponentInfo component)) {
35 // Walk the HTML tree looking for class names or id that are in our parsed 51 // Walk the HTML tree looking for class names or id that are in our parsed
36 // stylesheet selectors and making those CSS classes and ids unique to that 52 // stylesheet selectors and making those CSS classes and ids unique to that
37 // component. 53 // component.
38 if (options.verbose) { 54 if (options.verbose) {
39 print(" CSS fixup ${path.basename(fileInfo.inputUrl.resolvedPath)}"); 55 print(" CSS fixup ${path.basename(fileInfo.inputUrl.resolvedPath)}");
40 } 56 }
41 for (var component in fileInfo.declaredComponents) { 57 for (var component in fileInfo.declaredComponents) {
42 // Mangle class names and element ids in the HTML to match the stylesheet. 58 // Mangle class names and element ids in the HTML to match the stylesheet.
43 // TODO(terry): Allow more than one style sheet per component. 59 // TODO(terry): Allow more than one style sheet per component.
44 if (component.styleSheets.length == 1) { 60 if (component.styleSheets.length == 1) {
45 // For components only 1 stylesheet allowed. 61 // For components only 1 stylesheet allowed.
46 var styleSheet = component.styleSheets[0]; 62 var styleSheet = component.styleSheets[0];
47 var prefix = polyfillKind(component) == CssPolyfillKind.MANGLED_POLYFILL ? 63 var prefix = CssPolyfillKind.of(options, component) ==
48 component.tagName : null; 64 CssPolyfillKind.MANGLED_POLYFILL ? component.tagName : null;
49 65
50 // List of referenced #id and .class in CSS. 66 // List of referenced #id and .class in CSS.
51 var knownCss = new IdClassVisitor()..visitTree(styleSheet); 67 var knownCss = new IdClassVisitor()..visitTree(styleSheet);
52 // Prefix all id and class refs in CSS selectors and HTML attributes. 68 // Prefix all id and class refs in CSS selectors and HTML attributes.
53 new _ScopedStyleRenamer(knownCss, prefix, options.debugCss) 69 new _ScopedStyleRenamer(knownCss, prefix, options.debugCss)
54 .visit(component.elementNode); 70 .visit(component.element);
55 } 71 }
56 } 72 }
57 } 73 }
58 74
59 /** Build list of every CSS class name and id selector in a stylesheet. */ 75 /** Build list of every CSS class name and id selector in a stylesheet. */
60 class IdClassVisitor extends Visitor { 76 class IdClassVisitor extends Visitor {
61 final Set<String> classes = new Set(); 77 final Set<String> classes = new Set();
62 final Set<String> ids = new Set(); 78 final Set<String> ids = new Set();
63 79
64 void visitClassSelector(ClassSelector node) { 80 void visitClassSelector(ClassSelector node) {
65 classes.add(node.name); 81 classes.add(node.name);
66 } 82 }
67 83
68 void visitIdSelector(IdSelector node) { 84 void visitIdSelector(IdSelector node) {
69 ids.add(node.name); 85 ids.add(node.name);
70 } 86 }
71 } 87 }
72 88
73 /** Build the Dart map of managled class/id names and component tag name. */ 89 /** Build the Dart map of managled class/id names and component tag name. */
74 Map _createCssSimpleSelectors(IdClassVisitor visitedCss, ComponentInfo info, 90 Map _createCssSimpleSelectors(IdClassVisitor visitedCss, ComponentInfo info,
75 bool mangleNames) { 91 CssPolyfillKind kind) {
92 bool mangleNames = kind == CssPolyfillKind.MANGLED_POLYFILL;
76 Map selectors = {}; 93 Map selectors = {};
77 if (visitedCss != null) { 94 if (visitedCss != null) {
78 for (var cssClass in visitedCss.classes) { 95 for (var cssClass in visitedCss.classes) {
79 selectors['.$cssClass'] = 96 selectors['.$cssClass'] =
80 mangleNames ? '${info.tagName}_$cssClass' : cssClass; 97 mangleNames ? '${info.tagName}_$cssClass' : cssClass;
81 } 98 }
82 for (var id in visitedCss.ids) { 99 for (var id in visitedCss.ids) {
83 selectors['#$id'] = mangleNames ? '${info.tagName}_$id' : id; 100 selectors['#$id'] = mangleNames ? '${info.tagName}_$id' : id;
84 } 101 }
85 } 102 }
86 103
87 // Add tag name selector x-comp == [is="x-comp"]. 104 // Add tag name selector x-comp == [is="x-comp"].
88 var componentName = info.tagName; 105 var componentName = info.tagName;
89 selectors['$componentName'] = '[is="$componentName"]'; 106 selectors['$componentName'] = '[is="$componentName"]';
90 107
91 return selectors; 108 return selectors;
92 } 109 }
93 110
94 /** 111 /**
95 * Return a map of simple CSS selectors (class and id selectors) as a Dart map 112 * Return a map of simple CSS selectors (class and id selectors) as a Dart map
96 * definition. 113 * definition.
97 */ 114 */
98 String createCssSelectorsExpression(ComponentInfo info, bool mangled) { 115 String createCssSelectorsExpression(ComponentInfo info, CssPolyfillKind kind) {
99 var cssVisited = new IdClassVisitor(); 116 var cssVisited = new IdClassVisitor();
100 117
101 // For components only 1 stylesheet allowed. 118 // For components only 1 stylesheet allowed.
102 if (!info.styleSheets.isEmpty && info.styleSheets.length == 1) { 119 if (!info.styleSheets.isEmpty && info.styleSheets.length == 1) {
103 var styleSheet = info.styleSheets[0]; 120 var styleSheet = info.styleSheets[0];
104 cssVisited..visitTree(styleSheet); 121 cssVisited..visitTree(styleSheet);
105 } 122 }
106 123
107 return json.stringify(_createCssSimpleSelectors(cssVisited, info, mangled)); 124 return json.stringify(_createCssSimpleSelectors(cssVisited, info, kind));
108 } 125 }
109 126
110 // TODO(terry): Need to handle other selectors than IDs/classes like tag name 127 // TODO(terry): Need to handle other selectors than IDs/classes like tag name
111 // e.g., DIV { color: red; } 128 // e.g., DIV { color: red; }
112 // TODO(terry): Would be nice if we didn't need to mangle names; requires users 129 // TODO(terry): Would be nice if we didn't need to mangle names; requires users
113 // to be careful in their code and makes it more than a "polyfill". 130 // to be careful in their code and makes it more than a "polyfill".
114 // Maybe mechanism that generates CSS class name for scoping. This 131 // Maybe mechanism that generates CSS class name for scoping. This
115 // would solve tag name selectors (see above TODO). 132 // would solve tag name selectors (see above TODO).
116 /** 133 /**
117 * Fix a component's HTML to implement scoped stylesheets. 134 * Fix a component's HTML to implement scoped stylesheets.
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 /** List of @imports found. */ 555 /** List of @imports found. */
539 List<UrlInfo> imports = []; 556 List<UrlInfo> imports = [];
540 557
541 CssStyleTag(this._packageRoot, this._info, this._inputUrl, this._messages, 558 CssStyleTag(this._packageRoot, this._info, this._inputUrl, this._messages,
542 this._options); 559 this._options);
543 560
544 void visitElement(Element node) { 561 void visitElement(Element node) {
545 // Don't process any style tags inside of element if we're processing a 562 // Don't process any style tags inside of element if we're processing a
546 // FileInfo. The style tags inside of a component defintion will be 563 // FileInfo. The style tags inside of a component defintion will be
547 // processed when _info is a ComponentInfo. 564 // processed when _info is a ComponentInfo.
548 if (node.tagName == 'element' && _info is FileInfo) return; 565 if (node.tagName == 'polymer-element' && _info is FileInfo) return;
549 if (node.tagName == 'style') { 566 if (node.tagName == 'style') {
550 // Parse the contents of the scoped style tag. 567 // Parse the contents of the scoped style tag.
551 var styleSheet = parseCss(node.nodes.single.value, _messages, _options); 568 var styleSheet = parseCss(node.nodes.single.value, _messages, _options);
552 if (styleSheet != null) { 569 if (styleSheet != null) {
553 _info.styleSheets.add(styleSheet); 570 _info.styleSheets.add(styleSheet);
554 571
555 // TODO(terry): Check on scoped attribute there's a rumor that styles 572 // TODO(terry): Check on scoped attribute there's a rumor that styles
556 // might always be scoped in a component. 573 // might always be scoped in a component.
557 // TODO(terry): May need to handle multiple style tags some with scoped 574 // TODO(terry): May need to handle multiple style tags some with scoped
558 // and some without for now first style tag determines how 575 // and some without for now first style tag determines how
559 // CSS is emitted. 576 // CSS is emitted.
560 if (node.attributes.containsKey('scoped') && _info is ComponentInfo) { 577 if (node.attributes.containsKey('scoped') && _info is ComponentInfo) {
561 (_info as ComponentInfo).scoped = true; 578 (_info as ComponentInfo).scoped = true;
562 } 579 }
563 580
564 // Find all imports return list of @imports in this style tag. 581 // Find all imports return list of @imports in this style tag.
565 var urlInfos = findImportsInStyleSheet(styleSheet, _packageRoot, 582 var urlInfos = findImportsInStyleSheet(styleSheet, _packageRoot,
566 _inputUrl, _messages); 583 _inputUrl, _messages);
567 imports.addAll(urlInfos); 584 imports.addAll(urlInfos);
568 } 585 }
569 } 586 }
570 super.visitElement(node); 587 super.visitElement(node);
571 } 588 }
572 } 589 }
OLDNEW
« lib/polymer_element.dart ('K') | « lib/src/emitters.dart ('k') | lib/src/info.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698