Chromium Code Reviews| Index: pkg/polymer/lib/src/transform/import_inliner.dart |
| diff --git a/pkg/polymer/lib/src/transform/import_inliner.dart b/pkg/polymer/lib/src/transform/import_inliner.dart |
| index ac8ab7e38d418e03fecc5dff10b576c736f3e7b4..2366d5606a1eed069e3a63ff312525727d8c2a62 100644 |
| --- a/pkg/polymer/lib/src/transform/import_inliner.dart |
| +++ b/pkg/polymer/lib/src/transform/import_inliner.dart |
| @@ -8,15 +8,17 @@ library polymer.src.transform.import_inliner; |
| import 'dart:async'; |
| import 'package:barback/barback.dart'; |
| +import 'package:path/path.dart' as path; |
| import 'package:html5lib/dom.dart' show Document, Node, DocumentFragment; |
| +import 'package:html5lib/dom_parsing.dart' show TreeVisitor; |
| import 'common.dart'; |
| /** Recursively inlines polymer-element definitions from html imports. */ |
| // TODO(sigmund): make sure we match semantics of html-imports for tags other |
| // than polymer-element (see dartbug.com/12613). |
| class ImportedElementInliner extends Transformer { |
| - Future<bool> isPrimary(Asset input) => |
| - new Future.value(input.id.extension == ".html"); |
| + /** Only run this transformer on .html files. */ |
| + final String allowedExtensions = ".html"; |
| Future apply(Transform transform) { |
| var seen = new Set<AssetId>(); |
| @@ -78,14 +80,91 @@ class ImportedElementInliner extends Transformer { |
| * Loads an asset identified by [id], visits its imports and collects it's |
| * polymer-element definitions. |
| */ |
| - Future _collectPolymerElements( |
| - AssetId id, Transform transform, Set<AssetId> seen, List elements) { |
| - return getContent(transform, id) |
| - .then((content) => parseHtml( |
| - content, id.path, transform.logger, checkDocType: false)) |
| - .then((document) { |
| - return _visitImports(document, id, transform, seen, elements) |
| - .then((_) => elements.addAll(document.queryAll('polymer-element'))); |
| - }); |
| + Future _collectPolymerElements(AssetId id, Transform transform, |
| + Set<AssetId> seen, List elements) { |
| + return getContent(transform, id).then((content) { |
| + var document = parseHtml( |
| + content, id.path, transform.logger, checkDocType: false); |
| + return _visitImports(document, id, transform, seen, elements).then((_) { |
| + var normalizer = new _UrlNormalizer(transform, id); |
| + for (var element in document.queryAll('polymer-element')) { |
| + normalizer.visit(document); |
| + elements.add(element); |
| + } |
| + }); |
| + }); |
| } |
| } |
| + |
| +/** Internally adjusts urls in the html that we are about to inline. */ |
| +class _UrlNormalizer extends TreeVisitor { |
| + final Transform transform; |
| + |
| + /** Asset where the original content (and original url) was found. */ |
| + final AssetId sourceId; |
| + |
| + _UrlNormalizer(this.transform, this.sourceId); |
| + |
| + visitElement(Element node) { |
| + for (var key in node.attributes.keys) { |
| + if (_urlAttributes.contains(key)) { |
| + var url = node.attributes[key]; |
| + if (url != null && url != '') { |
| + node.attributes[key] = _newUrl(url, node.sourceSpan); |
| + } |
| + } |
| + } |
| + super.visitElement(node); |
| + } |
| + |
| + _newUrl(String href, Span span) { |
| + var uri = Uri.parse(href); |
| + if (uri.isAbsolute) return href; |
| + if (!uri.scheme.isEmpty) return href; |
| + if (!uri.host.isEmpty) return href; |
| + if (uri.path.isEmpty) return href; // Implies standalone ? or # in URI. |
| + if (path.isAbsolute(href)) return href; |
| + |
| + var id = resolve(sourceId, href, transform.logger, span); |
| + var primaryId = transform.primaryId; |
| + |
| + if (id.path.startsWith('lib/')) { |
| + return 'packages/${id.package}/${id.path.substring(4)}'; |
| + } |
| + |
| + if (id.path.startsWith('asset/')) { |
| + return 'assets/${id.package}/${id.path.substring(6)}'; |
| + } |
| + |
| + if (primaryId.package != id.package) { |
| + // Techincally we shouldn't get there |
| + logger.error("don't know how to include $id from $primaryId", span); |
| + return null; |
| + } |
| + |
| + var builder = path.url; |
| + return builder.relative(builder.join('/', id.path), |
| + from: builder.join('/', builder.dirname(primaryId.path))); |
| + } |
| +} |
| + |
| +/** |
| + * HTML attributes that expect a URL value. |
| + * <http://dev.w3.org/html5/spec/section-index.html#attributes-1> |
| + * |
| + * Every one of these attributes is a URL in every context where it is used in |
| + * the DOM. The comments show every DOM element where an attribute can be used. |
| + */ |
| +const _urlAttributes = const [ |
|
Jennifer Messerly
2013/08/28 22:25:45
interesting. FWIW, this is a much bigger list than
Siggi Cherem (dart-lang)
2013/08/28 23:17:06
good point, totally.
Siggi Cherem (dart-lang)
2013/08/28 23:36:34
filed here: https://github.com/Polymer/HTMLImports
|
| + 'action', // in form |
| + 'background', // in body |
| + 'cite', // in blockquote, del, ins, q |
| + 'data', // in object |
| + 'formaction', // in button, input |
| + 'href', // in a, area, link, base, command |
| + 'icon', // in command |
| + 'manifest', // in html |
| + 'poster', // in video |
| + 'src', // in audio, embed, iframe, img, input, script, source, track, |
| + // video |
| +]; |