feat(compiler): Support $baseUrl in HTML attributes when loading a template.
Angular fetches template HTML files outside of the browser's normal parsing flow. As a result, URLs in template files are interpreted relative to the root application, when the components defined by the template files are inserted into the DOM. This change enables a template author to prefix URLs with the string $baseUrl, which will be replaced with the relative base path of the template file. So for an example template loaded from /component/foo/template.html: <img src="$baseUrl/logo.png" /> becomes: <img src="/component/foo/logo.png" /> Addresses #2384.
This commit is contained in:
parent
40d21b808d
commit
e94270946a
@ -1,5 +1,12 @@
|
|||||||
import {Injectable} from 'angular2/di';
|
import {Injectable} from 'angular2/di';
|
||||||
import {isBlank, isPresent, BaseException, stringify, isPromise} from 'angular2/src/facade/lang';
|
import {
|
||||||
|
isBlank,
|
||||||
|
isPresent,
|
||||||
|
BaseException,
|
||||||
|
stringify,
|
||||||
|
isPromise,
|
||||||
|
StringWrapper
|
||||||
|
} from 'angular2/src/facade/lang';
|
||||||
import {Map, MapWrapper, ListWrapper, List} from 'angular2/src/facade/collection';
|
import {Map, MapWrapper, ListWrapper, List} from 'angular2/src/facade/collection';
|
||||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
@ -82,9 +89,17 @@ export class ViewLoader {
|
|||||||
throw new BaseException('View should have either the templateUrl or template property set');
|
throw new BaseException('View should have either the templateUrl or template property set');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline the style tags from the html
|
|
||||||
return html.then(html => {
|
return html.then(html => {
|
||||||
var tplEl = DOM.createTemplate(html);
|
var tplEl = DOM.createTemplate(html);
|
||||||
|
|
||||||
|
// Replace $baseUrl with the base url for the template
|
||||||
|
let templateAbsUrl = view.templateAbsUrl;
|
||||||
|
if (isPresent(templateAbsUrl) && templateAbsUrl.indexOf("/") >= 0) {
|
||||||
|
let baseUrl = templateAbsUrl.substring(0, templateAbsUrl.lastIndexOf("/"));
|
||||||
|
this._substituteBaseUrl(DOM.content(tplEl), baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inline the style tags from the html
|
||||||
let styleEls = DOM.querySelectorAll(DOM.content(tplEl), 'STYLE');
|
let styleEls = DOM.querySelectorAll(DOM.content(tplEl), 'STYLE');
|
||||||
|
|
||||||
let promises: List<Promise<string>> = [];
|
let promises: List<Promise<string>> = [];
|
||||||
@ -99,6 +114,31 @@ export class ViewLoader {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace all occurrences of $baseUrl in the attributes of an element and its
|
||||||
|
* children with the base URL of the template.
|
||||||
|
*
|
||||||
|
* @param element The element to process
|
||||||
|
* @param baseUrl The base URL of the template.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private _substituteBaseUrl(element, baseUrl: string): void {
|
||||||
|
if (DOM.isElementNode(element)) {
|
||||||
|
var attrs = DOM.attributeMap(element);
|
||||||
|
MapWrapper.forEach(attrs, (v, k) => {
|
||||||
|
if (isPresent(v) && v.indexOf('$baseUrl') >= 0) {
|
||||||
|
DOM.setAttribute(element, k, StringWrapper.replaceAll(v, /\$baseUrl/g, baseUrl));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let children = DOM.childNodes(element);
|
||||||
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
if (DOM.isElementNode(children[i])) {
|
||||||
|
this._substituteBaseUrl(children[i], baseUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inlines a style element.
|
* Inlines a style element.
|
||||||
*
|
*
|
||||||
|
@ -118,6 +118,16 @@ export function main() {
|
|||||||
});
|
});
|
||||||
xhr.flush();
|
xhr.flush();
|
||||||
}));
|
}));
|
||||||
|
it('should replace $baseUrl in attributes with the template base url',
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
xhr.expect('http://ng.io/path/foo.html', '<img src="$baseUrl/logo.png">');
|
||||||
|
var view = new ViewDefinition({templateAbsUrl: 'http://ng.io/path/foo.html'});
|
||||||
|
loader.load(view).then((el) => {
|
||||||
|
expect(DOM.getInnerHTML(el)).toEqual('<img src="http://ng.io/path/logo.png">');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
xhr.flush();
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('css', () => {
|
describe('css', () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user