refactor(views): clean up creating views in place and extract view_hydrator
Major changes: - `compiler.compileRoot(el, type)` -> `compiler.compileInHost(type) + viewHydrator.hydrateHostViewInPlace(el, view)` - move all `hydrate`/`dehydrate` methods out of `View` and `ViewContainer` into a standalone class `view_hydrator` as private methods and provide new public methods dedicated to the individual use cases. Note: This PR does not change the current functionality, only moves it into different places. See design discussion in #1351, in preparation for imperative views.
This commit is contained in:
192
modules/angular2/src/render/dom/view/view_hydrator.js
vendored
Normal file
192
modules/angular2/src/render/dom/view/view_hydrator.js
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
import {Injectable} from 'angular2/di';
|
||||
import {int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||
|
||||
import * as ldModule from '../shadow_dom/light_dom';
|
||||
import {EventManager} from '../events/event_manager';
|
||||
import {ViewFactory} from './view_factory';
|
||||
import * as vcModule from './view_container';
|
||||
import * as viewModule from './view';
|
||||
|
||||
/**
|
||||
* A dehydrated view is a state of the view that allows it to be moved around
|
||||
* the view tree.
|
||||
*
|
||||
* A dehydrated view has the following properties:
|
||||
*
|
||||
* - all viewcontainers are empty.
|
||||
*
|
||||
* A call to hydrate/dehydrate is called whenever a view is attached/detached,
|
||||
* but it does not do the attach/detach itself.
|
||||
*/
|
||||
@Injectable()
|
||||
export class RenderViewHydrator {
|
||||
_eventManager:EventManager;
|
||||
_viewFactory:ViewFactory;
|
||||
|
||||
constructor(eventManager:EventManager, viewFactory:ViewFactory) {
|
||||
this._eventManager = eventManager;
|
||||
this._viewFactory = viewFactory;
|
||||
}
|
||||
|
||||
hydrateDynamicComponentView(hostView:viewModule.RenderView, boundElementIndex:number, componentView:viewModule.RenderView) {
|
||||
this._viewFactory.setComponentView(hostView, boundElementIndex, componentView);
|
||||
var lightDom = hostView.lightDoms[boundElementIndex];
|
||||
this._viewHydrateRecurse(componentView, lightDom);
|
||||
if (isPresent(lightDom)) {
|
||||
lightDom.redistribute();
|
||||
}
|
||||
}
|
||||
|
||||
dehydrateDynamicComponentView(parentView:viewModule.RenderView, boundElementIndex:number) {
|
||||
throw new BaseException('Not supported yet');
|
||||
// Something along these lines:
|
||||
// var componentView = parentView.componentChildViews[boundElementIndex];
|
||||
// vcModule.ViewContainer.removeViewNodes(componentView);
|
||||
// parentView.componentChildViews[boundElementIndex] = null;
|
||||
// parentView.lightDoms[boundElementIndex] = null;
|
||||
// this._viewDehydrateRecurse(componentView);
|
||||
}
|
||||
|
||||
hydrateInPlaceHostView(parentView:viewModule.RenderView, hostView:viewModule.RenderView) {
|
||||
if (isPresent(parentView)) {
|
||||
throw new BaseException('Not supported yet');
|
||||
}
|
||||
this._viewHydrateRecurse(hostView, null);
|
||||
}
|
||||
|
||||
dehydrateInPlaceHostView(parentView:viewModule.RenderView, hostView:viewModule.RenderView) {
|
||||
if (isPresent(parentView)) {
|
||||
throw new BaseException('Not supported yet');
|
||||
}
|
||||
this._viewDehydrateRecurse(hostView);
|
||||
}
|
||||
|
||||
hydrateViewInViewContainer(viewContainer:vcModule.ViewContainer, view:viewModule.RenderView) {
|
||||
this._viewHydrateRecurse(view, viewContainer.hostLightDom);
|
||||
}
|
||||
|
||||
dehydrateViewInViewContainer(viewContainer:vcModule.ViewContainer, view:viewModule.RenderView) {
|
||||
this._viewDehydrateRecurse(view);
|
||||
}
|
||||
|
||||
_getViewDestLightDom(view, binderIndex) {
|
||||
var binder = view.proto.elementBinders[binderIndex];
|
||||
var destLightDom = null;
|
||||
if (binder.parentIndex !== -1 && binder.distanceToParent === 1) {
|
||||
destLightDom = view.lightDoms[binder.parentIndex];
|
||||
}
|
||||
return destLightDom;
|
||||
}
|
||||
|
||||
_viewHydrateRecurse(view, hostLightDom: ldModule.LightDom) {
|
||||
if (view.hydrated) throw new BaseException('The view is already hydrated.');
|
||||
view.hydrated = true;
|
||||
|
||||
// viewContainers and content tags
|
||||
for (var i = 0; i < view.viewContainers.length; i++) {
|
||||
var vc = view.viewContainers[i];
|
||||
var destLightDom = this._getViewDestLightDom(view, i);
|
||||
if (isPresent(vc)) {
|
||||
this._viewContainerHydrateRecurse(vc, destLightDom, hostLightDom);
|
||||
}
|
||||
var ct = view.contentTags[i];
|
||||
if (isPresent(ct)) {
|
||||
ct.hydrate(destLightDom);
|
||||
}
|
||||
}
|
||||
|
||||
// componentChildViews
|
||||
for (var i = 0; i < view.componentChildViews.length; i++) {
|
||||
var cv = view.componentChildViews[i];
|
||||
if (isPresent(cv)) {
|
||||
this._viewHydrateRecurse(cv, view.lightDoms[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < view.lightDoms.length; ++i) {
|
||||
var lightDom = view.lightDoms[i];
|
||||
if (isPresent(lightDom)) {
|
||||
lightDom.redistribute();
|
||||
}
|
||||
}
|
||||
|
||||
//add global events
|
||||
view.eventHandlerRemovers = ListWrapper.create();
|
||||
var binders = view.proto.elementBinders;
|
||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||
var binder = binders[binderIdx];
|
||||
if (isPresent(binder.globalEvents)) {
|
||||
for (var i = 0; i < binder.globalEvents.length; i++) {
|
||||
var globalEvent = binder.globalEvents[i];
|
||||
var remover = this._createGlobalEventListener(view, binderIdx, globalEvent.name, globalEvent.target, globalEvent.fullName);
|
||||
ListWrapper.push(view.eventHandlerRemovers, remover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_createGlobalEventListener(view, elementIndex, eventName, eventTarget, fullName): Function {
|
||||
return this._eventManager.addGlobalEventListener(eventTarget, eventName, (event) => {
|
||||
view.dispatchEvent(elementIndex, fullName, event);
|
||||
});
|
||||
}
|
||||
|
||||
_viewDehydrateRecurse(view) {
|
||||
// Note: preserve the opposite order of the hydration process.
|
||||
|
||||
// componentChildViews
|
||||
for (var i = 0; i < view.componentChildViews.length; i++) {
|
||||
var cv = view.componentChildViews[i];
|
||||
if (isPresent(cv)) {
|
||||
this._viewDehydrateRecurse(cv);
|
||||
if (view.proto.elementBinders[i].hasDynamicComponent()) {
|
||||
vcModule.ViewContainer.removeViewNodes(cv);
|
||||
view.lightDoms[i] = null;
|
||||
view.componentChildViews[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// viewContainers and content tags
|
||||
if (isPresent(view.viewContainers)) {
|
||||
for (var i = 0; i < view.viewContainers.length; i++) {
|
||||
var vc = view.viewContainers[i];
|
||||
if (isPresent(vc)) {
|
||||
this._viewContainerDehydrateRecurse(vc);
|
||||
}
|
||||
var ct = view.contentTags[i];
|
||||
if (isPresent(ct)) {
|
||||
ct.dehydrate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//remove global events
|
||||
for (var i = 0; i < view.eventHandlerRemovers.length; i++) {
|
||||
view.eventHandlerRemovers[i]();
|
||||
}
|
||||
|
||||
view.eventHandlerRemovers = null;
|
||||
view.setEventDispatcher(null);
|
||||
view.hydrated = false;
|
||||
}
|
||||
|
||||
_viewContainerHydrateRecurse(viewContainer, destLightDom: ldModule.LightDom, hostLightDom: ldModule.LightDom) {
|
||||
viewContainer.hydrated = true;
|
||||
viewContainer.hostLightDom = hostLightDom;
|
||||
viewContainer.lightDom = destLightDom;
|
||||
}
|
||||
|
||||
_viewContainerDehydrateRecurse(viewContainer) {
|
||||
for (var i=0; i<viewContainer.views.length; i++) {
|
||||
this._viewDehydrateRecurse(viewContainer.views[i]);
|
||||
}
|
||||
viewContainer.clear();
|
||||
|
||||
viewContainer.hostLightDom = null;
|
||||
viewContainer.lightDom = null;
|
||||
viewContainer.hydrated = false;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user