| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 /** | 5 /** |
| 6 * Part of the template compilation that concerns with extracting information | 6 * Part of the template compilation that concerns with extracting information |
| 7 * from the HTML parse tree. | 7 * from the HTML parse tree. |
| 8 */ | 8 */ |
| 9 library analyzer; | 9 library analyzer; |
| 10 | 10 |
| 11 import 'dart:uri'; |
| 11 import 'package:html5lib/dom.dart'; | 12 import 'package:html5lib/dom.dart'; |
| 12 import 'package:html5lib/dom_parsing.dart'; | 13 import 'package:html5lib/dom_parsing.dart'; |
| 13 import 'package:source_maps/span.dart'; | 14 import 'package:source_maps/span.dart'; |
| 14 | 15 |
| 15 import 'dart_parser.dart'; | 16 import 'dart_parser.dart'; |
| 16 import 'file_system/path.dart'; | 17 import 'file_system/path.dart'; |
| 17 import 'files.dart'; | 18 import 'files.dart'; |
| 18 import 'html5_utils.dart'; | 19 import 'html5_utils.dart'; |
| 19 import 'info.dart'; | 20 import 'info.dart'; |
| 20 import 'messages.dart'; | 21 import 'messages.dart'; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 // child nodes and get their infos, and if any of them need data binding, | 113 // child nodes and get their infos, and if any of them need data binding, |
| 113 // we create an ElementInfo for ourselves and return it, otherwise we just | 114 // we create an ElementInfo for ourselves and return it, otherwise we just |
| 114 // return null. | 115 // return null. |
| 115 if (info == null) { | 116 if (info == null) { |
| 116 // <element> tags are tracked in the file's declared components, so they | 117 // <element> tags are tracked in the file's declared components, so they |
| 117 // don't need a parent. | 118 // don't need a parent. |
| 118 var parent = node.tagName == 'element' ? null : _parent; | 119 var parent = node.tagName == 'element' ? null : _parent; |
| 119 info = new ElementInfo(node, parent); | 120 info = new ElementInfo(node, parent); |
| 120 } | 121 } |
| 121 | 122 |
| 122 // TODO(terry): How to handle <link rel="stylesheet" href="..."> | |
| 123 // - What if multiple stylesheet links for a component? | |
| 124 // - What if a stylesheet link for all component and particular | |
| 125 // stylesheet links for each component? | |
| 126 // - What if multiple <style> tags for the same component? | |
| 127 if (node.tagName == 'style' && node.attributes.containsKey("scoped")) { | |
| 128 // TODO(terry): Faster to parse the CSS tags separately instead of | |
| 129 // concatenating all styles. | |
| 130 // Get contents of style tag. | |
| 131 _currentInfo.cssSource.write(node.nodes.single.value); | |
| 132 } | |
| 133 | |
| 134 visitElementInfo(info); | 123 visitElementInfo(info); |
| 135 | 124 |
| 136 if (_parent == null) { | 125 if (_parent == null) { |
| 137 _fileInfo.bodyInfo = info; | 126 _fileInfo.bodyInfo = info; |
| 138 } | 127 } |
| 139 } | 128 } |
| 140 | 129 |
| 141 void visitElementInfo(ElementInfo info) { | 130 void visitElementInfo(ElementInfo info) { |
| 142 var node = info.node; | 131 var node = info.node; |
| 143 | 132 |
| (...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 753 } | 742 } |
| 754 } | 743 } |
| 755 | 744 |
| 756 /** | 745 /** |
| 757 * Process `link rel="component"` as specified in: | 746 * Process `link rel="component"` as specified in: |
| 758 * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/components/index.ht
ml#link-type-component> | 747 * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/components/index.ht
ml#link-type-component> |
| 759 */ | 748 */ |
| 760 void visitLinkElement(Element node) { | 749 void visitLinkElement(Element node) { |
| 761 // TODO(jmesserly): deprecate the plural form, it is singular in the spec. | 750 // TODO(jmesserly): deprecate the plural form, it is singular in the spec. |
| 762 var rel = node.attributes['rel']; | 751 var rel = node.attributes['rel']; |
| 763 if (rel != 'component' && rel != 'components') return; | 752 if (rel != 'component' && rel != 'components' && |
| 753 rel != 'stylesheet') return; |
| 764 | 754 |
| 765 if (!_inHead) { | 755 if (!_inHead) { |
| 766 _messages.warning('link rel="$rel" only valid in ' | 756 _messages.warning('link rel="$rel" only valid in ' |
| 767 'head.', node.sourceSpan, file: _fileInfo.path); | 757 'head.', node.sourceSpan, file: _fileInfo.path); |
| 768 return; | 758 return; |
| 769 } | 759 } |
| 770 | 760 |
| 771 var href = node.attributes['href']; | 761 var href = node.attributes['href']; |
| 772 if (href == null || href == '') { | 762 if (href == null || href == '') { |
| 773 _messages.warning('link rel="$rel" missing href.', | 763 _messages.warning('link rel="$rel" missing href.', |
| 774 node.sourceSpan, file: _fileInfo.path); | 764 node.sourceSpan, file: _fileInfo.path); |
| 775 return; | 765 return; |
| 776 } | 766 } |
| 777 | 767 |
| 778 var path; | 768 var path; |
| 779 if (href.startsWith('package:')) { | 769 if (href.startsWith('package:')) { |
| 780 path = _packageRoot.join(new Path(href.substring(8))); | 770 path = _packageRoot.join(new Path(href.substring(8))); |
| 781 } else { | 771 } else { |
| 782 path = _fileInfo.path.directoryPath.join(new Path(href)); | 772 path = _fileInfo.path.directoryPath.join(new Path(href)); |
| 783 } | 773 } |
| 784 | 774 |
| 785 _fileInfo.componentLinks.add(path); | 775 if (rel == 'component' || rel == 'components') { |
| 776 _fileInfo.componentLinks.add(path); |
| 777 } else { |
| 778 assert(rel == 'stylesheet'); |
| 779 // Local stylesheets only are handled. |
| 780 var scheme = Uri.parse(href).scheme; |
| 781 if (scheme != 'http' && scheme != 'https') { |
| 782 _fileInfo.styleSheetHref.add(path); |
| 783 } |
| 784 } |
| 786 } | 785 } |
| 787 | 786 |
| 788 void visitElementElement(Element node) { | 787 void visitElementElement(Element node) { |
| 789 // TODO(jmesserly): what do we do in this case? It seems like an <element> | 788 // TODO(jmesserly): what do we do in this case? It seems like an <element> |
| 790 // inside a Shadow DOM should be scoped to that <template> tag, and not | 789 // inside a Shadow DOM should be scoped to that <template> tag, and not |
| 791 // visible from the outside. | 790 // visible from the outside. |
| 792 if (_currentInfo is ComponentInfo) { | 791 if (_currentInfo is ComponentInfo) { |
| 793 _messages.error('Nested component definitions are not yet supported.', | 792 _messages.error('Nested component definitions are not yet supported.', |
| 794 node.sourceSpan, file: _fileInfo.path); | 793 node.sourceSpan, file: _fileInfo.path); |
| 795 return; | 794 return; |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 996 if (start == null) moveNext(); | 995 if (start == null) moveNext(); |
| 997 if (start < length) { | 996 if (start < length) { |
| 998 do { | 997 do { |
| 999 bindings.add(binding); | 998 bindings.add(binding); |
| 1000 content.add(textContent); | 999 content.add(textContent); |
| 1001 } while (moveNext()); | 1000 } while (moveNext()); |
| 1002 } | 1001 } |
| 1003 content.add(textContent); | 1002 content.add(textContent); |
| 1004 } | 1003 } |
| 1005 } | 1004 } |
| OLD | NEW |