refactor(shadow_dom): remove ShadowDomStrategy in favor of @View(encapsulation)
BREAKING CHANGES: - `ShadowDomStrategy` was removed. To specify the encapsulation of a component use `@View(encapsulation: ViewEncapsulation.NONE | ViewEncapsulation.EMULATED | ViewEncapsulation.NATIVE)` - The default encapsulation strategy is now `ViewEncapsulation.EMULATED` if a component contains styles and `ViewEncapsulation.NONE` if it does not. Before this was always `NONE`. - `ViewLoader` now returns the template as a string and the styles as a separate array
This commit is contained in:
@@ -17,26 +17,38 @@ import {Type, isBlank, stringify, isPresent, BaseException} from 'angular2/src/f
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
|
||||
import {DomCompiler} from 'angular2/src/render/dom/compiler/compiler';
|
||||
import {ProtoViewDto, ViewDefinition, DirectiveMetadata, ViewType} from 'angular2/src/render/api';
|
||||
import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element';
|
||||
import {
|
||||
ProtoViewDto,
|
||||
ViewDefinition,
|
||||
DirectiveMetadata,
|
||||
ViewType,
|
||||
ViewEncapsulation
|
||||
} from 'angular2/src/render/api';
|
||||
import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step';
|
||||
import {CompileStepFactory} from 'angular2/src/render/dom/compiler/compile_step_factory';
|
||||
import {CompileControl} from 'angular2/src/render/dom/compiler/compile_control';
|
||||
import {ViewLoader} from 'angular2/src/render/dom/compiler/view_loader';
|
||||
import {ViewLoader, TemplateAndStyles} from 'angular2/src/render/dom/compiler/view_loader';
|
||||
|
||||
import {resolveInternalDomProtoView} from 'angular2/src/render/dom/view/proto_view';
|
||||
import {SharedStylesHost} from 'angular2/src/render/dom/view/shared_styles_host';
|
||||
|
||||
import {MockStep} from './pipeline_spec';
|
||||
|
||||
export function runCompilerCommonTests() {
|
||||
describe('DomCompiler', function() {
|
||||
var mockStepFactory: MockStepFactory;
|
||||
var sharedStylesHost: SharedStylesHost;
|
||||
|
||||
function createCompiler(processClosure, urlData = null) {
|
||||
beforeEach(() => {sharedStylesHost = new SharedStylesHost()});
|
||||
|
||||
function createCompiler(processElementClosure = null, processStyleClosure = null,
|
||||
urlData = null) {
|
||||
if (isBlank(urlData)) {
|
||||
urlData = new Map();
|
||||
}
|
||||
var tplLoader = new FakeViewLoader(urlData);
|
||||
mockStepFactory = new MockStepFactory([new MockStep(processClosure)]);
|
||||
return new DomCompiler(mockStepFactory, tplLoader, false);
|
||||
mockStepFactory =
|
||||
new MockStepFactory([new MockStep(processElementClosure, processStyleClosure)]);
|
||||
return new DomCompiler(mockStepFactory, tplLoader, sharedStylesHost);
|
||||
}
|
||||
|
||||
describe('compile', () => {
|
||||
@@ -61,12 +73,13 @@ export function runCompilerCommonTests() {
|
||||
});
|
||||
|
||||
var dirMetadata = DirectiveMetadata.create(
|
||||
{id: 'id', selector: 'CUSTOM', type: DirectiveMetadata.COMPONENT_TYPE});
|
||||
{id: 'id', selector: 'custom', type: DirectiveMetadata.COMPONENT_TYPE});
|
||||
compiler.compileHost(dirMetadata)
|
||||
.then((protoView) => {
|
||||
expect(DOM.tagName(DOM.firstChild(DOM.content(
|
||||
resolveInternalDomProtoView(protoView.render).rootElement))))
|
||||
.toEqual('CUSTOM');
|
||||
resolveInternalDomProtoView(protoView.render).rootElement)))
|
||||
.toLowerCase())
|
||||
.toEqual('custom');
|
||||
expect(mockStepFactory.viewDef.directives).toEqual([dirMetadata]);
|
||||
expect(protoView.variableBindings)
|
||||
.toEqual(MapWrapper.createFromStringMap({'a': 'b'}));
|
||||
@@ -88,7 +101,7 @@ export function runCompilerCommonTests() {
|
||||
|
||||
it('should load url templates', inject([AsyncTestCompleter], (async) => {
|
||||
var urlData = MapWrapper.createFromStringMap({'someUrl': 'url component'});
|
||||
var compiler = createCompiler(EMPTY_STEP, urlData);
|
||||
var compiler = createCompiler(EMPTY_STEP, null, urlData);
|
||||
compiler.compile(new ViewDefinition({componentId: 'someId', templateAbsUrl: 'someUrl'}))
|
||||
.then((protoView) => {
|
||||
expect(DOM.getInnerHTML(resolveInternalDomProtoView(protoView.render).rootElement))
|
||||
@@ -98,7 +111,7 @@ export function runCompilerCommonTests() {
|
||||
}));
|
||||
|
||||
it('should report loading errors', inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler(EMPTY_STEP, new Map());
|
||||
var compiler = createCompiler(EMPTY_STEP, null, new Map());
|
||||
PromiseWrapper.catchError(
|
||||
compiler.compile(
|
||||
new ViewDefinition({componentId: 'someId', templateAbsUrl: 'someUrl'})),
|
||||
@@ -137,6 +150,110 @@ export function runCompilerCommonTests() {
|
||||
|
||||
});
|
||||
|
||||
describe('compile styles', () => {
|
||||
it('should run the steps', inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler(null, (style) => { return style + 'b {};'; });
|
||||
compiler.compile(new ViewDefinition(
|
||||
{componentId: 'someComponent', template: '', styles: ['a {};']}))
|
||||
.then((protoViewDto) => {
|
||||
expect(sharedStylesHost.getAllStyles()).toEqual(['a {};b {};']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should store the styles in the SharedStylesHost for ViewEncapsulation.NONE',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler();
|
||||
compiler.compile(new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '',
|
||||
styles: ['a {};'],
|
||||
encapsulation: ViewEncapsulation.NONE
|
||||
}))
|
||||
.then((protoViewDto) => {
|
||||
var domProtoView = resolveInternalDomProtoView(protoViewDto.render);
|
||||
expect(DOM.getInnerHTML(domProtoView.rootElement)).toEqual('');
|
||||
expect(sharedStylesHost.getAllStyles()).toEqual(['a {};']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should store the styles in the SharedStylesHost for ViewEncapsulation.EMULATED',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler();
|
||||
compiler.compile(new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '',
|
||||
styles: ['a {};'],
|
||||
encapsulation: ViewEncapsulation.EMULATED
|
||||
}))
|
||||
.then((protoViewDto) => {
|
||||
var domProtoView = resolveInternalDomProtoView(protoViewDto.render);
|
||||
expect(DOM.getInnerHTML(domProtoView.rootElement)).toEqual('');
|
||||
expect(sharedStylesHost.getAllStyles()).toEqual(['a {};']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
if (DOM.supportsNativeShadowDOM()) {
|
||||
it('should store the styles in the template for ViewEncapsulation.NATIVE',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler();
|
||||
compiler.compile(new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '',
|
||||
styles: ['a {};'],
|
||||
encapsulation: ViewEncapsulation.NATIVE
|
||||
}))
|
||||
.then((protoViewDto) => {
|
||||
var domProtoView = resolveInternalDomProtoView(protoViewDto.render);
|
||||
expect(DOM.getInnerHTML(domProtoView.rootElement))
|
||||
.toEqual('<style>a {};</style>');
|
||||
expect(sharedStylesHost.getAllStyles()).toEqual([]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
it('should default to ViewEncapsulation.NONE if no styles are specified',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler();
|
||||
compiler.compile(
|
||||
new ViewDefinition({componentId: 'someComponent', template: '', styles: []}))
|
||||
.then((protoView) => {
|
||||
expect(mockStepFactory.viewDef.encapsulation).toBe(ViewEncapsulation.NONE);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should default to ViewEncapsulation.EMULATED if styles are specified',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler();
|
||||
compiler.compile(new ViewDefinition(
|
||||
{componentId: 'someComponent', template: '', styles: ['a {};']}))
|
||||
.then((protoView) => {
|
||||
expect(mockStepFactory.viewDef.encapsulation).toBe(ViewEncapsulation.EMULATED);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('mergeProtoViews', () => {
|
||||
it('should store the styles of the merged ProtoView in the SharedStylesHost',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var compiler = createCompiler();
|
||||
compiler.compile(new ViewDefinition(
|
||||
{componentId: 'someComponent', template: '', styles: ['a {};']}))
|
||||
.then(protoViewDto => compiler.mergeProtoViewsRecursively([protoViewDto.render]))
|
||||
.then(_ => {
|
||||
expect(sharedStylesHost.getAllStyles()).toEqual(['a {};']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -155,14 +272,6 @@ class MockStepFactory extends CompileStepFactory {
|
||||
}
|
||||
}
|
||||
|
||||
class MockStep implements CompileStep {
|
||||
processClosure: Function;
|
||||
constructor(process) { this.processClosure = process; }
|
||||
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
this.processClosure(parent, current, control);
|
||||
}
|
||||
}
|
||||
|
||||
var EMPTY_STEP = (parent, current, control) => {
|
||||
if (isPresent(parent)) {
|
||||
current.inheritedProtoView = parent.inheritedProtoView;
|
||||
@@ -176,16 +285,17 @@ class FakeViewLoader extends ViewLoader {
|
||||
this._urlData = urlData;
|
||||
}
|
||||
|
||||
load(view: ViewDefinition): Promise<any> {
|
||||
if (isPresent(view.template)) {
|
||||
return PromiseWrapper.resolve(DOM.createTemplate(view.template));
|
||||
load(viewDef): Promise<any> {
|
||||
var styles = isPresent(viewDef.styles) ? viewDef.styles : [];
|
||||
if (isPresent(viewDef.template)) {
|
||||
return PromiseWrapper.resolve(new TemplateAndStyles(viewDef.template, styles));
|
||||
}
|
||||
|
||||
if (isPresent(view.templateAbsUrl)) {
|
||||
var content = this._urlData.get(view.templateAbsUrl);
|
||||
if (isPresent(viewDef.templateAbsUrl)) {
|
||||
var content = this._urlData.get(viewDef.templateAbsUrl);
|
||||
return isPresent(content) ?
|
||||
PromiseWrapper.resolve(DOM.createTemplate(content)) :
|
||||
PromiseWrapper.reject(`Failed to fetch url "${view.templateAbsUrl}"`, null);
|
||||
PromiseWrapper.resolve(new TemplateAndStyles(content, styles)) :
|
||||
PromiseWrapper.reject(`Failed to fetch url "${viewDef.templateAbsUrl}"`, null);
|
||||
}
|
||||
|
||||
throw new BaseException('View should have either the templateUrl or template property set');
|
||||
|
||||
@@ -4,12 +4,10 @@ import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/col
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {DirectiveParser} from 'angular2/src/render/dom/compiler/directive_parser';
|
||||
import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline';
|
||||
import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step';
|
||||
import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element';
|
||||
import {CompileControl} from 'angular2/src/render/dom/compiler/compile_control';
|
||||
import {ViewDefinition, DirectiveMetadata} from 'angular2/src/render/api';
|
||||
import {ViewDefinition, DirectiveMetadata, ViewType} from 'angular2/src/render/api';
|
||||
import {Lexer, Parser} from 'angular2/src/change_detection/change_detection';
|
||||
import {ElementBinderBuilder} from 'angular2/src/render/dom/view/proto_view_builder';
|
||||
import {MockStep} from './pipeline_spec';
|
||||
|
||||
export function main() {
|
||||
describe('DirectiveParser', () => {
|
||||
@@ -47,9 +45,15 @@ export function main() {
|
||||
]);
|
||||
}
|
||||
|
||||
function createViewDefinition(): ViewDefinition {
|
||||
return new ViewDefinition({componentId: 'someComponent'});
|
||||
}
|
||||
|
||||
function process(el, propertyBindings = null, directives = null): List<ElementBinderBuilder> {
|
||||
var pipeline = createPipeline(propertyBindings, directives);
|
||||
return ListWrapper.map(pipeline.process(el), (ce) => ce.inheritedElementBinder);
|
||||
return ListWrapper.map(
|
||||
pipeline.processElements(el, ViewType.COMPONENT, createViewDefinition()),
|
||||
(ce) => ce.inheritedElementBinder);
|
||||
}
|
||||
|
||||
it('should not add directives if they are not used', () => {
|
||||
@@ -70,12 +74,14 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should compile children by default', () => {
|
||||
var results = createPipeline().process(el('<div some-decor></div>'));
|
||||
var results = createPipeline().processElements(el('<div some-decor></div>'),
|
||||
ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].compileChildren).toEqual(true);
|
||||
});
|
||||
|
||||
it('should stop compiling children when specified in the directive config', () => {
|
||||
var results = createPipeline().process(el('<div some-decor-ignoring-children></div>'));
|
||||
var results = createPipeline().processElements(el('<div some-decor-ignoring-children></div>'),
|
||||
ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].compileChildren).toEqual(false);
|
||||
});
|
||||
|
||||
@@ -191,14 +197,6 @@ export function main() {
|
||||
});
|
||||
}
|
||||
|
||||
class MockStep implements CompileStep {
|
||||
processClosure: Function;
|
||||
constructor(process) { this.processClosure = process; }
|
||||
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
this.processClosure(parent, current, control);
|
||||
}
|
||||
}
|
||||
|
||||
var someComponent = DirectiveMetadata.create(
|
||||
{selector: 'some-comp', id: 'someComponent', type: DirectiveMetadata.COMPONENT_TYPE});
|
||||
|
||||
|
||||
@@ -9,16 +9,21 @@ import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step';
|
||||
import {CompileControl} from 'angular2/src/render/dom/compiler/compile_control';
|
||||
|
||||
import {ProtoViewBuilder} from 'angular2/src/render/dom/view/proto_view_builder';
|
||||
import {ProtoViewDto, ViewType} from 'angular2/src/render/api';
|
||||
import {ProtoViewDto, ViewType, ViewEncapsulation, ViewDefinition} from 'angular2/src/render/api';
|
||||
|
||||
export function main() {
|
||||
describe('compile_pipeline', () => {
|
||||
function createViewDefinition(): ViewDefinition {
|
||||
return new ViewDefinition({componentId: 'someComponent'});
|
||||
}
|
||||
|
||||
describe('children compilation', () => {
|
||||
it('should walk the tree in depth first order including template contents', () => {
|
||||
var element = el('<div id="1"><template id="2"><span id="3"></span></template></div>');
|
||||
|
||||
var step0Log = [];
|
||||
var results = new CompilePipeline([createLoggerStep(step0Log)]).process(element);
|
||||
var results = new CompilePipeline([createLoggerStep(step0Log)])
|
||||
.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(resultIdLog(results)).toEqual(['1', '2', '3']);
|
||||
@@ -30,7 +35,7 @@ export function main() {
|
||||
|
||||
var step0Log = [];
|
||||
var pipeline = new CompilePipeline([new IgnoreChildrenStep(), createLoggerStep(step0Log)]);
|
||||
var results = pipeline.process(element);
|
||||
var results = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
|
||||
expect(step0Log).toEqual(['1', '1<2']);
|
||||
expect(resultIdLog(results)).toEqual(['1', '2']);
|
||||
@@ -42,11 +47,12 @@ export function main() {
|
||||
var pipeline = new CompilePipeline([
|
||||
new MockStep((parent, current, control) => {
|
||||
if (isPresent(DOM.getAttribute(current.element, 'viewroot'))) {
|
||||
current.inheritedProtoView = new ProtoViewBuilder(current.element, ViewType.EMBEDDED);
|
||||
current.inheritedProtoView =
|
||||
new ProtoViewBuilder(current.element, ViewType.EMBEDDED, ViewEncapsulation.NONE);
|
||||
}
|
||||
})
|
||||
]);
|
||||
var results = pipeline.process(element);
|
||||
var results = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].inheritedProtoView).toBe(results[1].inheritedProtoView);
|
||||
expect(results[2].inheritedProtoView).toBe(results[3].inheritedProtoView);
|
||||
});
|
||||
@@ -60,14 +66,15 @@ export function main() {
|
||||
}
|
||||
})
|
||||
]);
|
||||
var results = pipeline.process(element);
|
||||
var results = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].inheritedElementBinder).toBe(results[1].inheritedElementBinder);
|
||||
expect(results[2].inheritedElementBinder).toBe(results[3].inheritedElementBinder);
|
||||
});
|
||||
|
||||
it('should mark root elements as viewRoot', () => {
|
||||
var rootElement = el('<div></div>');
|
||||
var results = new CompilePipeline([]).process(rootElement);
|
||||
var results = new CompilePipeline([])
|
||||
.processElements(rootElement, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].isViewRoot).toBe(true);
|
||||
});
|
||||
|
||||
@@ -80,7 +87,7 @@ export function main() {
|
||||
}
|
||||
})
|
||||
]);
|
||||
var results = pipeline.process(element);
|
||||
var results = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].inheritedElementBinder.distanceToParent).toBe(0);
|
||||
expect(results[1].inheritedElementBinder.distanceToParent).toBe(1);
|
||||
expect(results[3].inheritedElementBinder.distanceToParent).toBe(2);
|
||||
@@ -95,7 +102,7 @@ export function main() {
|
||||
new IgnoreCurrentElementStep(),
|
||||
createLoggerStep(logs),
|
||||
]);
|
||||
var results = pipeline.process(element);
|
||||
var results = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
|
||||
expect(results.length).toBe(2);
|
||||
expect(logs).toEqual(['1', '1<3'])
|
||||
@@ -108,7 +115,7 @@ export function main() {
|
||||
var step1Log = [];
|
||||
var pipeline =
|
||||
new CompilePipeline([createWrapperStep('wrap0', step0Log), createLoggerStep(step1Log)]);
|
||||
var result = pipeline.process(element);
|
||||
var result = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<2', '2<3']);
|
||||
expect(resultIdLog(result)).toEqual(['1', 'wrap0#0', '2', '3']);
|
||||
@@ -125,7 +132,7 @@ export function main() {
|
||||
createWrapperStep('wrap1', step1Log),
|
||||
createLoggerStep(step2Log)
|
||||
]);
|
||||
var result = pipeline.process(element);
|
||||
var result = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<2', '2<3']);
|
||||
expect(step2Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<wrap1#0', 'wrap1#0<2', '2<3']);
|
||||
@@ -143,7 +150,7 @@ export function main() {
|
||||
createWrapperStep('wrap1', step1Log),
|
||||
createLoggerStep(step2Log)
|
||||
]);
|
||||
var result = pipeline.process(element);
|
||||
var result = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<2', '2<3']);
|
||||
expect(step2Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<2', '2<wrap1#0', 'wrap1#0<3']);
|
||||
@@ -156,7 +163,7 @@ export function main() {
|
||||
var step1Log = [];
|
||||
var pipeline =
|
||||
new CompilePipeline([createWrapperStep('wrap0', step0Log), createLoggerStep(step1Log)]);
|
||||
var result = pipeline.process(element);
|
||||
var result = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<wrap0#1', 'wrap0#1<2', '2<3']);
|
||||
expect(resultIdLog(result)).toEqual(['1', 'wrap0#0', 'wrap0#1', '2', '3']);
|
||||
@@ -177,40 +184,68 @@ export function main() {
|
||||
}),
|
||||
createLoggerStep(resultLog)
|
||||
]);
|
||||
var result = pipeline.process(element);
|
||||
var result = pipeline.processElements(element, ViewType.COMPONENT, createViewDefinition());
|
||||
expect(result[2]).toBe(newChild);
|
||||
expect(resultLog).toEqual(['1', '1<2', '1<3']);
|
||||
expect(resultIdLog(result)).toEqual(['1', '2', '3']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('processStyles', () => {
|
||||
it('should call the steps for every style', () => {
|
||||
var stepCalls = [];
|
||||
var pipeline = new CompilePipeline([
|
||||
new MockStep(null,
|
||||
(style) => {
|
||||
stepCalls.push(style);
|
||||
return style;
|
||||
})
|
||||
]);
|
||||
var result = pipeline.processStyles(['a', 'b']);
|
||||
expect(result[0]).toEqual('a');
|
||||
expect(result[1]).toEqual('b');
|
||||
expect(result).toEqual(stepCalls);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
class MockStep implements CompileStep {
|
||||
processClosure: Function;
|
||||
constructor(process) { this.processClosure = process; }
|
||||
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
this.processClosure(parent, current, control);
|
||||
export class MockStep implements CompileStep {
|
||||
constructor(private processElementClosure: Function,
|
||||
private processStyleClosure: Function = null) {}
|
||||
processElement(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
if (isPresent(this.processElementClosure)) {
|
||||
this.processElementClosure(parent, current, control);
|
||||
}
|
||||
}
|
||||
processStyle(style: string): string {
|
||||
if (isPresent(this.processStyleClosure)) {
|
||||
return this.processStyleClosure(style);
|
||||
} else {
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class IgnoreChildrenStep implements CompileStep {
|
||||
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
processElement(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
var attributeMap = DOM.attributeMap(current.element);
|
||||
if (attributeMap.has('ignore-children')) {
|
||||
current.compileChildren = false;
|
||||
}
|
||||
}
|
||||
processStyle(style: string): string { return style; }
|
||||
}
|
||||
|
||||
class IgnoreCurrentElementStep implements CompileStep {
|
||||
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
processElement(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
var attributeMap = DOM.attributeMap(current.element);
|
||||
if (attributeMap.has('ignore-current')) {
|
||||
control.ignoreCurrentElement();
|
||||
}
|
||||
}
|
||||
processStyle(style: string): string { return style; }
|
||||
}
|
||||
|
||||
function logEntry(log: string[], parent, current) {
|
||||
|
||||
@@ -3,11 +3,10 @@ import {IMPLEMENTS} from 'angular2/src/facade/lang';
|
||||
import {PropertyBindingParser} from 'angular2/src/render/dom/compiler/property_binding_parser';
|
||||
import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline';
|
||||
import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element';
|
||||
import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step';
|
||||
import {CompileControl} from 'angular2/src/render/dom/compiler/compile_control';
|
||||
import {Lexer, Parser} from 'angular2/src/change_detection/change_detection';
|
||||
import {ElementBinderBuilder} from 'angular2/src/render/dom/view/proto_view_builder';
|
||||
import {ViewDefinition, ViewType} from 'angular2/src/render/api';
|
||||
import {MockStep} from './pipeline_spec';
|
||||
|
||||
var EMPTY_MAP = new Map();
|
||||
|
||||
@@ -24,9 +23,15 @@ export function main() {
|
||||
]);
|
||||
}
|
||||
|
||||
function createViewDefinition(): ViewDefinition {
|
||||
return new ViewDefinition({componentId: 'someComponent'});
|
||||
}
|
||||
|
||||
function process(element, hasNestedProtoView = false): List<ElementBinderBuilder> {
|
||||
return ListWrapper.map(createPipeline(hasNestedProtoView).process(element),
|
||||
(compileElement) => compileElement.inheritedElementBinder);
|
||||
return ListWrapper.map(
|
||||
createPipeline(hasNestedProtoView)
|
||||
.processElements(element, ViewType.COMPONENT, createViewDefinition()),
|
||||
(compileElement) => compileElement.inheritedElementBinder);
|
||||
}
|
||||
|
||||
it('should detect [] syntax', () => {
|
||||
@@ -174,13 +179,15 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should store bound properties as temporal attributes', () => {
|
||||
var results = createPipeline().process(el('<div bind-a="b" [c]="d"></div>'));
|
||||
var results = createPipeline().processElements(el('<div bind-a="b" [c]="d"></div>'),
|
||||
ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].attrs().get('a')).toEqual('b');
|
||||
expect(results[0].attrs().get('c')).toEqual('d');
|
||||
});
|
||||
|
||||
it('should store variables as temporal attributes', () => {
|
||||
var results = createPipeline().process(el('<div var-a="b" #c="d"></div>'));
|
||||
var results = createPipeline().processElements(el('<div var-a="b" #c="d"></div>'),
|
||||
ViewType.COMPONENT, createViewDefinition());
|
||||
expect(results[0].attrs().get('a')).toEqual('b');
|
||||
expect(results[0].attrs().get('c')).toEqual('d');
|
||||
});
|
||||
@@ -210,11 +217,3 @@ export function main() {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class MockStep implements CompileStep {
|
||||
processClosure: Function;
|
||||
constructor(process) { this.processClosure = process; }
|
||||
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
this.processClosure(parent, current, control);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import {
|
||||
el,
|
||||
normalizeCSS
|
||||
} from 'angular2/test_lib';
|
||||
import {ShadowCss} from 'angular2/src/render/dom/shadow_dom/shadow_css';
|
||||
import {ShadowCss} from 'angular2/src/render/dom/compiler/shadow_css';
|
||||
|
||||
import {RegExpWrapper, StringWrapper, isPresent} from 'angular2/src/facade/lang';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
@@ -0,0 +1,135 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
SpyObject,
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline';
|
||||
|
||||
import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {
|
||||
ProtoViewBuilder,
|
||||
ElementBinderBuilder
|
||||
} from 'angular2/src/render/dom/view/proto_view_builder';
|
||||
import {ViewDefinition, ViewType, ViewEncapsulation} from 'angular2/src/render/api';
|
||||
|
||||
import {StyleEncapsulator} from 'angular2/src/render/dom/compiler/style_encapsulator';
|
||||
import {MockStep} from './pipeline_spec';
|
||||
|
||||
export function main() {
|
||||
describe('StyleEncapsulator', () => {
|
||||
var componentIdCache;
|
||||
|
||||
beforeEach(() => { componentIdCache = new Map(); });
|
||||
|
||||
function createPipeline(viewDef: ViewDefinition) {
|
||||
return new CompilePipeline([
|
||||
new MockStep((parent, current, control) => {
|
||||
var tagName = DOM.tagName(current.element).toLowerCase();
|
||||
if (tagName.startsWith('comp-')) {
|
||||
current.bindElement().setComponentId(tagName);
|
||||
}
|
||||
}),
|
||||
new StyleEncapsulator('someapp', viewDef, componentIdCache)
|
||||
]);
|
||||
}
|
||||
|
||||
function createViewDefinition(encapsulation: ViewEncapsulation, componentId: string):
|
||||
ViewDefinition {
|
||||
return new ViewDefinition({encapsulation: encapsulation, componentId: componentId});
|
||||
}
|
||||
|
||||
function processStyles(encapsulation: ViewEncapsulation, componentId: string, styles: string[]):
|
||||
string[] {
|
||||
var viewDef = createViewDefinition(encapsulation, componentId);
|
||||
return createPipeline(viewDef).processStyles(styles);
|
||||
}
|
||||
|
||||
function processElements(encapsulation: ViewEncapsulation, componentId: string,
|
||||
template: Element, viewType: ViewType = ViewType.COMPONENT):
|
||||
ProtoViewBuilder {
|
||||
var viewDef = createViewDefinition(encapsulation, componentId);
|
||||
var compileElements = createPipeline(viewDef).processElements(template, viewType, viewDef);
|
||||
return compileElements[0].inheritedProtoView;
|
||||
}
|
||||
|
||||
describe('ViewEncapsulation.NONE', () => {
|
||||
it('should not change the styles', () => {
|
||||
var cs = processStyles(ViewEncapsulation.NONE, 'someComponent', ['.one {}']);
|
||||
expect(cs[0]).toEqual('.one {}');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ViewEncapsulation.NATIVE', () => {
|
||||
it('should not change the styles', () => {
|
||||
var cs = processStyles(ViewEncapsulation.NATIVE, 'someComponent', ['.one {}']);
|
||||
expect(cs[0]).toEqual('.one {}');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ViewEncapsulation.EMULATED', () => {
|
||||
it('should scope styles', () => {
|
||||
var cs = processStyles(ViewEncapsulation.EMULATED, 'someComponent', ['.foo {} :host {}']);
|
||||
expect(cs[0]).toEqual(".foo[_ngcontent-someapp-0] {\n\n}\n\n[_nghost-someapp-0] {\n\n}");
|
||||
});
|
||||
|
||||
it('should return the same style given the same component', () => {
|
||||
var style = '.foo {} :host {}';
|
||||
var cs1 = processStyles(ViewEncapsulation.EMULATED, 'someComponent', [style]);
|
||||
var cs2 = processStyles(ViewEncapsulation.EMULATED, 'someComponent', [style]);
|
||||
|
||||
expect(cs1[0]).toEqual(cs2[0]);
|
||||
});
|
||||
|
||||
it('should return different styles given different components', () => {
|
||||
var style = '.foo {} :host {}';
|
||||
var cs1 = processStyles(ViewEncapsulation.EMULATED, 'someComponent1', [style]);
|
||||
var cs2 = processStyles(ViewEncapsulation.EMULATED, 'someComponent2', [style]);
|
||||
|
||||
expect(cs1[0]).not.toEqual(cs2[0]);
|
||||
});
|
||||
|
||||
it('should add a host attribute to component proto views', () => {
|
||||
var template = DOM.createTemplate('<div></div>');
|
||||
var protoViewBuilder =
|
||||
processElements(ViewEncapsulation.EMULATED, 'someComponent', template);
|
||||
expect(protoViewBuilder.hostAttributes.get('_nghost-someapp-0')).toEqual('');
|
||||
});
|
||||
|
||||
it('should not add a host attribute to embedded proto views', () => {
|
||||
var template = DOM.createTemplate('<div></div>');
|
||||
var protoViewBuilder = processElements(ViewEncapsulation.EMULATED, 'someComponent',
|
||||
template, ViewType.EMBEDDED);
|
||||
expect(protoViewBuilder.hostAttributes.size).toBe(0);
|
||||
});
|
||||
|
||||
it('should not add a host attribute to host proto views', () => {
|
||||
var template = DOM.createTemplate('<div></div>');
|
||||
var protoViewBuilder =
|
||||
processElements(ViewEncapsulation.EMULATED, 'someComponent', template, ViewType.HOST);
|
||||
expect(protoViewBuilder.hostAttributes.size).toBe(0);
|
||||
});
|
||||
|
||||
it('should add an attribute to the content elements', () => {
|
||||
var template = DOM.createTemplate('<div></div>');
|
||||
processElements(ViewEncapsulation.EMULATED, 'someComponent', template);
|
||||
expect(DOM.getInnerHTML(template)).toEqual('<div _ngcontent-someapp-0=""></div>');
|
||||
});
|
||||
|
||||
it('should not add an attribute to the content elements for host views', () => {
|
||||
var template = DOM.createTemplate('<div></div>');
|
||||
processElements(ViewEncapsulation.EMULATED, 'someComponent', template, ViewType.HOST);
|
||||
expect(DOM.getInnerHTML(template)).toEqual('<div></div>');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
ElementBinderBuilder
|
||||
} from 'angular2/src/render/dom/view/proto_view_builder';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {ViewDefinition, ViewType} from 'angular2/src/render/api';
|
||||
|
||||
export function main() {
|
||||
describe('TextInterpolationParser', () => {
|
||||
@@ -17,8 +18,13 @@ export function main() {
|
||||
[new IgnoreChildrenStep(), new TextInterpolationParser(new Parser(new Lexer()))]);
|
||||
}
|
||||
|
||||
function createViewDefinition(): ViewDefinition {
|
||||
return new ViewDefinition({componentId: 'someComponent'});
|
||||
}
|
||||
|
||||
function process(templateString: string): ProtoViewBuilder {
|
||||
var compileElements = createPipeline().process(DOM.createTemplate(templateString));
|
||||
var compileElements = createPipeline().processElements(
|
||||
DOM.createTemplate(templateString), ViewType.COMPONENT, createViewDefinition());
|
||||
return compileElements[0].inheritedProtoView;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,21 +10,21 @@ import {
|
||||
it,
|
||||
xit,
|
||||
} from 'angular2/test_lib';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {ViewLoader} from 'angular2/src/render/dom/compiler/view_loader';
|
||||
import {ViewLoader, TemplateAndStyles} from 'angular2/src/render/dom/compiler/view_loader';
|
||||
import {StyleInliner} from 'angular2/src/render/dom/compiler/style_inliner';
|
||||
import {StyleUrlResolver} from 'angular2/src/render/dom/compiler/style_url_resolver';
|
||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||
|
||||
import {ViewDefinition} from 'angular2/src/render/api';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {XHR} from 'angular2/src/render/xhr';
|
||||
import {MockXHR} from 'angular2/src/render/xhr_mock';
|
||||
import {ViewDefinition} from 'angular2/src/render/api';
|
||||
|
||||
export function main() {
|
||||
describe('ViewLoader', () => {
|
||||
var loader, xhr, styleUrlResolver, urlResolver;
|
||||
var loader: ViewLoader;
|
||||
var xhr, styleUrlResolver, urlResolver;
|
||||
|
||||
beforeEach(() => {
|
||||
xhr = new MockXHR();
|
||||
@@ -36,32 +36,33 @@ export function main() {
|
||||
|
||||
describe('html', () => {
|
||||
it('should load inline templates', inject([AsyncTestCompleter], (async) => {
|
||||
var view = new ViewDefinition({template: 'template template'});
|
||||
loader.load(view).then((el) => {
|
||||
expect(DOM.content(el)).toHaveText('template template');
|
||||
async.done();
|
||||
});
|
||||
loader.load(new ViewDefinition({template: 'template template'}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('template template');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should load templates through XHR', inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://ng.io/foo.html', 'xhr template');
|
||||
var view = new ViewDefinition({templateAbsUrl: 'http://ng.io/foo.html'});
|
||||
loader.load(view).then((el) => {
|
||||
expect(DOM.content(el)).toHaveText('xhr template');
|
||||
async.done();
|
||||
});
|
||||
loader.load(new ViewDefinition({templateAbsUrl: 'http://ng.io/foo.html'}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('xhr template');
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should resolve urls in styles', inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://ng.io/foo.html',
|
||||
'<style>.foo { background-image: url("double.jpg"); }</style>');
|
||||
var view = new ViewDefinition({templateAbsUrl: 'http://ng.io/foo.html'});
|
||||
loader.load(view).then((el) => {
|
||||
expect(DOM.content(el))
|
||||
.toHaveText(".foo { background-image: url('http://ng.io/double.jpg'); }");
|
||||
async.done();
|
||||
});
|
||||
loader.load(new ViewDefinition({templateAbsUrl: 'http://ng.io/foo.html'}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('');
|
||||
expect(el.styles)
|
||||
.toEqual([".foo { background-image: url('http://ng.io/double.jpg'); }"]);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
@@ -73,85 +74,66 @@ export function main() {
|
||||
let styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver);
|
||||
let loader = new ViewLoader(xhr, styleInliner, styleUrlResolver);
|
||||
|
||||
var view = new ViewDefinition({templateAbsUrl: 'http://ng.io/foo.html'});
|
||||
loader.load(view).then((el) => {
|
||||
expect(DOM.getInnerHTML(el)).toEqual("<style>/* foo.css */\n</style>");
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should return a new template element on each call',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var firstEl;
|
||||
// we have only one xhr.expect, so there can only be one xhr call!
|
||||
xhr.expect('http://ng.io/foo.html', 'xhr template');
|
||||
var view = new ViewDefinition({templateAbsUrl: 'http://ng.io/foo.html'});
|
||||
loader.load(view)
|
||||
loader.load(new ViewDefinition({templateAbsUrl: 'http://ng.io/foo.html'}))
|
||||
.then((el) => {
|
||||
expect(DOM.content(el)).toHaveText('xhr template');
|
||||
firstEl = el;
|
||||
return loader.load(view);
|
||||
})
|
||||
.then((el) => {
|
||||
expect(el).not.toBe(firstEl);
|
||||
expect(DOM.content(el)).toHaveText('xhr template');
|
||||
expect(el.template).toEqual('');
|
||||
expect(el.styles).toEqual(["/* foo.css */\n"]);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
it('should throw when no template is defined', () => {
|
||||
var view = new ViewDefinition({template: null, templateAbsUrl: null});
|
||||
expect(() => loader.load(view))
|
||||
expect(() => loader.load(new ViewDefinition({template: null, templateAbsUrl: null})))
|
||||
.toThrowError('View should have either the templateUrl or template property set');
|
||||
});
|
||||
|
||||
it('should return a rejected Promise when XHR loading fails',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://ng.io/foo.html', null);
|
||||
var view = new ViewDefinition({templateAbsUrl: 'http://ng.io/foo.html'});
|
||||
PromiseWrapper.then(loader.load(view), function(_) { throw 'Unexpected response'; },
|
||||
function(error) {
|
||||
expect(error.message)
|
||||
.toEqual('Failed to fetch url "http://ng.io/foo.html"');
|
||||
async.done();
|
||||
});
|
||||
PromiseWrapper.then(
|
||||
loader.load(new ViewDefinition({templateAbsUrl: 'http://ng.io/foo.html'})),
|
||||
function(_) { throw 'Unexpected response'; },
|
||||
function(error) {
|
||||
expect(error.message).toEqual('Failed to fetch url "http://ng.io/foo.html"');
|
||||
async.done();
|
||||
});
|
||||
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();
|
||||
});
|
||||
loader.load(new ViewDefinition({templateAbsUrl: 'http://ng.io/path/foo.html'}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('<img src="http://ng.io/path/logo.png">');
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('css', () => {
|
||||
it('should load inline styles', inject([AsyncTestCompleter], (async) => {
|
||||
var view = new ViewDefinition({template: 'html', styles: ['style 1', 'style 2']});
|
||||
loader.load(view).then((el) => {
|
||||
expect(DOM.getInnerHTML(el))
|
||||
.toEqual('<style>style 1</style><style>style 2</style>html');
|
||||
async.done();
|
||||
});
|
||||
loader.load(new ViewDefinition({template: 'html', styles: ['style 1', 'style 2']}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('html');
|
||||
expect(el.styles).toEqual(['style 1', 'style 2']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should resolve urls in inline styles', inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://ng.io/foo.html', 'html');
|
||||
var view = new ViewDefinition({
|
||||
templateAbsUrl: 'http://ng.io/foo.html',
|
||||
styles: ['.foo { background-image: url("double.jpg"); }']
|
||||
});
|
||||
loader.load(view).then((el) => {
|
||||
expect(DOM.getInnerHTML(el))
|
||||
.toEqual(
|
||||
"<style>.foo { background-image: url('http://ng.io/double.jpg'); }</style>html");
|
||||
async.done();
|
||||
});
|
||||
loader.load(new ViewDefinition({
|
||||
templateAbsUrl: 'http://ng.io/foo.html',
|
||||
styles: ['.foo { background-image: url("double.jpg"); }']
|
||||
}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('html');
|
||||
expect(el.styles)
|
||||
.toEqual([".foo { background-image: url('http://ng.io/double.jpg'); }"]);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
@@ -159,16 +141,16 @@ export function main() {
|
||||
xhr.expect('http://ng.io/foo.html', 'xhr template');
|
||||
xhr.expect('http://ng.io/foo-1.css', '1');
|
||||
xhr.expect('http://ng.io/foo-2.css', '2');
|
||||
var view = new ViewDefinition({
|
||||
templateAbsUrl: 'http://ng.io/foo.html',
|
||||
styles: ['i1'],
|
||||
styleAbsUrls: ['http://ng.io/foo-1.css', 'http://ng.io/foo-2.css']
|
||||
});
|
||||
loader.load(view).then((el) => {
|
||||
expect(DOM.getInnerHTML(el))
|
||||
.toEqual('<style>i1</style><style>1</style><style>2</style>xhr template');
|
||||
async.done();
|
||||
});
|
||||
loader.load(new ViewDefinition({
|
||||
templateAbsUrl: 'http://ng.io/foo.html',
|
||||
styles: ['i1'],
|
||||
styleAbsUrls: ['http://ng.io/foo-1.css', 'http://ng.io/foo-2.css']
|
||||
}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual('xhr template');
|
||||
expect(el.styles).toEqual(['i1', '1', '2']);
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
|
||||
@@ -180,25 +162,27 @@ export function main() {
|
||||
let styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver);
|
||||
let loader = new ViewLoader(xhr, styleInliner, styleUrlResolver);
|
||||
|
||||
var view = new ViewDefinition(
|
||||
{templateAbsUrl: 'http://ng.io/foo.html', styles: ['@import "foo.css";']});
|
||||
loader.load(view).then((el) => {
|
||||
expect(DOM.getInnerHTML(el)).toEqual("<style>/* foo.css */\n</style><p>template</p>");
|
||||
async.done();
|
||||
});
|
||||
loader.load(
|
||||
new ViewDefinition(
|
||||
{templateAbsUrl: 'http://ng.io/foo.html', styles: ['@import "foo.css";']}))
|
||||
.then((el) => {
|
||||
expect(el.template).toEqual("<p>template</p>");
|
||||
expect(el.styles).toEqual(["/* foo.css */\n"]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
it('should return a rejected Promise when XHR loading fails',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
xhr.expect('http://ng.io/foo.css', null);
|
||||
var view = new ViewDefinition({template: '', styleAbsUrls: ['http://ng.io/foo.css']});
|
||||
PromiseWrapper.then(loader.load(view), function(_) { throw 'Unexpected response'; },
|
||||
function(error) {
|
||||
expect(error.message)
|
||||
.toEqual('Failed to fetch url "http://ng.io/foo.css"');
|
||||
async.done();
|
||||
});
|
||||
PromiseWrapper.then(
|
||||
loader.load(
|
||||
new ViewDefinition({template: '', styleAbsUrls: ['http://ng.io/foo.css']})),
|
||||
function(_) { throw 'Unexpected response'; },
|
||||
function(error) {
|
||||
expect(error.message).toEqual('Failed to fetch url "http://ng.io/foo.css"');
|
||||
async.done();
|
||||
});
|
||||
xhr.flush();
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -12,7 +12,8 @@ import {MapWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
import {ViewSplitter} from 'angular2/src/render/dom/compiler/view_splitter';
|
||||
import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline';
|
||||
import {ProtoViewDto, ViewType} from 'angular2/src/render/api';
|
||||
import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element';
|
||||
import {ProtoViewDto, ViewType, ViewDefinition} from 'angular2/src/render/api';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
|
||||
import {Lexer, Parser} from 'angular2/src/change_detection/change_detection';
|
||||
@@ -20,15 +21,23 @@ import {Lexer, Parser} from 'angular2/src/change_detection/change_detection';
|
||||
export function main() {
|
||||
describe('ViewSplitter', () => {
|
||||
|
||||
function createViewDefinition(): ViewDefinition {
|
||||
return new ViewDefinition({componentId: 'someComponent'});
|
||||
}
|
||||
|
||||
function createPipeline() {
|
||||
return new CompilePipeline([new ViewSplitter(new Parser(new Lexer()))]);
|
||||
}
|
||||
|
||||
function proceess(el): CompileElement[] {
|
||||
return createPipeline().processElements(el, ViewType.COMPONENT, createViewDefinition());
|
||||
}
|
||||
|
||||
describe('<template> elements', () => {
|
||||
|
||||
it('should move the content into a new <template> element and mark that as viewRoot', () => {
|
||||
var rootElement = DOM.createTemplate('<template if="true">a</template>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
|
||||
expect(stringifyElement(results[1].element))
|
||||
.toEqual('<template class="ng-binding" if="true"></template>');
|
||||
@@ -39,32 +48,32 @@ export function main() {
|
||||
|
||||
it('should mark the new <template> element as viewRoot', () => {
|
||||
var rootElement = DOM.createTemplate('<template if="true">a</template>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
});
|
||||
|
||||
it('should not wrap the root element', () => {
|
||||
var rootElement = DOM.createTemplate('');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results.length).toBe(1);
|
||||
expect(stringifyElement(rootElement)).toEqual('<template></template>');
|
||||
});
|
||||
|
||||
it('should copy over the elementDescription', () => {
|
||||
var rootElement = DOM.createTemplate('<template if="true">a</template>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].elementDescription).toBe(results[1].elementDescription);
|
||||
});
|
||||
|
||||
it('should clean out the inheritedElementBinder', () => {
|
||||
var rootElement = DOM.createTemplate('<template if="true">a</template>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedElementBinder).toBe(null);
|
||||
});
|
||||
|
||||
it('should create a nestedProtoView', () => {
|
||||
var rootElement = DOM.createTemplate('<template if="true">a</template>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedProtoView).not.toBe(null);
|
||||
expect(results[2].inheritedProtoView)
|
||||
.toBe(results[1].inheritedElementBinder.nestedProtoView);
|
||||
@@ -80,7 +89,7 @@ export function main() {
|
||||
it('should replace the element with an empty <template> element', () => {
|
||||
var rootElement = DOM.createTemplate('<span template=""></span>');
|
||||
var originalChild = DOM.firstChild(DOM.content(rootElement));
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[0].element).toBe(rootElement);
|
||||
expect(stringifyElement(results[0].element))
|
||||
.toEqual('<template><template class="ng-binding"></template></template>');
|
||||
@@ -92,7 +101,7 @@ export function main() {
|
||||
it('should work with top-level template node', () => {
|
||||
var rootElement = DOM.createTemplate('<div template>x</div>');
|
||||
var originalChild = DOM.content(rootElement).childNodes[0];
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
|
||||
expect(results[0].element).toBe(rootElement);
|
||||
expect(results[0].isViewRoot).toBe(true);
|
||||
@@ -104,13 +113,13 @@ export function main() {
|
||||
|
||||
it('should mark the element as viewRoot', () => {
|
||||
var rootElement = DOM.createTemplate('<div template></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
});
|
||||
|
||||
it('should add property bindings from the template attribute', () => {
|
||||
var rootElement = DOM.createTemplate('<div template="some-prop:expr"></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[1].inheritedElementBinder.propertyBindings.get('someProp').source)
|
||||
.toEqual('expr');
|
||||
expect(results[1].attrs().get('some-prop')).toEqual('expr');
|
||||
@@ -118,14 +127,14 @@ export function main() {
|
||||
|
||||
it('should add variable mappings from the template attribute to the nestedProtoView', () => {
|
||||
var rootElement = DOM.createTemplate('<div template="var var-name=mapName"></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedProtoView.variableBindings)
|
||||
.toEqual(MapWrapper.createFromStringMap({'mapName': 'varName'}));
|
||||
});
|
||||
|
||||
it('should add entries without value as attributes to the element', () => {
|
||||
var rootElement = DOM.createTemplate('<div template="varname"></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[1].attrs().get('varname')).toEqual('');
|
||||
expect(results[1].inheritedElementBinder.propertyBindings).toEqual(new Map());
|
||||
expect(results[1].inheritedElementBinder.variableBindings).toEqual(new Map());
|
||||
@@ -133,26 +142,26 @@ export function main() {
|
||||
|
||||
it('should iterate properly after a template dom modification', () => {
|
||||
var rootElement = DOM.createTemplate('<div template></div><after></after>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
// 1 root + 2 initial + 2 generated template elements
|
||||
expect(results.length).toEqual(5);
|
||||
});
|
||||
|
||||
it('should copy over the elementDescription', () => {
|
||||
var rootElement = DOM.createTemplate('<span template=""></span>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].elementDescription).toBe(results[1].elementDescription);
|
||||
});
|
||||
|
||||
it('should clean out the inheritedElementBinder', () => {
|
||||
var rootElement = DOM.createTemplate('<span template=""></span>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedElementBinder).toBe(null);
|
||||
});
|
||||
|
||||
it('should create a nestedProtoView', () => {
|
||||
var rootElement = DOM.createTemplate('<span template=""></span>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedProtoView).not.toBe(null);
|
||||
expect(results[2].inheritedProtoView)
|
||||
.toBe(results[1].inheritedElementBinder.nestedProtoView);
|
||||
@@ -167,7 +176,7 @@ export function main() {
|
||||
it('should replace the element with an empty <template> element', () => {
|
||||
var rootElement = DOM.createTemplate('<span *ng-if></span>');
|
||||
var originalChild = DOM.firstChild(DOM.content(rootElement));
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[0].element).toBe(rootElement);
|
||||
expect(stringifyElement(results[0].element))
|
||||
.toEqual('<template><template class="ng-binding" ng-if=""></template></template>');
|
||||
@@ -178,14 +187,14 @@ export function main() {
|
||||
|
||||
it('should mark the element as viewRoot', () => {
|
||||
var rootElement = DOM.createTemplate('<div *foo="bar"></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
});
|
||||
|
||||
it('should work with top-level template node', () => {
|
||||
var rootElement = DOM.createTemplate('<div *foo>x</div>');
|
||||
var originalChild = DOM.content(rootElement).childNodes[0];
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
|
||||
expect(results[0].element).toBe(rootElement);
|
||||
expect(results[0].isViewRoot).toBe(true);
|
||||
@@ -197,7 +206,7 @@ export function main() {
|
||||
|
||||
it('should add property bindings from the template attribute', () => {
|
||||
var rootElement = DOM.createTemplate('<div *prop="expr"></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[1].inheritedElementBinder.propertyBindings.get('prop').source)
|
||||
.toEqual('expr');
|
||||
expect(results[1].attrs().get('prop')).toEqual('expr');
|
||||
@@ -205,14 +214,14 @@ export function main() {
|
||||
|
||||
it('should add variable mappings from the template attribute to the nestedProtoView', () => {
|
||||
var rootElement = DOM.createTemplate('<div *foreach="var varName=mapName"></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedProtoView.variableBindings)
|
||||
.toEqual(MapWrapper.createFromStringMap({'mapName': 'varName'}));
|
||||
});
|
||||
|
||||
it('should add entries without value as attribute to the element', () => {
|
||||
var rootElement = DOM.createTemplate('<div *varname></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[1].attrs().get('varname')).toEqual('');
|
||||
expect(results[1].inheritedElementBinder.propertyBindings).toEqual(new Map());
|
||||
expect(results[1].inheritedElementBinder.variableBindings).toEqual(new Map());
|
||||
@@ -220,26 +229,26 @@ export function main() {
|
||||
|
||||
it('should iterate properly after a template dom modification', () => {
|
||||
var rootElement = DOM.createTemplate('<div *foo></div><after></after>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
// 1 root + 2 initial + 2 generated template elements
|
||||
expect(results.length).toEqual(5);
|
||||
});
|
||||
|
||||
it('should copy over the elementDescription', () => {
|
||||
var rootElement = DOM.createTemplate('<span *foo></span>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].elementDescription).toBe(results[1].elementDescription);
|
||||
});
|
||||
|
||||
it('should clean out the inheritedElementBinder', () => {
|
||||
var rootElement = DOM.createTemplate('<span *foo></span>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedElementBinder).toBe(null);
|
||||
});
|
||||
|
||||
it('should create a nestedProtoView', () => {
|
||||
var rootElement = DOM.createTemplate('<span *foo></span>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
var results = proceess(rootElement);
|
||||
expect(results[2].inheritedProtoView).not.toBe(null);
|
||||
expect(results[2].inheritedProtoView)
|
||||
.toBe(results[1].inheritedElementBinder.nestedProtoView);
|
||||
|
||||
@@ -18,9 +18,13 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
|
||||
import {DomTestbed, TestRootView, elRef} from './dom_testbed';
|
||||
|
||||
import {ViewDefinition, DirectiveMetadata, RenderViewRef} from 'angular2/src/render/api';
|
||||
import {DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES} from 'angular2/src/render/dom/dom_renderer';
|
||||
import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/render/render';
|
||||
import {
|
||||
ViewDefinition,
|
||||
DirectiveMetadata,
|
||||
RenderViewRef,
|
||||
ViewEncapsulation
|
||||
} from 'angular2/src/render/api';
|
||||
import {DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES} from 'angular2/src/render/dom/dom_tokens';
|
||||
import {bind} from 'angular2/di';
|
||||
|
||||
export function main() {
|
||||
@@ -271,17 +275,17 @@ export function main() {
|
||||
|
||||
if (DOM.supportsNativeShadowDOM()) {
|
||||
describe('native shadow dom support', () => {
|
||||
beforeEachBindings(
|
||||
() => { return [bind(ShadowDomStrategy).toValue(new NativeShadowDomStrategy())]; });
|
||||
|
||||
it('should support shadow dom components',
|
||||
it('should put the template into a shadow root',
|
||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
||||
tb.compileAndMerge(
|
||||
someComponent,
|
||||
[
|
||||
new ViewDefinition(
|
||||
{componentId: 'someComponent', template: 'hello', directives: []})
|
||||
])
|
||||
tb.compileAndMerge(someComponent,
|
||||
[
|
||||
new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: 'hello',
|
||||
directives: [],
|
||||
encapsulation: ViewEncapsulation.NATIVE
|
||||
})
|
||||
])
|
||||
.then((protoViewMergeMappings) => {
|
||||
var rootView = tb.createView(protoViewMergeMappings);
|
||||
expect(DOM.getShadowRoot(rootView.hostElement)).toHaveText('hello');
|
||||
@@ -289,6 +293,48 @@ export function main() {
|
||||
});
|
||||
|
||||
}));
|
||||
|
||||
it('should add styles from non native components to shadow roots while the view is not destroyed',
|
||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
||||
tb.compileAndMerge(someComponent,
|
||||
[
|
||||
new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '',
|
||||
directives: [],
|
||||
encapsulation: ViewEncapsulation.NATIVE,
|
||||
styles: ['a {};']
|
||||
})
|
||||
])
|
||||
.then((protoViewMergeMappings) => {
|
||||
var rootView = tb.createView(protoViewMergeMappings);
|
||||
tb.compiler.compile(new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '',
|
||||
directives: [],
|
||||
encapsulation: ViewEncapsulation.NONE,
|
||||
styles: ['b {};']
|
||||
}))
|
||||
.then(_ => {
|
||||
expect(DOM.getShadowRoot(rootView.hostElement)).toHaveText('a {};b {};');
|
||||
tb.renderer.destroyView(rootView.viewRef);
|
||||
tb.compiler.compile(new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '',
|
||||
directives: [],
|
||||
encapsulation: ViewEncapsulation.NONE,
|
||||
styles: ['c {};']
|
||||
}))
|
||||
.then(_ => {
|
||||
expect(DOM.getShadowRoot(rootView.hostElement))
|
||||
.toHaveText('a {};b {};');
|
||||
async.done();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ import {MapWrapper, ListWrapper, List, Map} from 'angular2/src/facade/collection
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
|
||||
import {DomRenderer, DOCUMENT_TOKEN} from 'angular2/src/render/dom/dom_renderer';
|
||||
import {DomRenderer} from 'angular2/src/render/dom/dom_renderer';
|
||||
import {DOCUMENT_TOKEN} from 'angular2/src/render/dom/dom_tokens';
|
||||
import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler';
|
||||
import {
|
||||
RenderViewWithFragments,
|
||||
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
SpyObject,
|
||||
normalizeCSS
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
|
||||
import {
|
||||
EmulatedScopedShadowDomStrategy,
|
||||
} from 'angular2/src/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy';
|
||||
import {
|
||||
resetShadowDomCache,
|
||||
} from 'angular2/src/render/dom/shadow_dom/util';
|
||||
|
||||
export function main() {
|
||||
describe('EmulatedScopedShadowDomStrategy', () => {
|
||||
var styleHost, strategy;
|
||||
|
||||
beforeEach(() => {
|
||||
styleHost = el('<div></div>');
|
||||
strategy = new EmulatedScopedShadowDomStrategy(styleHost);
|
||||
resetShadowDomCache();
|
||||
});
|
||||
|
||||
it('should report that this is not the native strategy',
|
||||
() => { expect(strategy.hasNativeContentElement()).toBe(false); });
|
||||
|
||||
it('should scope styles', () => {
|
||||
var styleElement = el('<style>.foo {} :host {}</style>');
|
||||
strategy.processStyleElement('someComponent', 'http://base', styleElement);
|
||||
expect(styleElement).toHaveText(".foo[_ngcontent-0] {\n\n}\n\n[_nghost-0] {\n\n}");
|
||||
});
|
||||
|
||||
it('should return the same style given the same component', () => {
|
||||
var styleElement = el('<style>.foo {} :host {}</style>');
|
||||
strategy.processStyleElement('someComponent', 'http://base', styleElement);
|
||||
|
||||
var styleElement2 = el('<style>.foo {} :host {}</style>');
|
||||
strategy.processStyleElement('someComponent', 'http://base', styleElement2);
|
||||
|
||||
expect(DOM.getText(styleElement)).toEqual(DOM.getText(styleElement2));
|
||||
});
|
||||
|
||||
it('should return different styles given different components', () => {
|
||||
var styleElement = el('<style>.foo {} :host {}</style>');
|
||||
strategy.processStyleElement('someComponent1', 'http://base', styleElement);
|
||||
|
||||
var styleElement2 = el('<style>.foo {} :host {}</style>');
|
||||
strategy.processStyleElement('someComponent2', 'http://base', styleElement2);
|
||||
|
||||
expect(DOM.getText(styleElement)).not.toEqual(DOM.getText(styleElement2));
|
||||
});
|
||||
|
||||
it('should move the style element to the style host', () => {
|
||||
var compileElement = el('<div><style>.one {}</style></div>');
|
||||
var styleElement = DOM.firstChild(compileElement);
|
||||
strategy.processStyleElement('someComponent', 'http://base', styleElement);
|
||||
|
||||
expect(compileElement).toHaveText('');
|
||||
expect(styleHost).toHaveText('.one[_ngcontent-0] {\n\n}');
|
||||
});
|
||||
|
||||
it('should add an attribute to component elements', () => {
|
||||
var element = el('<div></div>');
|
||||
strategy.processElement(null, 'elComponent', element);
|
||||
expect(DOM.getAttribute(element, '_nghost-0')).toEqual('');
|
||||
});
|
||||
|
||||
it('should add an attribute to the content elements', () => {
|
||||
var element = el('<div></div>');
|
||||
strategy.processElement('hostComponent', null, element);
|
||||
expect(DOM.getAttribute(element, '_ngcontent-0')).toEqual('');
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
SpyObject,
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
import {
|
||||
EmulatedUnscopedShadowDomStrategy,
|
||||
} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
|
||||
import {
|
||||
resetShadowDomCache,
|
||||
} from 'angular2/src/render/dom/shadow_dom/util';
|
||||
|
||||
export function main() {
|
||||
var strategy;
|
||||
|
||||
describe('EmulatedUnscopedShadowDomStrategy', () => {
|
||||
var styleHost;
|
||||
|
||||
beforeEach(() => {
|
||||
styleHost = el('<div></div>');
|
||||
strategy = new EmulatedUnscopedShadowDomStrategy(styleHost);
|
||||
resetShadowDomCache();
|
||||
});
|
||||
|
||||
it('should report that this is not the native strategy',
|
||||
() => { expect(strategy.hasNativeContentElement()).toBe(false); });
|
||||
|
||||
it('should move the style element to the style host', () => {
|
||||
var compileElement = el('<div><style>.one {}</style></div>');
|
||||
var styleElement = DOM.firstChild(compileElement);
|
||||
strategy.processStyleElement('someComponent', 'http://base', styleElement);
|
||||
|
||||
expect(compileElement).toHaveText('');
|
||||
expect(styleHost).toHaveText('.one {}');
|
||||
});
|
||||
|
||||
it('should insert the same style only once in the style host', () => {
|
||||
var styleEls = [
|
||||
el('<style>/*css1*/</style>'),
|
||||
el('<style>/*css2*/</style>'),
|
||||
el('<style>/*css1*/</style>')
|
||||
];
|
||||
ListWrapper.forEach(styleEls, (styleEl) => {
|
||||
strategy.processStyleElement('someComponent', 'http://base', styleEl);
|
||||
});
|
||||
|
||||
expect(styleHost).toHaveText("/*css1*//*css2*/");
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
SpyObject,
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {
|
||||
NativeShadowDomStrategy
|
||||
} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
|
||||
|
||||
export function main() {
|
||||
var strategy: NativeShadowDomStrategy;
|
||||
|
||||
describe('NativeShadowDomStrategy', () => {
|
||||
beforeEach(() => { strategy = new NativeShadowDomStrategy(); });
|
||||
|
||||
it('should report that this is the native strategy',
|
||||
() => { expect(strategy.hasNativeContentElement()).toBe(true); });
|
||||
});
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
|
||||
import {ProtoViewBuilder} from 'angular2/src/render/dom/view/proto_view_builder';
|
||||
import {ASTWithSource, AST} from 'angular2/src/change_detection/change_detection';
|
||||
import {PropertyBindingType, ViewType} from 'angular2/src/render/api';
|
||||
import {PropertyBindingType, ViewType, ViewEncapsulation} from 'angular2/src/render/api';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
|
||||
export function main() {
|
||||
@@ -21,8 +21,10 @@ export function main() {
|
||||
|
||||
describe('ProtoViewBuilder', () => {
|
||||
var builder;
|
||||
beforeEach(
|
||||
() => { builder = new ProtoViewBuilder(DOM.createTemplate(''), ViewType.EMBEDDED); });
|
||||
beforeEach(() => {
|
||||
builder =
|
||||
new ProtoViewBuilder(DOM.createTemplate(''), ViewType.EMBEDDED, ViewEncapsulation.NONE);
|
||||
});
|
||||
|
||||
if (!IS_DARTIUM) {
|
||||
describe('verification of properties', () => {
|
||||
|
||||
@@ -21,15 +21,15 @@ import {DomTestbed} from '../dom_testbed';
|
||||
import {
|
||||
ViewDefinition,
|
||||
DirectiveMetadata,
|
||||
RenderProtoViewMergeMapping
|
||||
RenderProtoViewMergeMapping,
|
||||
ViewEncapsulation,
|
||||
ViewType
|
||||
} from 'angular2/src/render/api';
|
||||
import {bind} from 'angular2/di';
|
||||
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {cloneAndQueryProtoView} from 'angular2/src/render/dom/util';
|
||||
import {resolveInternalDomProtoView} from 'angular2/src/render/dom/view/proto_view';
|
||||
|
||||
import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/render/render';
|
||||
import {ProtoViewBuilder} from 'angular2/src/render/dom/view/proto_view_builder';
|
||||
|
||||
export function main() {
|
||||
describe('ProtoViewMerger integration test', () => {
|
||||
@@ -232,29 +232,46 @@ export function main() {
|
||||
});
|
||||
|
||||
describe('native shadow dom support', () => {
|
||||
beforeEachBindings(
|
||||
() => { return [bind(ShadowDomStrategy).toValue(new NativeShadowDomStrategy())]; });
|
||||
|
||||
it('should keep the non projected light dom and wrap the component view into a shadow-root element',
|
||||
runAndAssert('root', ['<a>b</a>', 'c'], [
|
||||
'<root class="ng-binding" idx="0"><shadow-root><a class="ng-binding" idx="1"><shadow-root>c</shadow-root>b</a></shadow-root></root>'
|
||||
runAndAssert('native-root', ['<a>b</a>', 'c'], [
|
||||
'<native-root class="ng-binding" idx="0"><shadow-root><a class="ng-binding" idx="1"><shadow-root>c</shadow-root>b</a></shadow-root></native-root>'
|
||||
]));
|
||||
|
||||
});
|
||||
|
||||
describe('host attributes', () => {
|
||||
it('should set host attributes while merging',
|
||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
||||
tb.compiler.compileHost(rootDirective('root'))
|
||||
.then((rootProtoViewDto) => {
|
||||
var builder = new ProtoViewBuilder(DOM.createTemplate(''), ViewType.COMPONENT,
|
||||
ViewEncapsulation.NONE);
|
||||
builder.setHostAttribute('a', 'b');
|
||||
var componentProtoViewDto = builder.build();
|
||||
tb.merge([rootProtoViewDto, componentProtoViewDto])
|
||||
.then(mergeMappings => {
|
||||
var domPv = resolveInternalDomProtoView(mergeMappings.mergedProtoViewRef);
|
||||
expect(DOM.getInnerHTML(domPv.rootElement))
|
||||
.toEqual('<root class="ng-binding" a="b"></root>');
|
||||
async.done();
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function runAndAssert(hostElementName: string, componentTemplates: string[],
|
||||
expectedFragments: string[]) {
|
||||
var rootComp = DirectiveMetadata.create(
|
||||
{id: 'rootComp', type: DirectiveMetadata.COMPONENT_TYPE, selector: hostElementName});
|
||||
var useNativeEncapsulation = hostElementName.startsWith('native-');
|
||||
var rootComp = rootDirective(hostElementName);
|
||||
return inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
||||
tb.compileAndMerge(rootComp, componentTemplates.map(template => new ViewDefinition({
|
||||
componentId: 'someComp',
|
||||
template: template,
|
||||
directives: [aComp, bComp, cComp]
|
||||
})))
|
||||
tb.compileAndMerge(rootComp, componentTemplates.map(template => componentView(
|
||||
template, useNativeEncapsulation ?
|
||||
ViewEncapsulation.NATIVE :
|
||||
ViewEncapsulation.NONE)))
|
||||
.then((mergeMappings) => {
|
||||
expect(stringify(mergeMappings)).toEqual(expectedFragments);
|
||||
async.done();
|
||||
@@ -262,6 +279,21 @@ function runAndAssert(hostElementName: string, componentTemplates: string[],
|
||||
});
|
||||
}
|
||||
|
||||
function rootDirective(hostElementName: string) {
|
||||
return DirectiveMetadata.create(
|
||||
{id: 'rootComp', type: DirectiveMetadata.COMPONENT_TYPE, selector: hostElementName});
|
||||
}
|
||||
|
||||
function componentView(template: string,
|
||||
encapsulation: ViewEncapsulation = ViewEncapsulation.NONE) {
|
||||
return new ViewDefinition({
|
||||
componentId: 'someComp',
|
||||
template: template,
|
||||
directives: [aComp, bComp, cComp],
|
||||
encapsulation: encapsulation
|
||||
});
|
||||
}
|
||||
|
||||
function stringify(protoViewMergeMapping: RenderProtoViewMergeMapping): string[] {
|
||||
var testView = cloneAndQueryProtoView(
|
||||
resolveInternalDomProtoView(protoViewMergeMapping.mergedProtoViewRef), false);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
xdescribe,
|
||||
describe,
|
||||
el,
|
||||
dispatchEvent,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
beforeEachBindings,
|
||||
it,
|
||||
xit,
|
||||
SpyObject,
|
||||
proxy
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {DomSharedStylesHost} from 'angular2/src/render/dom/view/shared_styles_host';
|
||||
|
||||
export function main() {
|
||||
describe('DomSharedStylesHost', () => {
|
||||
var doc;
|
||||
var ssh: DomSharedStylesHost;
|
||||
var someHost: Element;
|
||||
beforeEach(() => {
|
||||
doc = DOM.createHtmlDocument();
|
||||
doc.title = '';
|
||||
ssh = new DomSharedStylesHost(doc);
|
||||
someHost = DOM.createElement('div');
|
||||
});
|
||||
|
||||
it('should add existing styles to new hosts', () => {
|
||||
ssh.addStyles(['a {};']);
|
||||
ssh.addHost(someHost);
|
||||
expect(DOM.getInnerHTML(someHost)).toEqual('<style>a {};</style>');
|
||||
});
|
||||
|
||||
it('should add new styles to hosts', () => {
|
||||
ssh.addHost(someHost);
|
||||
ssh.addStyles(['a {};']);
|
||||
expect(DOM.getInnerHTML(someHost)).toEqual('<style>a {};</style>');
|
||||
});
|
||||
|
||||
it('should add styles only once to hosts', () => {
|
||||
ssh.addStyles(['a {};']);
|
||||
ssh.addHost(someHost);
|
||||
ssh.addStyles(['a {};']);
|
||||
expect(DOM.getInnerHTML(someHost)).toEqual('<style>a {};</style>');
|
||||
});
|
||||
|
||||
it('should use the document head as default host', () => {
|
||||
ssh.addStyles(['a {};', 'b {};']);
|
||||
expect(doc.head).toHaveText('a {};b {};');
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -30,7 +30,7 @@ export function main() {
|
||||
binders = [];
|
||||
}
|
||||
var rootEl = DOM.createTemplate('<div></div>');
|
||||
return DomProtoView.create(null, <Element>rootEl, [1], [], binders);
|
||||
return DomProtoView.create(null, <Element>rootEl, null, [1], [], binders, null);
|
||||
}
|
||||
|
||||
function createElementBinder() { return new DomElementBinder({textNodeIndices: []}); }
|
||||
|
||||
Reference in New Issue
Block a user