123 lines
4.9 KiB
TypeScript
123 lines
4.9 KiB
TypeScript
import {Injectable} from 'angular2/di';
|
|
|
|
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
|
import {BaseException, isPresent, isBlank} from 'angular2/src/facade/lang';
|
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
|
|
|
import {
|
|
ViewDefinition,
|
|
ProtoViewDto,
|
|
ViewType,
|
|
DirectiveMetadata,
|
|
RenderCompiler,
|
|
RenderProtoViewRef,
|
|
RenderProtoViewMergeMapping,
|
|
ViewEncapsulation
|
|
} from '../../api';
|
|
import {CompilePipeline} from './compile_pipeline';
|
|
import {ViewLoader, TemplateAndStyles} from 'angular2/src/render/dom/compiler/view_loader';
|
|
import {CompileStepFactory, DefaultStepFactory} from './compile_step_factory';
|
|
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
|
|
import {Parser} from 'angular2/src/change_detection/change_detection';
|
|
import * as pvm from '../view/proto_view_merger';
|
|
import {CssSelector} from './selector';
|
|
import {DOCUMENT_TOKEN, APP_ID_TOKEN} from '../dom_tokens';
|
|
import {Inject} from 'angular2/di';
|
|
import {SharedStylesHost} from '../view/shared_styles_host';
|
|
import {prependAll} from '../util';
|
|
import {TemplateCloner} from '../template_cloner';
|
|
|
|
/**
|
|
* The compiler loads and translates the html templates of components into
|
|
* nested ProtoViews. To decompose its functionality it uses
|
|
* the CompilePipeline and the CompileSteps.
|
|
*/
|
|
export class DomCompiler extends RenderCompiler {
|
|
constructor(private _schemaRegistry: ElementSchemaRegistry,
|
|
private _templateCloner: TemplateCloner, private _stepFactory: CompileStepFactory,
|
|
private _viewLoader: ViewLoader, private _sharedStylesHost: SharedStylesHost) {
|
|
super();
|
|
}
|
|
|
|
compile(view: ViewDefinition): Promise<ProtoViewDto> {
|
|
var tplPromise = this._viewLoader.load(view);
|
|
return PromiseWrapper.then(
|
|
tplPromise, (tplAndStyles: TemplateAndStyles) =>
|
|
this._compileView(view, tplAndStyles, ViewType.COMPONENT),
|
|
(e) => {
|
|
throw new BaseException(`Failed to load the template for "${view.componentId}" : ${e}`);
|
|
return null;
|
|
});
|
|
}
|
|
|
|
compileHost(directiveMetadata: DirectiveMetadata): Promise<ProtoViewDto> {
|
|
let hostViewDef = new ViewDefinition({
|
|
componentId: directiveMetadata.id,
|
|
templateAbsUrl: null, template: null,
|
|
styles: null,
|
|
styleAbsUrls: null,
|
|
directives: [directiveMetadata],
|
|
encapsulation: ViewEncapsulation.NONE
|
|
});
|
|
|
|
let selector = CssSelector.parse(directiveMetadata.selector)[0];
|
|
let hostTemplate = selector.getMatchingElementTemplate();
|
|
let templateAndStyles = new TemplateAndStyles(hostTemplate, []);
|
|
|
|
return this._compileView(hostViewDef, templateAndStyles, ViewType.HOST);
|
|
}
|
|
|
|
mergeProtoViewsRecursively(
|
|
protoViewRefs: List<RenderProtoViewRef | List<any>>): Promise<RenderProtoViewMergeMapping> {
|
|
return PromiseWrapper.resolve(
|
|
pvm.mergeProtoViewsRecursively(this._templateCloner, protoViewRefs));
|
|
}
|
|
|
|
_compileView(viewDef: ViewDefinition, templateAndStyles: TemplateAndStyles,
|
|
protoViewType: ViewType): Promise<ProtoViewDto> {
|
|
if (viewDef.encapsulation === ViewEncapsulation.EMULATED &&
|
|
templateAndStyles.styles.length === 0) {
|
|
viewDef = this._normalizeViewEncapsulationIfThereAreNoStyles(viewDef);
|
|
}
|
|
var pipeline = new CompilePipeline(this._stepFactory.createSteps(viewDef));
|
|
|
|
var compiledStyles = pipeline.processStyles(templateAndStyles.styles);
|
|
var compileElements = pipeline.processElements(DOM.createTemplate(templateAndStyles.template),
|
|
protoViewType, viewDef);
|
|
if (viewDef.encapsulation === ViewEncapsulation.NATIVE) {
|
|
prependAll(DOM.content(compileElements[0].element),
|
|
compiledStyles.map(style => DOM.createStyleElement(style)));
|
|
} else {
|
|
this._sharedStylesHost.addStyles(compiledStyles);
|
|
}
|
|
|
|
return PromiseWrapper.resolve(
|
|
compileElements[0].inheritedProtoView.build(this._schemaRegistry, this._templateCloner));
|
|
}
|
|
|
|
_normalizeViewEncapsulationIfThereAreNoStyles(viewDef: ViewDefinition): ViewDefinition {
|
|
if (viewDef.encapsulation === ViewEncapsulation.EMULATED) {
|
|
return new ViewDefinition({
|
|
componentId: viewDef.componentId,
|
|
templateAbsUrl: viewDef.templateAbsUrl, template: viewDef.template,
|
|
styleAbsUrls: viewDef.styleAbsUrls,
|
|
styles: viewDef.styles,
|
|
directives: viewDef.directives,
|
|
encapsulation: ViewEncapsulation.NONE
|
|
});
|
|
} else {
|
|
return viewDef;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Injectable()
|
|
export class DefaultDomCompiler extends DomCompiler {
|
|
constructor(schemaRegistry: ElementSchemaRegistry, templateCloner: TemplateCloner, parser: Parser,
|
|
viewLoader: ViewLoader, sharedStylesHost: SharedStylesHost,
|
|
@Inject(APP_ID_TOKEN) appId: any) {
|
|
super(schemaRegistry, templateCloner, new DefaultStepFactory(parser, appId), viewLoader,
|
|
sharedStylesHost);
|
|
}
|
|
}
|