feat(emuldated_shadow_dom): implement intermediate content tags
This commit is contained in:
@ -109,50 +109,9 @@ export function main() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should emulate content tag', (done) => {
|
||||
var temp = `<emulated-shadow-dom-component>` +
|
||||
`<div>Light</div>` +
|
||||
`<div template="trivial-template">DOM</div>` +
|
||||
`</emulated-shadow-dom-component>`;
|
||||
|
||||
function createView(pv) {
|
||||
var view = pv.instantiate(null);
|
||||
view.hydrate(new Injector([]), null, {});
|
||||
return view;
|
||||
}
|
||||
|
||||
compiler.compile(MyComp, el(temp)).
|
||||
then(createView).
|
||||
then((view) => {
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('Before LightDOM After');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Template({
|
||||
selector: '[trivial-template]'
|
||||
})
|
||||
class TrivialTemplateDirective {
|
||||
constructor(viewPort:ViewPort) {
|
||||
viewPort.create();
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'emulated-shadow-dom-component',
|
||||
template: new TemplateConfig({
|
||||
inline: 'Before <content></content> After',
|
||||
directives: []
|
||||
}),
|
||||
shadowDom: ShadowDomEmulated
|
||||
})
|
||||
class EmulatedShadowDomCmp {
|
||||
|
||||
}
|
||||
|
||||
@Decorator({
|
||||
selector: '[my-dir]',
|
||||
bind: {'elprop':'dirProp'}
|
||||
@ -166,7 +125,7 @@ class MyDir {
|
||||
|
||||
@Component({
|
||||
template: new TemplateConfig({
|
||||
directives: [MyDir, ChildComp, SomeTemplate, EmulatedShadowDomCmp, TrivialTemplateDirective]
|
||||
directives: [MyDir, ChildComp, SomeTemplate]
|
||||
})
|
||||
})
|
||||
class MyComp {
|
||||
@ -207,3 +166,4 @@ class MyService {
|
||||
this.greeting = 'hello';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,22 +14,20 @@ var _script = `<script type="ng/content"></script>`;
|
||||
export function main() {
|
||||
describe('Content', function() {
|
||||
it("should insert the nodes", () => {
|
||||
var lightDom = new DummyLightDom();
|
||||
var parent = el("<div><content></content></div>");
|
||||
var content = DOM.firstChild(parent);
|
||||
|
||||
var c = new Content(lightDom, new NgElement(content));
|
||||
var c = new Content(null, new NgElement(content));
|
||||
c.insert([el("<a></a>"), el("<b></b>")])
|
||||
|
||||
expect(DOM.getInnerHTML(parent)).toEqual(`${_script}<a></a><b></b>${_script}`);
|
||||
});
|
||||
|
||||
it("should remove the nodes from the previous insertion", () => {
|
||||
var lightDom = new DummyLightDom();
|
||||
var parent = el("<div><content></content></div>");
|
||||
var content = DOM.firstChild(parent);
|
||||
|
||||
var c = new Content(lightDom, new NgElement(content));
|
||||
var c = new Content(null, new NgElement(content));
|
||||
c.insert([el("<a></a>")]);
|
||||
c.insert([el("<b></b>")]);
|
||||
|
||||
@ -37,11 +35,10 @@ export function main() {
|
||||
});
|
||||
|
||||
it("should insert empty list", () => {
|
||||
var lightDom = new DummyLightDom();
|
||||
var parent = el("<div><content></content></div>");
|
||||
var content = DOM.firstChild(parent);
|
||||
|
||||
var c = new Content(lightDom, new NgElement(content));
|
||||
var c = new Content(null, new NgElement(content));
|
||||
c.insert([el("<a></a>")]);
|
||||
c.insert([]);
|
||||
|
||||
|
@ -15,10 +15,12 @@ import {ProtoRecordRange} from 'change_detection/change_detection';
|
||||
class FakeElementInjector {
|
||||
content;
|
||||
viewPort;
|
||||
element;
|
||||
|
||||
constructor(content, viewPort) {
|
||||
constructor(content = null, viewPort = null, element = null) {
|
||||
this.content = content;
|
||||
this.viewPort = viewPort;
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
hasDirective(type) {
|
||||
@ -29,6 +31,10 @@ class FakeElementInjector {
|
||||
return this.viewPort != null;
|
||||
}
|
||||
|
||||
forElement(n) {
|
||||
return this.element == n;
|
||||
}
|
||||
|
||||
get(t) {
|
||||
if (t === Content) return this.content;
|
||||
if (t === ViewPort) return this.viewPort;
|
||||
@ -44,16 +50,9 @@ class FakeElementInjector {
|
||||
@IMPLEMENTS(View)
|
||||
class FakeView {
|
||||
elementInjectors;
|
||||
ports;
|
||||
|
||||
constructor(elementInjectors = null, ports = null) {
|
||||
constructor(elementInjectors = null) {
|
||||
this.elementInjectors = elementInjectors;
|
||||
this.ports = ports;
|
||||
}
|
||||
|
||||
getViewPortByTemplateElement(el) {
|
||||
if (isBlank(this.ports)) return null;
|
||||
return MapWrapper.get(this.ports, el);
|
||||
}
|
||||
|
||||
noSuchMethod(i) {
|
||||
@ -67,7 +66,7 @@ class FakeViewPort {
|
||||
_nodes;
|
||||
_contentTagContainers;
|
||||
|
||||
constructor(nodes, views) {
|
||||
constructor(nodes = null, views = null) {
|
||||
this._nodes = nodes;
|
||||
this._contentTagContainers = views;
|
||||
}
|
||||
@ -90,14 +89,19 @@ class FakeViewPort {
|
||||
@IMPLEMENTS(Content)
|
||||
class FakeContentTag {
|
||||
select;
|
||||
nodes;
|
||||
_nodes;
|
||||
|
||||
constructor(select = null) {
|
||||
constructor(select = null, nodes = null) {
|
||||
this.select = select;
|
||||
this._nodes = nodes;
|
||||
}
|
||||
|
||||
insert(nodes){
|
||||
this.nodes = ListWrapper.clone(nodes);
|
||||
this._nodes = ListWrapper.clone(nodes);
|
||||
}
|
||||
|
||||
nodes() {
|
||||
return this._nodes;
|
||||
}
|
||||
|
||||
noSuchMethod(i) {
|
||||
@ -111,13 +115,13 @@ export function main() {
|
||||
var lightDomView;
|
||||
|
||||
beforeEach(() => {
|
||||
lightDomView = new FakeView([], MapWrapper.create());
|
||||
lightDomView = new FakeView([]);
|
||||
});
|
||||
|
||||
describe("contentTags", () => {
|
||||
it("should collect content tags from element injectors", () => {
|
||||
var tag = new FakeContentTag();
|
||||
var shadowDomView = new FakeView([new FakeElementInjector(tag, null)]);
|
||||
var shadowDomView = new FakeView([new FakeElementInjector(tag)]);
|
||||
|
||||
var lightDom = new LightDom(lightDomView, shadowDomView, el("<div></div>"));
|
||||
|
||||
@ -147,15 +151,34 @@ export function main() {
|
||||
|
||||
it("should include view port nodes", () => {
|
||||
var lightDomEl = el("<div><template></template></div>")
|
||||
var template = lightDomEl.childNodes[0];
|
||||
|
||||
var lightDomView = new FakeView([],
|
||||
MapWrapper.createFromPairs([
|
||||
[template, new FakeViewPort([el("<a></a>")], null)]
|
||||
])
|
||||
);
|
||||
var lightDomView = new FakeView([
|
||||
new FakeElementInjector(
|
||||
null,
|
||||
new FakeViewPort([el("<a></a>")]),
|
||||
DOM.firstChild(lightDomEl))]);
|
||||
|
||||
var lightDom = new LightDom(lightDomView, new FakeView(), lightDomEl);
|
||||
var lightDom = new LightDom(
|
||||
lightDomView,
|
||||
new FakeView(),
|
||||
lightDomEl);
|
||||
|
||||
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["<a></a>"]);
|
||||
});
|
||||
|
||||
it("should include content nodes", () => {
|
||||
var lightDomEl = el("<div><content></content></div>")
|
||||
|
||||
var lightDomView = new FakeView([
|
||||
new FakeElementInjector(
|
||||
new FakeContentTag(null, [el("<a></a>")]),
|
||||
null,
|
||||
DOM.firstChild(lightDomEl))]);
|
||||
|
||||
var lightDom = new LightDom(
|
||||
lightDomView,
|
||||
new FakeView(),
|
||||
lightDomEl);
|
||||
|
||||
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["<a></a>"]);
|
||||
});
|
||||
@ -175,8 +198,8 @@ export function main() {
|
||||
|
||||
lightDom.redistribute();
|
||||
|
||||
expect(toHtml(contentA.nodes)).toEqual(["<a>1</a>", "<a>3</a>"]);
|
||||
expect(toHtml(contentB.nodes)).toEqual(["<b>2</b>"]);
|
||||
expect(toHtml(contentA.nodes())).toEqual(["<a>1</a>", "<a>3</a>"]);
|
||||
expect(toHtml(contentB.nodes())).toEqual(["<b>2</b>"]);
|
||||
});
|
||||
|
||||
it("should support wildcard content tags", () => {
|
||||
@ -192,8 +215,8 @@ export function main() {
|
||||
|
||||
lightDom.redistribute();
|
||||
|
||||
expect(toHtml(wildcard.nodes)).toEqual(["<a>1</a>", "<b>2</b>", "<a>3</a>"]);
|
||||
expect(toHtml(contentB.nodes)).toEqual([]);
|
||||
expect(toHtml(wildcard.nodes())).toEqual(["<a>1</a>", "<b>2</b>", "<a>3</a>"]);
|
||||
expect(toHtml(contentB.nodes())).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -0,0 +1,311 @@
|
||||
import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'test_lib/test_lib';
|
||||
|
||||
import {DOM} from 'facade/dom';
|
||||
|
||||
import {Injector} from 'di/di';
|
||||
import {Lexer, Parser, ChangeDetector} from 'change_detection/change_detection';
|
||||
|
||||
import {Compiler, CompilerCache} from 'core/compiler/compiler';
|
||||
import {LifeCycle} from 'core/life_cycle/life_cycle';
|
||||
import {DirectiveMetadataReader} from 'core/compiler/directive_metadata_reader';
|
||||
import {ShadowDomStrategy, ShadowDomNative, ShadowDomEmulated} from 'core/compiler/shadow_dom';
|
||||
|
||||
import {Decorator, Component, Template} from 'core/annotations/annotations';
|
||||
import {TemplateConfig} from 'core/annotations/template_config';
|
||||
|
||||
import {ViewPort} from 'core/compiler/viewport';
|
||||
import {StringMapWrapper, MapWrapper} from 'facade/collection';
|
||||
|
||||
export function main() {
|
||||
describe('integration tests', function() {
|
||||
|
||||
StringMapWrapper.forEach(
|
||||
{"native" : ShadowDomNative, "emulated" : ShadowDomEmulated}, (strategy, name) => {
|
||||
|
||||
describe(`${name} shadow dom strategy`, () => {
|
||||
var compiler;
|
||||
|
||||
beforeEach( () => {
|
||||
compiler = new Compiler(null, new TestDirectiveMetadataReader(strategy),
|
||||
new Parser(new Lexer()), new CompilerCache());
|
||||
});
|
||||
|
||||
function compile(template, assertions) {
|
||||
compiler.compile(MyComp, el(template)).
|
||||
then(createView).
|
||||
then((view) => {
|
||||
var lc = new LifeCycle(new ChangeDetector(view.recordRange));
|
||||
assertions(view, lc);
|
||||
});
|
||||
}
|
||||
|
||||
it('should support multiple content tags', (done) => {
|
||||
var temp = '<multiple-content-tags>' +
|
||||
'<div>B</div>' +
|
||||
'<div>C</div>' +
|
||||
'<div class="left">A</div>' +
|
||||
'</multiple-content-tags>';
|
||||
|
||||
compile(temp, (view, lc) => {
|
||||
expect(view.nodes).toHaveText('(A, BC)');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should redistribute only direct children', (done) => {
|
||||
var temp = '<multiple-content-tags>' +
|
||||
'<div>B<div class="left">A</div></div>' +
|
||||
'<div>C</div>' +
|
||||
'</multiple-content-tags>';
|
||||
|
||||
compile(temp, (view, lc) => {
|
||||
expect(view.nodes).toHaveText('(, BAC)');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should redistribute when the light dom changes", (done) => {
|
||||
var temp = '<multiple-content-tags>' +
|
||||
'<div template="manual" class="left">A</div>' +
|
||||
'<div>B</div>' +
|
||||
'</multiple-content-tags>';
|
||||
|
||||
compile(temp, (view, lc) => {
|
||||
var dir = view.elementInjectors[1].get(ManualTemplateDirective);
|
||||
|
||||
expect(view.nodes).toHaveText('(, B)');
|
||||
|
||||
dir.show();
|
||||
lc.tick();
|
||||
|
||||
expect(view.nodes).toHaveText('(A, B)');
|
||||
|
||||
dir.hide();
|
||||
lc.tick();
|
||||
|
||||
expect(view.nodes).toHaveText('(, B)');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should support nested components", (done) => {
|
||||
var temp = '<outer-with-indirect-nested>' +
|
||||
'<div>A</div>' +
|
||||
'<div>B</div>' +
|
||||
'</outer-with-indirect-nested>';
|
||||
|
||||
compile(temp, (view, lc) => {
|
||||
expect(view.nodes).toHaveText('OUTER(SIMPLE(AB))');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should support nesting with content being direct child of a nested component", (done) => {
|
||||
var temp = '<outer>' +
|
||||
'<div template="manual" class="left">A</div>' +
|
||||
'<div>B</div>' +
|
||||
'<div>C</div>' +
|
||||
'</outer>';
|
||||
|
||||
compile(temp, (view, lc) => {
|
||||
var dir = view.elementInjectors[1].get(ManualTemplateDirective);
|
||||
|
||||
expect(view.nodes).toHaveText('OUTER(INNER(INNERINNER(,BC)))');
|
||||
|
||||
dir.show();
|
||||
lc.tick();
|
||||
|
||||
expect(view.nodes).toHaveText('OUTER(INNER(INNERINNER(A,BC)))');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Enable once dom-write queue is implemented and onDehydrate is implemented
|
||||
//it('should redistribute when the shadow dom changes', (done) => {
|
||||
// var temp = '<conditional-content>' +
|
||||
// '<div class="left">A</div>' +
|
||||
// '<div>B</div>' +
|
||||
// '<div>C</div>' +
|
||||
// '</conditional-content>';
|
||||
//
|
||||
//
|
||||
// compile(temp, (view, lc) => {
|
||||
// var cmp = view.elementInjectors[0].get(ConditionalContentComponent);
|
||||
//
|
||||
// expect(view.nodes).toHaveText('(, ABC)');
|
||||
//
|
||||
// cmp.showLeft();
|
||||
// lc.tick();
|
||||
//
|
||||
// expect(view.nodes).toHaveText('(A, BC)');
|
||||
//
|
||||
// cmp.hideLeft()
|
||||
// lc.tick();
|
||||
//
|
||||
// expect(view.nodes).toHaveText('(, ABC)');
|
||||
//
|
||||
// done();
|
||||
// });
|
||||
//});
|
||||
|
||||
//Implement once NgElement support changing a class
|
||||
//it("should redistribute when a class has been added or removed");
|
||||
//it('should not lose focus', () => {
|
||||
// var temp = `<simple>aaa<input type="text" id="focused-input" ng-class="{'aClass' : showClass}"> bbb</simple>`;
|
||||
//
|
||||
// compile(temp, (view, lc) => {
|
||||
// var input = view.nodes[1];
|
||||
// input.focus();
|
||||
//
|
||||
// expect(document.activeElement.id).toEqual("focused-input");
|
||||
//
|
||||
// // update class of input
|
||||
//
|
||||
// expect(document.activeElement.id).toEqual("focused-input");
|
||||
// });
|
||||
//});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
class TestDirectiveMetadataReader extends DirectiveMetadataReader {
|
||||
shadowDomStrategy;
|
||||
|
||||
constructor(shadowDomStrategy) {
|
||||
this.shadowDomStrategy = shadowDomStrategy;
|
||||
}
|
||||
|
||||
parseShadowDomStrategy(annotation:Component):ShadowDomStrategy{
|
||||
return this.shadowDomStrategy;
|
||||
}
|
||||
}
|
||||
|
||||
@Template({
|
||||
selector: '[manual]'
|
||||
})
|
||||
class ManualTemplateDirective {
|
||||
viewPort;
|
||||
constructor(viewPort:ViewPort) {
|
||||
this.viewPort = viewPort;
|
||||
}
|
||||
|
||||
show() { this.viewPort.create(); }
|
||||
hide() { this.viewPort.remove(0); }
|
||||
}
|
||||
|
||||
@Template({
|
||||
selector: '[auto]',
|
||||
bind: {
|
||||
'auto': 'auto'
|
||||
}
|
||||
})
|
||||
class AutoTemplateDirective {
|
||||
viewPort;
|
||||
constructor(viewPort:ViewPort) {
|
||||
this.viewPort = viewPort;
|
||||
}
|
||||
|
||||
set auto(newValue:boolean) {
|
||||
if (newValue) {
|
||||
this.viewPort.create();
|
||||
} else {
|
||||
this.viewPort.remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'simple',
|
||||
template: new TemplateConfig({
|
||||
inline: 'SIMPLE(<content></content>)'
|
||||
})
|
||||
})
|
||||
class Simple {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'multiple-content-tags',
|
||||
template: new TemplateConfig({
|
||||
inline: '(<content select=".left"></content>, <content></content>)'
|
||||
})
|
||||
})
|
||||
class MultipleContentTagsComponent {
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'conditional-content',
|
||||
template: new TemplateConfig({
|
||||
inline: '<div>(<div template="auto: cond"><content select=".left"></content></div>, <content></content>)</div>',
|
||||
directives: [AutoTemplateDirective]
|
||||
})
|
||||
})
|
||||
class ConditionalContentComponent {
|
||||
cond:boolean;
|
||||
|
||||
constructor() {
|
||||
this.cond = false;
|
||||
}
|
||||
|
||||
showLeft() { this.cond = true; }
|
||||
hideLeft() { this.cond = false; }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'outer-with-indirect-nested',
|
||||
template: new TemplateConfig({
|
||||
inline: 'OUTER(<simple><div><content></content></div></simple>)',
|
||||
directives: [Simple]
|
||||
})
|
||||
})
|
||||
class OuterWithIndirectNestedComponent {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'outer',
|
||||
template: new TemplateConfig({
|
||||
inline: 'OUTER(<inner><content></content></inner>)',
|
||||
directives: [InnerComponent]
|
||||
})
|
||||
})
|
||||
class OuterComponent {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'inner',
|
||||
template: new TemplateConfig({
|
||||
inline: 'INNER(<innerinner><content></content></innerinner>)',
|
||||
directives: [InnerInnerComponent]
|
||||
})
|
||||
})
|
||||
class InnerComponent {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'innerinner',
|
||||
template: new TemplateConfig({
|
||||
inline: 'INNERINNER(<content select=".left"></content>,<content></content>)'
|
||||
})
|
||||
})
|
||||
class InnerInnerComponent {
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
template: new TemplateConfig({
|
||||
directives: [MultipleContentTagsComponent, ManualTemplateDirective,
|
||||
ConditionalContentComponent, OuterWithIndirectNestedComponent, OuterComponent]
|
||||
})
|
||||
})
|
||||
class MyComp {
|
||||
}
|
||||
|
||||
function createView(pv) {
|
||||
var view = pv.instantiate(null);
|
||||
view.hydrate(new Injector([]), null, {});
|
||||
return view;
|
||||
}
|
@ -69,25 +69,6 @@ export function main() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("getViewPortByTemplateElement", () => {
|
||||
var view, viewPort, templateElement;
|
||||
|
||||
beforeEach(() => {
|
||||
templateElement = el("<template></template>");
|
||||
view = new View(null, null, new ProtoRecordRange(), MapWrapper.create());
|
||||
viewPort = new FakeViewPort(templateElement);
|
||||
view.viewPorts = [viewPort];
|
||||
});
|
||||
|
||||
it("should return null when the given element is not an element", () => {
|
||||
expect(view.getViewPortByTemplateElement("not an element")).toBeNull();
|
||||
});
|
||||
|
||||
it("should return a view port with the matching template element", () => {
|
||||
expect(view.getViewPortByTemplateElement(templateElement)).toBe(viewPort);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with locals', function() {
|
||||
var view;
|
||||
beforeEach(() => {
|
||||
@ -204,7 +185,7 @@ export function main() {
|
||||
it('should be off by default.', () => {
|
||||
var template = el('<div></div>')
|
||||
var view = new ProtoView(template, new ProtoRecordRange())
|
||||
.instantiate(null);
|
||||
.instantiate(null);
|
||||
view.hydrate(null, null, null);
|
||||
expect(view.nodes[0]).not.toBe(template);
|
||||
});
|
||||
@ -333,24 +314,24 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should expose component services and component instance to directives in the shadow Dom',
|
||||
() => {
|
||||
var subpv = new ProtoView(
|
||||
() => {
|
||||
var subpv = new ProtoView(
|
||||
el('<div dec class="ng-binding">hello shadow dom</div>'), new ProtoRecordRange());
|
||||
subpv.bindElement(
|
||||
subpv.bindElement(
|
||||
new ProtoElementInjector(null, 0, [ServiceDependentDecorator]));
|
||||
var pv = createComponentWithSubPV(subpv);
|
||||
var pv = createComponentWithSubPV(subpv);
|
||||
|
||||
var view = createNestedView(pv);
|
||||
var view = createNestedView(pv);
|
||||
|
||||
var subView = view.componentChildViews[0];
|
||||
var subInj = subView.rootElementInjectors[0];
|
||||
var subDecorator = subInj.get(ServiceDependentDecorator);
|
||||
var comp = view.rootElementInjectors[0].get(SomeComponent);
|
||||
var subView = view.componentChildViews[0];
|
||||
var subInj = subView.rootElementInjectors[0];
|
||||
var subDecorator = subInj.get(ServiceDependentDecorator);
|
||||
var comp = view.rootElementInjectors[0].get(SomeComponent);
|
||||
|
||||
expect(subDecorator).toBeAnInstanceOf(ServiceDependentDecorator);
|
||||
expect(subDecorator.service).toBe(comp.service);
|
||||
expect(subDecorator.component).toBe(comp);
|
||||
});
|
||||
expect(subDecorator).toBeAnInstanceOf(ServiceDependentDecorator);
|
||||
expect(subDecorator.service).toBe(comp.service);
|
||||
expect(subDecorator.component).toBe(comp);
|
||||
});
|
||||
|
||||
function expectViewHasNoDirectiveInstances(view) {
|
||||
view.elementInjectors.forEach((inj) => expect(inj.hasInstances()).toBe(false));
|
||||
@ -358,9 +339,9 @@ export function main() {
|
||||
|
||||
it('dehydration should dehydrate child component views too', () => {
|
||||
var subpv = new ProtoView(
|
||||
el('<div dec class="ng-binding">hello shadow dom</div>'), new ProtoRecordRange());
|
||||
el('<div dec class="ng-binding">hello shadow dom</div>'), new ProtoRecordRange());
|
||||
subpv.bindElement(
|
||||
new ProtoElementInjector(null, 0, [ServiceDependentDecorator]));
|
||||
new ProtoElementInjector(null, 0, [ServiceDependentDecorator]));
|
||||
var pv = createComponentWithSubPV(subpv);
|
||||
|
||||
var view = createNestedView(pv);
|
||||
@ -369,7 +350,7 @@ export function main() {
|
||||
expect(view.hydrated()).toBe(false);
|
||||
expectViewHasNoDirectiveInstances(view);
|
||||
view.componentChildViews.forEach(
|
||||
(view) => expectViewHasNoDirectiveInstances(view));
|
||||
(view) => expectViewHasNoDirectiveInstances(view));
|
||||
});
|
||||
|
||||
it('should create shadow dom', () => {
|
||||
@ -398,7 +379,7 @@ export function main() {
|
||||
describe('with template views', () => {
|
||||
function createViewWithTemplate() {
|
||||
var templateProtoView = new ProtoView(
|
||||
el('<div id="1"></div>'), new ProtoRecordRange());
|
||||
el('<div id="1"></div>'), new ProtoRecordRange());
|
||||
var pv = new ProtoView(el('<someTmpl class="ng-binding"></someTmpl>'), new ProtoRecordRange());
|
||||
var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeTemplate]));
|
||||
binder.templateDirective = someTemplateDirective;
|
||||
@ -422,37 +403,6 @@ export function main() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('event handlers', () => {
|
||||
var view, ctx, called;
|
||||
|
||||
function createViewAndContext(protoView) {
|
||||
view = createView(protoView);
|
||||
ctx = view.context;
|
||||
called = 0;
|
||||
ctx.callMe = () => called += 1;
|
||||
}
|
||||
|
||||
function dispatchClick(el) {
|
||||
DOM.dispatchEvent(el, DOM.createMouseEvent('click'));
|
||||
}
|
||||
|
||||
it('should fire on non-bubbling native events', () => {
|
||||
var pv = new ProtoView(el('<div class="ng-binding"><div></div></div>'),
|
||||
new ProtoRecordRange());
|
||||
pv.bindElement(null);
|
||||
pv.bindEvent('click', parser.parseBinding('callMe()', null));
|
||||
createViewAndContext(pv);
|
||||
|
||||
dispatchClick(view.nodes[0]);
|
||||
dispatchClick(view.nodes[0].firstChild);
|
||||
|
||||
// the bubbled event does not execute the expression.
|
||||
// It is trivially passing on webkit browsers due to
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=122755
|
||||
expect(called).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('react to record changes', () => {
|
||||
var view, cd, ctx;
|
||||
|
||||
@ -633,7 +583,6 @@ class MyEvaluationContext {
|
||||
foo:string;
|
||||
a;
|
||||
b;
|
||||
callMe;
|
||||
constructor() {
|
||||
this.foo = 'bar';
|
||||
};
|
||||
|
Reference in New Issue
Block a user