Files
Angular-Docs-Cn/modules/upgrade/src/upgrade_module.ts
T

177 lines
6.0 KiB
TypeScript

///<reference path="../typings/angularjs/angular.d.ts"/>
import {
platform,
PlatformRef,
ApplicationRef,
ComponentRef,
bind,
Directive,
Component,
Inject,
View,
Type,
PlatformRef,
ApplicationRef,
ChangeDetectorRef,
AppViewManager,
NgZone,
Injector,
Compiler,
ProtoViewRef,
ElementRef,
HostViewRef,
ViewRef
} from 'angular2/angular2';
import {applicationDomBindings} from 'angular2/src/core/application_common';
import {applicationCommonBindings} from '../../angular2/src/core/application_ref';
import {compilerBindings} from 'angular2/src/core/compiler/compiler';
import {getComponentSelector} from './metadata';
import {onError} from './util';
export const INJECTOR = 'ng2.Injector';
export const APP_VIEW_MANAGER = 'ng2.AppViewManager';
export const NG2_COMPILER = 'ng2.Compiler';
export const NG2_ZONE = 'ng2.NgZone';
export const PROTO_VIEW_REF_MAP = 'ng2.ProtoViewRefMap';
const NG1_REQUIRE_INJECTOR_REF = '$' + INJECTOR + 'Controller';
const NG1_SCOPE = '$scope';
const NG1_COMPILE = '$compile';
const NG1_INJECTOR = '$injector';
const REQUIRE_INJECTOR = '^' + INJECTOR;
var moduleCount: number = 0;
const CAMEL_CASE = /([A-Z])/g;
export function createUpgradeModule(): UpgradeModule {
var prefix = `NG2_UPGRADE_m${moduleCount++}_`;
return new UpgradeModule(prefix, angular.module(prefix, []));
}
export class UpgradeModule {
componentTypes: Array<Type> = [];
constructor(public idPrefix: string, public ng1Module: angular.IModule) {}
importNg2Component(type: Type): UpgradeModule {
this.componentTypes.push(type);
var selector: string = getComponentSelector(type);
var factory: Function = ng1ComponentDirective(selector, type, `${this.idPrefix}${selector}_c`);
this.ng1Module.directive(selector, <any[]>factory);
return this;
}
exportAsNg2Component(name: string): Type {
return Directive({
selector: name.replace(CAMEL_CASE, (all, next: string) => '-' + next.toLowerCase())
})
.Class({
constructor: [
new Inject(NG1_COMPILE),
new Inject(NG1_SCOPE),
ElementRef,
function(compile: angular.ICompileService, scope: angular.IScope,
elementRef: ElementRef) { compile(elementRef.nativeElement)(scope); }
]
});
}
bootstrap(element: Element, modules?: any[],
config?: angular.IAngularBootstrapConfig): UpgradeRef {
var upgrade = new UpgradeRef();
var ng1Injector: angular.auto.IInjectorService = null;
var bindings = [
applicationCommonBindings(),
applicationDomBindings(),
compilerBindings(),
bind(NG1_INJECTOR).toFactory(() => ng1Injector),
bind(NG1_COMPILE).toFactory(() => ng1Injector.get(NG1_COMPILE))
];
var platformRef: PlatformRef = platform();
var applicationRef: ApplicationRef = platformRef.application(bindings);
var injector: Injector = applicationRef.injector;
var ngZone: NgZone = injector.get(NgZone);
var compiler: Compiler = injector.get(Compiler);
this.compileNg2Components(compiler).then((protoViewRefMap: ProtoViewRefMap) => {
ngZone.run(() => {
this.ng1Module.value(INJECTOR, injector)
.value(NG2_ZONE, ngZone)
.value(NG2_COMPILER, compiler)
.value(PROTO_VIEW_REF_MAP, protoViewRefMap)
.value(APP_VIEW_MANAGER, injector.get(AppViewManager))
.run([
'$injector',
'$rootScope',
(injector: angular.auto.IInjectorService, rootScope: angular.IRootScopeService) => {
ng1Injector = injector;
ngZone.overrideOnTurnDone(() => rootScope.$apply());
}
]);
modules = modules ? [].concat(modules) : [];
modules.push(this.idPrefix);
angular.element(element).data(NG1_REQUIRE_INJECTOR_REF, injector);
angular.bootstrap(element, modules, config);
upgrade.readyFn && upgrade.readyFn();
});
});
return upgrade;
}
private compileNg2Components(compiler: Compiler): Promise<ProtoViewRefMap> {
var promises: Array<Promise<ProtoViewRef>> = [];
var types = this.componentTypes;
for (var i = 0; i < types.length; i++) {
promises.push(compiler.compileInHost(types[i]));
}
return Promise.all(promises).then((protoViews: Array<ProtoViewRef>) => {
var protoViewRefMap: ProtoViewRefMap = {};
var types = this.componentTypes;
for (var i = 0; i < protoViews.length; i++) {
protoViewRefMap[getComponentSelector(types[i])] = protoViews[i];
}
return protoViewRefMap;
}, onError);
}
}
interface ProtoViewRefMap {
[selector: string]: ProtoViewRef
}
function ng1ComponentDirective(selector: string, type: Type, idPrefix: string): Function {
directiveFactory.$inject = [PROTO_VIEW_REF_MAP, APP_VIEW_MANAGER];
function directiveFactory(protoViewRefMap: ProtoViewRefMap, viewManager: AppViewManager):
angular.IDirective {
var protoView: ProtoViewRef = protoViewRefMap[selector];
if (!protoView) throw new Error('Expecting ProtoViewRef for: ' + selector);
var idCount = 0;
return {
restrict: 'E',
require: REQUIRE_INJECTOR,
link: (scope: angular.IScope, element: angular.IAugmentedJQuery, attrs: angular.IAttributes,
parentInjector: any, transclude: angular.ITranscludeFunction): void => {
var id = element[0].id = idPrefix + (idCount++);
var componentScope = scope.$new();
componentScope.$watch(() => changeDetector.detectChanges());
var childInjector =
parentInjector.resolveAndCreateChild([bind(NG1_SCOPE).toValue(componentScope)]);
var hostViewRef = viewManager.createRootHostView(protoView, '#' + id, childInjector);
var changeDetector: ChangeDetectorRef = hostViewRef.changeDetectorRef;
element.bind('$remove', () => viewManager.destroyRootHostView(hostViewRef));
}
};
}
return directiveFactory;
}
export class UpgradeRef {
readyFn: Function;
ready(fn: Function) { this.readyFn = fn; }
}