diff --git a/modules/angular2/src/core/compiler/style_compiler.ts b/modules/angular2/src/core/compiler/style_compiler.ts index 139ad9bef2..3b89379013 100644 --- a/modules/angular2/src/core/compiler/style_compiler.ts +++ b/modules/angular2/src/core/compiler/style_compiler.ts @@ -6,7 +6,7 @@ import {StringWrapper, isBlank} from 'angular2/src/core/facade/lang'; import {PromiseWrapper, Promise} from 'angular2/src/core/facade/async'; import {ShadowCss} from 'angular2/src/core/compiler/shadow_css'; import {UrlResolver} from 'angular2/src/core/compiler/url_resolver'; -import {resolveStyleUrls} from './style_url_resolver'; +import {extractStyleUrls} from './style_url_resolver'; import { escapeSingleQuoteString, IS_DART, @@ -58,7 +58,7 @@ export class StyleCompiler { } compileStylesheetCodeGen(stylesheetUrl: string, cssText: string): SourceModule[] { - var styleWithImports = resolveStyleUrls(this._urlResolver, stylesheetUrl, cssText); + var styleWithImports = extractStyleUrls(this._urlResolver, stylesheetUrl, cssText); return [ this._styleModule( stylesheetUrl, false, @@ -78,7 +78,7 @@ export class StyleCompiler { var result = this._styleCache.get(cacheKey); if (isBlank(result)) { result = this._xhr.get(absUrl).then((style) => { - var styleWithImports = resolveStyleUrls(this._urlResolver, absUrl, style); + var styleWithImports = extractStyleUrls(this._urlResolver, absUrl, style); return this._loadStyles([styleWithImports.style], styleWithImports.styleUrls, encapsulate); }); diff --git a/modules/angular2/src/core/compiler/style_url_resolver.ts b/modules/angular2/src/core/compiler/style_url_resolver.ts index b1acc89cbe..a95352392f 100644 --- a/modules/angular2/src/core/compiler/style_url_resolver.ts +++ b/modules/angular2/src/core/compiler/style_url_resolver.ts @@ -1,60 +1,45 @@ // Some of the code comes from WebComponents.JS // https://github.com/webcomponents/webcomponentsjs/blob/master/src/HTMLImports/path.js -import {RegExp, RegExpWrapper, StringWrapper, isPresent} from 'angular2/src/core/facade/lang'; +import { + RegExp, + RegExpWrapper, + StringWrapper, + isPresent, + isBlank +} from 'angular2/src/core/facade/lang'; import {UrlResolver} from 'angular2/src/core/compiler/url_resolver'; -/** - * Rewrites URLs by resolving '@import' and 'url()' URLs from the given base URL, - * removes and returns the @import urls - */ -export function resolveStyleUrls(resolver: UrlResolver, baseUrl: string, cssText: string): - StyleWithImports { - var foundUrls = []; - cssText = extractUrls(resolver, baseUrl, cssText, foundUrls); - cssText = replaceUrls(resolver, baseUrl, cssText); - return new StyleWithImports(cssText, foundUrls); -} - export class StyleWithImports { constructor(public style: string, public styleUrls: string[]) {} } -function extractUrls(resolver: UrlResolver, baseUrl: string, cssText: string, foundUrls: string[]): - string { - return StringWrapper.replaceAllMapped(cssText, _cssImportRe, (m) => { +export function isStyleUrlResolvable(url: string): boolean { + if (isBlank(url) || url.length === 0) return false; + var schemeMatch = RegExpWrapper.firstMatch(_urlWithSchemaRe, url); + return isBlank(schemeMatch) || schemeMatch[1] == 'package'; +} + +/** + * Rewrites stylesheets by resolving and removing the @import urls that + * are either relative or don't have a `package:` scheme + */ +export function extractStyleUrls(resolver: UrlResolver, baseUrl: string, cssText: string): + StyleWithImports { + var foundUrls = []; + var modifiedCssText = StringWrapper.replaceAllMapped(cssText, _cssImportRe, (m) => { var url = isPresent(m[1]) ? m[1] : m[2]; - var schemeMatch = RegExpWrapper.firstMatch(_urlWithSchemaRe, url); - if (isPresent(schemeMatch) && schemeMatch[1] != 'package') { + if (!isStyleUrlResolvable(url)) { // Do not attempt to resolve non-package absolute URLs with URI scheme return m[0]; } foundUrls.push(resolver.resolve(baseUrl, url)); return ''; }); + return new StyleWithImports(modifiedCssText, foundUrls); } -function replaceUrls(resolver: UrlResolver, baseUrl: string, cssText: string): string { - return StringWrapper.replaceAllMapped(cssText, _cssUrlRe, (m) => { - var pre = m[1]; - var originalUrl = m[2]; - if (RegExpWrapper.test(_dataUrlRe, originalUrl)) { - // Do not attempt to resolve data: URLs - return m[0]; - } - var url = StringWrapper.replaceAll(originalUrl, _quoteRe, ''); - var post = m[3]; - - var resolvedUrl = resolver.resolve(baseUrl, url); - - return pre + "'" + resolvedUrl + "'" + post; - }); -} - -var _cssUrlRe = /(url\()([^)]*)(\))/g; var _cssImportRe = /@import\s+(?:url\()?\s*(?:(?:['"]([^'"]*))|([^;\)\s]*))[^;]*;?/g; -var _quoteRe = /['"]/g; -var _dataUrlRe = /^['"]?data:/g; // TODO: can't use /^[^:/?#.]+:/g due to clang-format bug: // https://github.com/angular/angular/issues/4596 -var _urlWithSchemaRe = /^['"]?([a-zA-Z\-\+\.]+):/g; +var _urlWithSchemaRe = /^['"]?([a-zA-Z\-\+\.]+):/g; \ No newline at end of file diff --git a/modules/angular2/src/core/compiler/template_normalizer.ts b/modules/angular2/src/core/compiler/template_normalizer.ts index a1114cae85..05970cf1b4 100644 --- a/modules/angular2/src/core/compiler/template_normalizer.ts +++ b/modules/angular2/src/core/compiler/template_normalizer.ts @@ -4,12 +4,13 @@ import { CompileTemplateMetadata } from './directive_metadata'; import {isPresent, isBlank} from 'angular2/src/core/facade/lang'; +import {ListWrapper} from 'angular2/src/core/facade/collection'; import {BaseException} from 'angular2/src/core/facade/exceptions'; import {Promise, PromiseWrapper} from 'angular2/src/core/facade/async'; import {XHR} from 'angular2/src/core/compiler/xhr'; import {UrlResolver} from 'angular2/src/core/compiler/url_resolver'; -import {resolveStyleUrls} from './style_url_resolver'; +import {extractStyleUrls, isStyleUrlResolvable} from './style_url_resolver'; import {Injectable} from 'angular2/src/core/di'; import {ViewEncapsulation} from 'angular2/src/core/metadata/view'; @@ -57,9 +58,9 @@ export class TemplateNormalizer { visitor.styleUrls.map(url => this._urlResolver.resolve(templateAbsUrl, url)) .concat(templateMeta.styleUrls.map( url => this._urlResolver.resolve(directiveType.moduleUrl, url))); - + allStyleAbsUrls = ListWrapper.filter(allStyleAbsUrls, isStyleUrlResolvable); var allResolvedStyles = allStyles.map(style => { - var styleWithImports = resolveStyleUrls(this._urlResolver, templateAbsUrl, style); + var styleWithImports = extractStyleUrls(this._urlResolver, templateAbsUrl, style); styleWithImports.styleUrls.forEach(styleUrl => allStyleAbsUrls.push(styleUrl)); return styleWithImports.style; }); diff --git a/modules/angular2/src/core/compiler/template_parser.ts b/modules/angular2/src/core/compiler/template_parser.ts index c68991f962..452e45a3ef 100644 --- a/modules/angular2/src/core/compiler/template_parser.ts +++ b/modules/angular2/src/core/compiler/template_parser.ts @@ -40,6 +40,8 @@ import {CssSelector, SelectorMatcher} from 'angular2/src/core/compiler/selector' import {ElementSchemaRegistry} from 'angular2/src/core/compiler/schema/element_schema_registry'; import {preparseElement, PreparsedElement, PreparsedElementType} from './template_preparser'; +import {isStyleUrlResolvable} from './style_url_resolver'; + import { HtmlAstVisitor, HtmlAst, @@ -165,10 +167,16 @@ class TemplateParseVisitor implements HtmlAstVisitor { var nodeName = element.name; var preparsedElement = preparseElement(element); if (preparsedElement.type === PreparsedElementType.SCRIPT || - preparsedElement.type === PreparsedElementType.STYLE || - preparsedElement.type === PreparsedElementType.STYLESHEET) { + preparsedElement.type === PreparsedElementType.STYLE) { // Skipping