| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library polymer.src.css_emitters; | |
| 6 | |
| 7 import 'package:csslib/visitor.dart' show Visitor, CssPrinter, ElementSelector, | |
| 8 UriTerm, Selector, HostDirective, SimpleSelectorSequence, StyleSheet; | |
| 9 | |
| 10 import 'info.dart'; | |
| 11 | |
| 12 | |
| 13 /** Emit the contents of the style tag outside of a component. */ | |
| 14 String emitStyleSheet(StyleSheet ss, FileInfo file) => | |
| 15 (new _CssEmitter(file.components.keys.toSet()) | |
| 16 ..visitTree(ss, pretty: true)).toString(); | |
| 17 | |
| 18 /** Emit a component's style tag content emulating scoped css. */ | |
| 19 String emitComponentStyleSheet(StyleSheet ss, String tagName) => | |
| 20 (new _ComponentCssEmitter(tagName)..visitTree(ss, pretty: true)).toString(); | |
| 21 | |
| 22 String emitOriginalCss(StyleSheet css) => | |
| 23 (new CssPrinter()..visitTree(css)).toString(); | |
| 24 | |
| 25 /** Only x-tag name element selectors are emitted as [is="x-"]. */ | |
| 26 class _CssEmitter extends CssPrinter { | |
| 27 final Set _componentsTag; | |
| 28 _CssEmitter(this._componentsTag); | |
| 29 | |
| 30 void visitElementSelector(ElementSelector node) { | |
| 31 // If element selector is a component's tag name, then change selector to | |
| 32 // find element who's is attribute's the component's name. | |
| 33 if (_componentsTag.contains(node.name)) { | |
| 34 emit('[is="${node.name}"]'); | |
| 35 return; | |
| 36 } | |
| 37 super.visitElementSelector(node); | |
| 38 } | |
| 39 } | |
| 40 | |
| 41 /** | |
| 42 * Emits a css stylesheet applying rules to emulate scoped css. The rules adjust | |
| 43 * element selectors to include the component's tag name. | |
| 44 */ | |
| 45 class _ComponentCssEmitter extends CssPrinter { | |
| 46 final String _componentTagName; | |
| 47 bool _inHostDirective = false; | |
| 48 bool _selectorStartInHostDirective = false; | |
| 49 | |
| 50 _ComponentCssEmitter(this._componentTagName); | |
| 51 | |
| 52 /** Is the element selector an x-tag name. */ | |
| 53 bool _isSelectorElementXTag(Selector node) { | |
| 54 if (node.simpleSelectorSequences.length > 0) { | |
| 55 var selector = node.simpleSelectorSequences[0].simpleSelector; | |
| 56 return selector is ElementSelector && selector.name == _componentTagName; | |
| 57 } | |
| 58 return false; | |
| 59 } | |
| 60 | |
| 61 void visitSelector(Selector node) { | |
| 62 // If the selector starts with an x-tag name don't emit it twice. | |
| 63 if (!_isSelectorElementXTag(node)) { | |
| 64 if (_inHostDirective) { | |
| 65 // Style the element that's hosting the component, therefore don't emit | |
| 66 // the descendent combinator (first space after the [is="x-..."]). | |
| 67 emit('[is="$_componentTagName"]'); | |
| 68 // Signal that first simpleSelector must be checked. | |
| 69 _selectorStartInHostDirective = true; | |
| 70 } else { | |
| 71 // Emit its scoped as a descendent (space at end). | |
| 72 emit('[is="$_componentTagName"] '); | |
| 73 } | |
| 74 } | |
| 75 super.visitSelector(node); | |
| 76 } | |
| 77 | |
| 78 /** | |
| 79 * If first simple selector of a ruleset in a @host directive is a wildcard | |
| 80 * then don't emit the wildcard. | |
| 81 */ | |
| 82 void visitSimpleSelectorSequence(SimpleSelectorSequence node) { | |
| 83 if (_selectorStartInHostDirective) { | |
| 84 _selectorStartInHostDirective = false; | |
| 85 if (node.simpleSelector.isWildcard) { | |
| 86 // Skip the wildcard if first item in the sequence. | |
| 87 return; | |
| 88 } | |
| 89 assert(node.isCombinatorNone); | |
| 90 } | |
| 91 | |
| 92 super.visitSimpleSelectorSequence(node); | |
| 93 } | |
| 94 | |
| 95 void visitElementSelector(ElementSelector node) { | |
| 96 // If element selector is the component's tag name, then change selector to | |
| 97 // find element who's is attribute is the component's name. | |
| 98 if (_componentTagName == node.name) { | |
| 99 emit('[is="$_componentTagName"]'); | |
| 100 return; | |
| 101 } | |
| 102 super.visitElementSelector(node); | |
| 103 } | |
| 104 | |
| 105 /** | |
| 106 * If we're polyfilling scoped styles the @host directive is stripped. Any | |
| 107 * ruleset(s) processed in an @host will fixup the first selector. See | |
| 108 * visitSelector and visitSimpleSelectorSequence in this class, they adjust | |
| 109 * the selectors so it styles the element hosting the compopnent. | |
| 110 */ | |
| 111 void visitHostDirective(HostDirective node) { | |
| 112 _inHostDirective = true; | |
| 113 emit('/* @host */'); | |
| 114 for (var ruleset in node.rulesets) { | |
| 115 ruleset.visit(this); | |
| 116 } | |
| 117 _inHostDirective = false; | |
| 118 emit('/* end of @host */\n'); | |
| 119 } | |
| 120 } | |
| OLD | NEW |