fix(shadowdom): allow conditional content tags.
Distribution is triggered on the host element injector after each new view creation.
This commit is contained in:
parent
a82e20889d
commit
f7963e1ea6
@ -5,7 +5,7 @@ import {Injector, Key, Dependency, bind, Binding, NoProviderError, ProviderError
|
|||||||
import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility';
|
import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility';
|
||||||
import {EventEmitter, PropertySetter} from 'angular2/src/core/annotations/di';
|
import {EventEmitter, PropertySetter} from 'angular2/src/core/annotations/di';
|
||||||
import * as viewModule from 'angular2/src/core/compiler/view';
|
import * as viewModule from 'angular2/src/core/compiler/view';
|
||||||
import {LightDom, SourceLightDom, DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
|
import {LightDom, DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
|
||||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||||
import {NgElement} from 'angular2/src/core/dom/element';
|
import {NgElement} from 'angular2/src/core/dom/element';
|
||||||
import {Directive, onChange, onDestroy} from 'angular2/src/core/annotations/annotations'
|
import {Directive, onChange, onDestroy} from 'angular2/src/core/annotations/annotations'
|
||||||
@ -25,7 +25,7 @@ class StaticKeys {
|
|||||||
ngElementId:number;
|
ngElementId:number;
|
||||||
viewContainerId:number;
|
viewContainerId:number;
|
||||||
destinationLightDomId:number;
|
destinationLightDomId:number;
|
||||||
sourceLightDomId:number;
|
lightDomId:number;
|
||||||
bindingPropagationConfigId:number;
|
bindingPropagationConfigId:number;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -34,7 +34,7 @@ class StaticKeys {
|
|||||||
this.ngElementId = Key.get(NgElement).id;
|
this.ngElementId = Key.get(NgElement).id;
|
||||||
this.viewContainerId = Key.get(ViewContainer).id;
|
this.viewContainerId = Key.get(ViewContainer).id;
|
||||||
this.destinationLightDomId = Key.get(DestinationLightDom).id;
|
this.destinationLightDomId = Key.get(DestinationLightDom).id;
|
||||||
this.sourceLightDomId = Key.get(SourceLightDom).id;
|
this.lightDomId = Key.get(LightDom).id;
|
||||||
this.bindingPropagationConfigId = Key.get(BindingPropagationConfig).id;
|
this.bindingPropagationConfigId = Key.get(BindingPropagationConfig).id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,8 +581,8 @@ export class ElementInjector extends TreeNode {
|
|||||||
var p:ElementInjector = this.directParent();
|
var p:ElementInjector = this.directParent();
|
||||||
return isPresent(p) ? p._preBuiltObjects.lightDom : null;
|
return isPresent(p) ? p._preBuiltObjects.lightDom : null;
|
||||||
}
|
}
|
||||||
if (keyId === staticKeys.sourceLightDomId) {
|
if (keyId === staticKeys.lightDomId) {
|
||||||
return this._host._preBuiltObjects.lightDom;
|
return this._preBuiltObjects.lightDom;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO add other objects as needed
|
//TODO add other objects as needed
|
||||||
|
@ -7,7 +7,6 @@ import {ElementInjector} from '../element_injector';
|
|||||||
import {ViewContainer} from '../view_container';
|
import {ViewContainer} from '../view_container';
|
||||||
import {Content} from './content_tag';
|
import {Content} from './content_tag';
|
||||||
|
|
||||||
export class SourceLightDom {}
|
|
||||||
export class DestinationLightDom {}
|
export class DestinationLightDom {}
|
||||||
|
|
||||||
|
|
||||||
@ -21,7 +20,7 @@ class _Root {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: LightDom should implement SourceLightDom and DestinationLightDom
|
// TODO: LightDom should implement DestinationLightDom
|
||||||
// once interfaces are supported
|
// once interfaces are supported
|
||||||
export class LightDom {
|
export class LightDom {
|
||||||
// The light DOM of the element is enclosed inside the lightDomView
|
// The light DOM of the element is enclosed inside the lightDomView
|
||||||
|
@ -6,17 +6,19 @@ import {Injector} from 'angular2/di';
|
|||||||
import * as eiModule from 'angular2/src/core/compiler/element_injector';
|
import * as eiModule from 'angular2/src/core/compiler/element_injector';
|
||||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||||
import {EventManager} from 'angular2/src/core/events/event_manager';
|
import {EventManager} from 'angular2/src/core/events/event_manager';
|
||||||
|
import * as ldModule from './shadow_dom_emulation/light_dom';
|
||||||
|
|
||||||
export class ViewContainer {
|
export class ViewContainer {
|
||||||
parentView: viewModule.View;
|
parentView: viewModule.View;
|
||||||
templateElement;
|
templateElement;
|
||||||
defaultProtoView: viewModule.ProtoView;
|
defaultProtoView: viewModule.ProtoView;
|
||||||
_views: List<viewModule.View>;
|
_views: List<viewModule.View>;
|
||||||
_lightDom: any;
|
_lightDom: ldModule.LightDom;
|
||||||
_eventManager: EventManager;
|
_eventManager: EventManager;
|
||||||
elementInjector: eiModule.ElementInjector;
|
elementInjector: eiModule.ElementInjector;
|
||||||
appInjector: Injector;
|
appInjector: Injector;
|
||||||
hostElementInjector: eiModule.ElementInjector;
|
hostElementInjector: eiModule.ElementInjector;
|
||||||
|
hostLightDom: ldModule.LightDom;
|
||||||
|
|
||||||
constructor(parentView: viewModule.View,
|
constructor(parentView: viewModule.View,
|
||||||
templateElement,
|
templateElement,
|
||||||
@ -34,17 +36,20 @@ export class ViewContainer {
|
|||||||
this._views = [];
|
this._views = [];
|
||||||
this.appInjector = null;
|
this.appInjector = null;
|
||||||
this.hostElementInjector = null;
|
this.hostElementInjector = null;
|
||||||
|
this.hostLightDom = null;
|
||||||
this._eventManager = eventManager;
|
this._eventManager = eventManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
hydrate(appInjector: Injector, hostElementInjector: eiModule.ElementInjector) {
|
hydrate(appInjector: Injector, hostElementInjector: eiModule.ElementInjector) {
|
||||||
this.appInjector = appInjector;
|
this.appInjector = appInjector;
|
||||||
this.hostElementInjector = hostElementInjector;
|
this.hostElementInjector = hostElementInjector;
|
||||||
|
this.hostLightDom = isPresent(hostElementInjector) ? hostElementInjector.get(ldModule.LightDom) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
dehydrate() {
|
dehydrate() {
|
||||||
this.appInjector = null;
|
this.appInjector = null;
|
||||||
this.hostElementInjector = null;
|
this.hostElementInjector = null;
|
||||||
|
this.hostLightDom = null;
|
||||||
this.clear();
|
this.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +86,11 @@ export class ViewContainer {
|
|||||||
// insertion must come before hydration so that element injector trees are attached.
|
// insertion must come before hydration so that element injector trees are attached.
|
||||||
this.insert(newView, atIndex);
|
this.insert(newView, atIndex);
|
||||||
newView.hydrate(this.appInjector, this.hostElementInjector, this.parentView.context);
|
newView.hydrate(this.appInjector, this.hostElementInjector, this.parentView.context);
|
||||||
|
|
||||||
|
// new content tags might have appeared, we need to redistrubute.
|
||||||
|
if (isPresent(this.hostLightDom)) {
|
||||||
|
this.hostLightDom.redistribute();
|
||||||
|
}
|
||||||
return newView;
|
return newView;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,6 +104,7 @@ export class ViewContainer {
|
|||||||
}
|
}
|
||||||
this.parentView.changeDetector.addChild(view.changeDetector);
|
this.parentView.changeDetector.addChild(view.changeDetector);
|
||||||
this._linkElementInjectors(view);
|
this._linkElementInjectors(view);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +130,10 @@ export class ViewContainer {
|
|||||||
} else {
|
} else {
|
||||||
this._lightDom.redistribute();
|
this._lightDom.redistribute();
|
||||||
}
|
}
|
||||||
|
// content tags might have disappeared we need to do redistribution.
|
||||||
|
if (isPresent(this.hostLightDom)) {
|
||||||
|
this.hostLightDom.redistribute();
|
||||||
|
}
|
||||||
detachedView.changeDetector.remove();
|
detachedView.changeDetector.remove();
|
||||||
this._unlinkElementInjectors(detachedView);
|
this._unlinkElementInjectors(detachedView);
|
||||||
return detachedView;
|
return detachedView;
|
||||||
|
@ -9,7 +9,7 @@ import {Optional, Injector, Inject, bind} from 'angular2/di';
|
|||||||
import {ProtoView, View} from 'angular2/src/core/compiler/view';
|
import {ProtoView, View} from 'angular2/src/core/compiler/view';
|
||||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||||
import {NgElement} from 'angular2/src/core/dom/element';
|
import {NgElement} from 'angular2/src/core/dom/element';
|
||||||
import {LightDom, SourceLightDom, DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
|
import {LightDom, DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
|
||||||
import {Directive} from 'angular2/src/core/annotations/annotations';
|
import {Directive} from 'angular2/src/core/annotations/annotations';
|
||||||
import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config';
|
import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config';
|
||||||
import {DynamicProtoChangeDetector} from 'angular2/change_detection';
|
import {DynamicProtoChangeDetector} from 'angular2/change_detection';
|
||||||
@ -455,10 +455,10 @@ export function main() {
|
|||||||
parentPreBuiltObjects = new PreBuiltObjects(null, null, null, lightDom, null);
|
parentPreBuiltObjects = new PreBuiltObjects(null, null, null, lightDom, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return destination light DOM from the parent's injector", function () {
|
it("should return light DOM from the current injector", function () {
|
||||||
var child = parentChildInjectors([], [], parentPreBuiltObjects);
|
var inj = injector([], null, null, parentPreBuiltObjects);
|
||||||
|
|
||||||
expect(child.get(DestinationLightDom)).toEqual(lightDom);
|
expect(inj.get(LightDom)).toEqual(lightDom);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return null when parent's injector is a component boundary", function () {
|
it("should return null when parent's injector is a component boundary", function () {
|
||||||
@ -466,12 +466,6 @@ export function main() {
|
|||||||
|
|
||||||
expect(child.get(DestinationLightDom)).toBeNull();
|
expect(child.get(DestinationLightDom)).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return source light DOM from the closest component boundary", function () {
|
|
||||||
var child = hostShadowInjectors([], [], parentPreBuiltObjects);
|
|
||||||
|
|
||||||
expect(child.get(SourceLightDom)).toEqual(lightDom);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -188,33 +188,32 @@ export function main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Enable once dom-write queue is implemented and onDehydrate is implemented
|
it('should redistribute when the shadow dom changes', (done) => {
|
||||||
//it('should redistribute when the shadow dom changes', (done) => {
|
var temp = '<conditional-content>' +
|
||||||
// var temp = '<conditional-content>' +
|
'<div class="left">A</div>' +
|
||||||
// '<div class="left">A</div>' +
|
'<div>B</div>' +
|
||||||
// '<div>B</div>' +
|
'<div>C</div>' +
|
||||||
// '<div>C</div>' +
|
'</conditional-content>';
|
||||||
// '</conditional-content>';
|
|
||||||
//
|
|
||||||
//
|
compile(temp, [ConditionalContentComponent, AutoViewportDirective], (view, lc) => {
|
||||||
// compile(temp, (view, lc) => {
|
var cmp = view.elementInjectors[0].get(ConditionalContentComponent);
|
||||||
// var cmp = view.elementInjectors[0].get(ConditionalContentComponent);
|
|
||||||
//
|
expect(view.nodes).toHaveText('(, ABC)');
|
||||||
// expect(view.nodes).toHaveText('(, ABC)');
|
|
||||||
//
|
cmp.showLeft();
|
||||||
// cmp.showLeft();
|
lc.tick();
|
||||||
// lc.tick();
|
|
||||||
//
|
expect(view.nodes).toHaveText('(A, BC)');
|
||||||
// expect(view.nodes).toHaveText('(A, BC)');
|
|
||||||
//
|
cmp.hideLeft();
|
||||||
// cmp.hideLeft()
|
lc.tick();
|
||||||
// lc.tick();
|
|
||||||
//
|
expect(view.nodes).toHaveText('(, ABC)');
|
||||||
// expect(view.nodes).toHaveText('(, ABC)');
|
|
||||||
//
|
done();
|
||||||
// done();
|
});
|
||||||
// });
|
});
|
||||||
//});
|
|
||||||
|
|
||||||
//Implement once NgElement support changing a class
|
//Implement once NgElement support changing a class
|
||||||
//it("should redistribute when a class has been added or removed");
|
//it("should redistribute when a class has been added or removed");
|
||||||
@ -300,7 +299,7 @@ class MultipleContentTagsComponent {
|
|||||||
|
|
||||||
@Component({selector: 'conditional-content'})
|
@Component({selector: 'conditional-content'})
|
||||||
@Template({
|
@Template({
|
||||||
inline: '<div>(<div template="auto: cond"><content select=".left"></content></div>, <content></content>)</div>',
|
inline: '<div>(<div *auto="cond"><content select=".left"></content></div>, <content></content>)</div>',
|
||||||
directives: [AutoViewportDirective]
|
directives: [AutoViewportDirective]
|
||||||
})
|
})
|
||||||
class ConditionalContentComponent {
|
class ConditionalContentComponent {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user