refactor(shadow_dom): remove ShadowDomStrategy in favor of @View(encapsulation)
BREAKING CHANGES: - `ShadowDomStrategy` was removed. To specify the encapsulation of a component use `@View(encapsulation: ViewEncapsulation.NONE | ViewEncapsulation.EMULATED | ViewEncapsulation.NATIVE)` - The default encapsulation strategy is now `ViewEncapsulation.EMULATED` if a component contains styles and `ViewEncapsulation.NONE` if it does not. Before this was always `NONE`. - `ViewLoader` now returns the template as a string and the styles as a separate array
This commit is contained in:
@@ -15,7 +15,7 @@ export {
|
||||
LifecycleEvent
|
||||
} from './src/core/annotations/annotations';
|
||||
|
||||
export {ViewAnnotation} from 'angular2/src/core/annotations/view';
|
||||
export {ViewAnnotation, ViewEncapsulation} from 'angular2/src/core/annotations/view';
|
||||
export {QueryAnnotation, AttributeAnnotation} from 'angular2/src/core/annotations/di';
|
||||
|
||||
export {
|
||||
|
||||
@@ -14,5 +14,6 @@ export {
|
||||
RenderViewWithFragments,
|
||||
DomRenderer,
|
||||
DOCUMENT_TOKEN,
|
||||
APP_ID_TOKEN,
|
||||
DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES
|
||||
} from './src/render/render';
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
Class
|
||||
} from '../../util/decorators';
|
||||
import {Type} from 'angular2/src/facade/lang';
|
||||
import {ViewEncapsulation} from 'angular2/src/render/api';
|
||||
|
||||
/**
|
||||
* Interface for the {@link Directive} decorator function.
|
||||
@@ -226,7 +227,7 @@ export interface ViewFactory {
|
||||
templateUrl?: string,
|
||||
template?: string,
|
||||
directives?: List<Type | any | List<any>>,
|
||||
renderer?: string,
|
||||
encapsulation?: ViewEncapsulation,
|
||||
styles?: List<string>,
|
||||
styleUrls?: List<string>,
|
||||
}): ViewDecorator;
|
||||
@@ -234,7 +235,7 @@ export interface ViewFactory {
|
||||
templateUrl?: string,
|
||||
template?: string,
|
||||
directives?: List<Type | any | List<any>>,
|
||||
renderer?: string,
|
||||
encapsulation?: ViewEncapsulation,
|
||||
styles?: List<string>,
|
||||
styleUrls?: List<string>,
|
||||
}): ViewAnnotation;
|
||||
|
||||
@@ -1 +1 @@
|
||||
export {View as ViewAnnotation} from '../annotations_impl/view';
|
||||
export {View as ViewAnnotation, ViewEncapsulation} from '../annotations_impl/view';
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import {ABSTRACT, CONST, Type} from 'angular2/src/facade/lang';
|
||||
import {ViewEncapsulation} from 'angular2/src/render/api';
|
||||
|
||||
export {ViewEncapsulation} from 'angular2/src/render/api';
|
||||
|
||||
/**
|
||||
* Declares the available HTML templates for an application.
|
||||
@@ -85,17 +88,17 @@ export class View {
|
||||
directives: List<Type | any | List<any>>;
|
||||
|
||||
/**
|
||||
* Specify a custom renderer for this View.
|
||||
* If this is set, neither `template`, `templateUrl`, `styles`, `styleUrls` nor `directives` are
|
||||
* used.
|
||||
* Specify how the template and the styles should be encapsulated.
|
||||
* The default is {@link ViewEncapsulation.EMULATED} if the view has styles,
|
||||
* otherwise {@link ViewEncapsulation.NONE}.
|
||||
*/
|
||||
renderer: string;
|
||||
encapsulation: ViewEncapsulation;
|
||||
|
||||
constructor({templateUrl, template, directives, renderer, styles, styleUrls}: {
|
||||
constructor({templateUrl, template, directives, encapsulation, styles, styleUrls}: {
|
||||
templateUrl?: string,
|
||||
template?: string,
|
||||
directives?: List<Type | any | List<any>>,
|
||||
renderer?: string,
|
||||
encapsulation?: ViewEncapsulation,
|
||||
styles?: List<string>,
|
||||
styleUrls?: List<string>,
|
||||
} = {}) {
|
||||
@@ -104,6 +107,6 @@ export class View {
|
||||
this.styleUrls = styleUrls;
|
||||
this.styles = styles;
|
||||
this.directives = directives;
|
||||
this.renderer = renderer;
|
||||
this.encapsulation = encapsulation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,6 @@ import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {Promise, PromiseWrapper, PromiseCompleter} from 'angular2/src/facade/async';
|
||||
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
||||
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
||||
import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
|
||||
import {
|
||||
EmulatedUnscopedShadowDomStrategy
|
||||
} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
|
||||
import {XHR} from 'angular2/src/render/xhr';
|
||||
import {XHRImpl} from 'angular2/src/render/xhr_impl';
|
||||
import {EventManager, DomEventsPlugin} from 'angular2/src/render/dom/events/event_manager';
|
||||
@@ -61,9 +57,14 @@ import {Renderer, RenderCompiler} from 'angular2/src/render/api';
|
||||
import {
|
||||
DomRenderer,
|
||||
DOCUMENT_TOKEN,
|
||||
DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES
|
||||
} from 'angular2/src/render/dom/dom_renderer';
|
||||
import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler';
|
||||
DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES,
|
||||
DefaultDomCompiler,
|
||||
APP_ID_RANDOM_BINDING
|
||||
} from 'angular2/src/render/render';
|
||||
import {
|
||||
SharedStylesHost,
|
||||
DomSharedStylesHost
|
||||
} from 'angular2/src/render/dom/view/shared_styles_host';
|
||||
import {internalView} from 'angular2/src/core/compiler/view_ref';
|
||||
import {appComponentRefPromiseToken, appComponentTypeToken} from './application_tokens';
|
||||
|
||||
@@ -108,12 +109,13 @@ function _injectorBindings(appComponentType): List<Type | Binding | List<any>> {
|
||||
return new EventManager(plugins, ngZone);
|
||||
},
|
||||
[NgZone]),
|
||||
bind(ShadowDomStrategy)
|
||||
.toFactory((doc) => new EmulatedUnscopedShadowDomStrategy(doc.head), [DOCUMENT_TOKEN]),
|
||||
DomRenderer,
|
||||
DefaultDomCompiler,
|
||||
bind(Renderer).toAlias(DomRenderer),
|
||||
APP_ID_RANDOM_BINDING,
|
||||
DefaultDomCompiler,
|
||||
bind(RenderCompiler).toAlias(DefaultDomCompiler),
|
||||
DomSharedStylesHost,
|
||||
bind(SharedStylesHost).toAlias(DomSharedStylesHost),
|
||||
ProtoViewFactory,
|
||||
AppViewPool,
|
||||
bind(APP_VIEW_POOL_CAPACITY).toValue(10000),
|
||||
|
||||
@@ -307,7 +307,8 @@ export class Compiler {
|
||||
templateAbsUrl: templateAbsUrl, template: view.template,
|
||||
styleAbsUrls: styleAbsUrls,
|
||||
styles: view.styles,
|
||||
directives: ListWrapper.map(directives, directiveBinding => directiveBinding.metadata)
|
||||
directives: ListWrapper.map(directives, directiveBinding => directiveBinding.metadata),
|
||||
encapsulation: view.encapsulation
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -317,10 +317,10 @@ class Html5LibDomAdapter implements DomAdapter {
|
||||
throw 'not implemented';
|
||||
}
|
||||
bool supportsDOMEvents() {
|
||||
throw 'not implemented';
|
||||
return false;
|
||||
}
|
||||
bool supportsNativeShadowDOM() {
|
||||
throw 'not implemented';
|
||||
return false;
|
||||
}
|
||||
getHistory() {
|
||||
throw 'not implemented';
|
||||
|
||||
@@ -212,4 +212,7 @@ void iterateListLike(iter, fn(item)) {
|
||||
class SetWrapper {
|
||||
static Set createFromList(List l) => new Set.from(l);
|
||||
static bool has(Set s, key) => s.contains(key);
|
||||
static void delete(Set m, k) {
|
||||
m.remove(k);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,4 +290,5 @@ var createSetFromList: {(lst: List<any>): Set<any>} = (function() {
|
||||
export class SetWrapper {
|
||||
static createFromList<T>(lst: List<T>): Set<T> { return createSetFromList(lst); }
|
||||
static has<T>(s: Set<T>, key: T): boolean { return s.has(key); }
|
||||
static delete<K>(m: Set<K>, k: K) { m.delete(k); }
|
||||
}
|
||||
|
||||
@@ -273,6 +273,25 @@ export class RenderFragmentRef {}
|
||||
// An opaque reference to a view
|
||||
export class RenderViewRef {}
|
||||
|
||||
/**
|
||||
* How the template and styles of a view should be encapsulated.
|
||||
*/
|
||||
export enum ViewEncapsulation {
|
||||
/**
|
||||
* Emulate scoping of styles by preprocessing the style rules
|
||||
* and adding additional attributes to elements. This is the default.
|
||||
*/
|
||||
EMULATED,
|
||||
/**
|
||||
* Uses the native mechanism of the renderer. For the DOM this means creating a ShadowRoot.
|
||||
*/
|
||||
NATIVE,
|
||||
/**
|
||||
* Don't scope the template nor the styles.
|
||||
*/
|
||||
NONE
|
||||
}
|
||||
|
||||
export class ViewDefinition {
|
||||
componentId: string;
|
||||
templateAbsUrl: string;
|
||||
@@ -280,21 +299,25 @@ export class ViewDefinition {
|
||||
directives: List<DirectiveMetadata>;
|
||||
styleAbsUrls: List<string>;
|
||||
styles: List<string>;
|
||||
encapsulation: ViewEncapsulation;
|
||||
|
||||
constructor({componentId, templateAbsUrl, template, styleAbsUrls, styles, directives}: {
|
||||
constructor({componentId, templateAbsUrl, template, styleAbsUrls, styles, directives,
|
||||
encapsulation}: {
|
||||
componentId?: string,
|
||||
templateAbsUrl?: string,
|
||||
template?: string,
|
||||
styleAbsUrls?: List<string>,
|
||||
styles?: List<string>,
|
||||
directives?: List<DirectiveMetadata>
|
||||
}) {
|
||||
directives?: List<DirectiveMetadata>,
|
||||
encapsulation?: ViewEncapsulation
|
||||
} = {}) {
|
||||
this.componentId = componentId;
|
||||
this.templateAbsUrl = templateAbsUrl;
|
||||
this.template = template;
|
||||
this.styleAbsUrls = styleAbsUrls;
|
||||
this.styles = styles;
|
||||
this.directives = directives;
|
||||
this.encapsulation = isPresent(encapsulation) ? encapsulation : ViewEncapsulation.EMULATED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export class CompileControl {
|
||||
var step = this._steps[i];
|
||||
this._parent = parent;
|
||||
this._currentStepIndex = i;
|
||||
step.process(parent, current, this);
|
||||
step.processElement(parent, current, this);
|
||||
parent = this._parent;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import {CompileElement} from './compile_element';
|
||||
import {CompileControl} from './compile_control';
|
||||
import {CompileStep} from './compile_step';
|
||||
import {ProtoViewBuilder} from '../view/proto_view_builder';
|
||||
import {ProtoViewDto, ViewType} from '../../api';
|
||||
import {ProtoViewDto, ViewType, ViewDefinition} from '../../api';
|
||||
|
||||
/**
|
||||
* CompilePipeline for executing CompileSteps recursively for
|
||||
@@ -13,26 +13,29 @@ import {ProtoViewDto, ViewType} from '../../api';
|
||||
*/
|
||||
export class CompilePipeline {
|
||||
_control: CompileControl;
|
||||
constructor(steps: List<CompileStep>, private _useNativeShadowDom: boolean = false) {
|
||||
this._control = new CompileControl(steps);
|
||||
constructor(public steps: List<CompileStep>) { this._control = new CompileControl(steps); }
|
||||
|
||||
processStyles(styles: string[]): string[] {
|
||||
return styles.map(style => {
|
||||
this.steps.forEach(step => { style = step.processStyle(style); });
|
||||
return style;
|
||||
});
|
||||
}
|
||||
|
||||
process(rootElement: HTMLElement, protoViewType: ViewType = null,
|
||||
compilationCtxtDescription: string = ''): List<CompileElement> {
|
||||
if (isBlank(protoViewType)) {
|
||||
protoViewType = ViewType.COMPONENT;
|
||||
}
|
||||
var results = [];
|
||||
processElements(rootElement: Element, protoViewType: ViewType,
|
||||
viewDef: ViewDefinition): CompileElement[] {
|
||||
var results: CompileElement[] = [];
|
||||
var compilationCtxtDescription = viewDef.componentId;
|
||||
var rootCompileElement = new CompileElement(rootElement, compilationCtxtDescription);
|
||||
rootCompileElement.inheritedProtoView =
|
||||
new ProtoViewBuilder(rootElement, protoViewType, this._useNativeShadowDom);
|
||||
new ProtoViewBuilder(rootElement, protoViewType, viewDef.encapsulation);
|
||||
rootCompileElement.isViewRoot = true;
|
||||
this._process(results, null, rootCompileElement, compilationCtxtDescription);
|
||||
this._processElement(results, null, rootCompileElement, compilationCtxtDescription);
|
||||
return results;
|
||||
}
|
||||
|
||||
_process(results, parent: CompileElement, current: CompileElement,
|
||||
compilationCtxtDescription: string = '') {
|
||||
_processElement(results: CompileElement[], parent: CompileElement, current: CompileElement,
|
||||
compilationCtxtDescription: string = '') {
|
||||
var additionalChildren = this._control.internalProcess(results, 0, parent, current);
|
||||
|
||||
if (current.compileChildren) {
|
||||
@@ -46,7 +49,7 @@ export class CompilePipeline {
|
||||
childCompileElement.inheritedProtoView = current.inheritedProtoView;
|
||||
childCompileElement.inheritedElementBinder = current.inheritedElementBinder;
|
||||
childCompileElement.distanceToInheritedBinder = current.distanceToInheritedBinder + 1;
|
||||
this._process(results, current, childCompileElement);
|
||||
this._processElement(results, current, childCompileElement);
|
||||
}
|
||||
node = nextNode;
|
||||
}
|
||||
@@ -54,7 +57,7 @@ export class CompilePipeline {
|
||||
|
||||
if (isPresent(additionalChildren)) {
|
||||
for (var i = 0; i < additionalChildren.length; i++) {
|
||||
this._process(results, current, additionalChildren[i]);
|
||||
this._processElement(results, current, additionalChildren[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import * as compileControlModule from './compile_control';
|
||||
* Is guaranteed to be called in depth first order
|
||||
*/
|
||||
export interface CompileStep {
|
||||
process(parent: CompileElement, current: CompileElement,
|
||||
control: compileControlModule.CompileControl): void;
|
||||
processElement(parent: CompileElement, current: CompileElement,
|
||||
control: compileControlModule.CompileControl): void;
|
||||
|
||||
processStyle(style: string): string;
|
||||
}
|
||||
|
||||
@@ -6,15 +6,15 @@ import {PropertyBindingParser} from './property_binding_parser';
|
||||
import {TextInterpolationParser} from './text_interpolation_parser';
|
||||
import {DirectiveParser} from './directive_parser';
|
||||
import {ViewSplitter} from './view_splitter';
|
||||
import {ShadowDomCompileStep} from '../shadow_dom/shadow_dom_compile_step';
|
||||
import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy';
|
||||
import {StyleEncapsulator} from './style_encapsulator';
|
||||
|
||||
export class CompileStepFactory {
|
||||
createSteps(view: ViewDefinition): List<CompileStep> { return null; }
|
||||
}
|
||||
|
||||
export class DefaultStepFactory extends CompileStepFactory {
|
||||
constructor(public _parser: Parser, public _shadowDomStrategy: ShadowDomStrategy) { super(); }
|
||||
private _componentUIDsCache: Map<string, string> = new Map();
|
||||
constructor(private _parser: Parser, private _appId: string) { super(); }
|
||||
|
||||
createSteps(view: ViewDefinition): List<CompileStep> {
|
||||
return [
|
||||
@@ -22,7 +22,7 @@ export class DefaultStepFactory extends CompileStepFactory {
|
||||
new PropertyBindingParser(this._parser),
|
||||
new DirectiveParser(this._parser, view.directives),
|
||||
new TextInterpolationParser(this._parser),
|
||||
new ShadowDomCompileStep(this._shadowDomStrategy, view)
|
||||
new StyleEncapsulator(this._appId, view, this._componentUIDsCache)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {Injectable} from 'angular2/di';
|
||||
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
import {BaseException, isPresent} from 'angular2/src/facade/lang';
|
||||
import {BaseException, isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
|
||||
import {
|
||||
@@ -11,14 +11,18 @@ import {
|
||||
DirectiveMetadata,
|
||||
RenderCompiler,
|
||||
RenderProtoViewRef,
|
||||
RenderProtoViewMergeMapping
|
||||
RenderProtoViewMergeMapping,
|
||||
ViewEncapsulation
|
||||
} from '../../api';
|
||||
import {CompilePipeline} from './compile_pipeline';
|
||||
import {ViewLoader} from 'angular2/src/render/dom/compiler/view_loader';
|
||||
import {ViewLoader, TemplateAndStyles} from 'angular2/src/render/dom/compiler/view_loader';
|
||||
import {CompileStepFactory, DefaultStepFactory} from './compile_step_factory';
|
||||
import {Parser} from 'angular2/src/change_detection/change_detection';
|
||||
import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy';
|
||||
import * as pvm from '../view/proto_view_merger';
|
||||
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';
|
||||
|
||||
/**
|
||||
* The compiler loads and translates the html templates of components into
|
||||
@@ -26,15 +30,17 @@ import * as pvm from '../view/proto_view_merger';
|
||||
* the CompilePipeline and the CompileSteps.
|
||||
*/
|
||||
export class DomCompiler extends RenderCompiler {
|
||||
constructor(public _stepFactory: CompileStepFactory, public _viewLoader: ViewLoader,
|
||||
public _useNativeShadowDom: boolean) {
|
||||
constructor(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, (el) => this._compileTemplate(view, el, ViewType.COMPONENT), (e) => {
|
||||
tplPromise, (tplAndStyles: TemplateAndStyles) =>
|
||||
this._compileView(view, tplAndStyles, ViewType.COMPONENT),
|
||||
(e) => {
|
||||
throw new BaseException(`Failed to load the template for "${view.componentId}" : ${e}`);
|
||||
return null;
|
||||
});
|
||||
@@ -46,11 +52,13 @@ export class DomCompiler extends RenderCompiler {
|
||||
templateAbsUrl: null, template: null,
|
||||
styles: null,
|
||||
styleAbsUrls: null,
|
||||
directives: [directiveMetadata]
|
||||
directives: [directiveMetadata],
|
||||
encapsulation: ViewEncapsulation.NONE
|
||||
});
|
||||
var template = DOM.createTemplate('');
|
||||
DOM.appendChild(DOM.content(template), DOM.createElement(directiveMetadata.selector));
|
||||
return this._compileTemplate(hostViewDef, template, ViewType.HOST);
|
||||
return this._compileView(
|
||||
hostViewDef, new TemplateAndStyles(
|
||||
`<${directiveMetadata.selector}></${directiveMetadata.selector}>`, []),
|
||||
ViewType.HOST);
|
||||
}
|
||||
|
||||
mergeProtoViewsRecursively(
|
||||
@@ -58,20 +66,47 @@ export class DomCompiler extends RenderCompiler {
|
||||
return PromiseWrapper.resolve(pvm.mergeProtoViewsRecursively(protoViewRefs));
|
||||
}
|
||||
|
||||
_compileTemplate(viewDef: ViewDefinition, tplElement,
|
||||
protoViewType: ViewType): Promise<ProtoViewDto> {
|
||||
var pipeline =
|
||||
new CompilePipeline(this._stepFactory.createSteps(viewDef), this._useNativeShadowDom);
|
||||
var compileElements = pipeline.process(tplElement, protoViewType, viewDef.componentId);
|
||||
_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());
|
||||
}
|
||||
|
||||
_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(parser: Parser, shadowDomStrategy: ShadowDomStrategy, viewLoader: ViewLoader) {
|
||||
super(new DefaultStepFactory(parser, shadowDomStrategy), viewLoader,
|
||||
shadowDomStrategy.hasNativeContentElement());
|
||||
constructor(parser: Parser, viewLoader: ViewLoader, sharedStylesHost: SharedStylesHost,
|
||||
@Inject(APP_ID_TOKEN) appId: any) {
|
||||
super(new DefaultStepFactory(parser, appId), viewLoader, sharedStylesHost);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ export class DirectiveParser implements CompileStep {
|
||||
}
|
||||
}
|
||||
|
||||
processStyle(style: string): string { return style; }
|
||||
|
||||
_ensureComponentOnlyHasElementSelector(selector, directive) {
|
||||
var isElementSelector = selector.length === 1 && selector[0].isElementSelector();
|
||||
if (!isElementSelector && directive.type === DirectiveMetadata.COMPONENT_TYPE) {
|
||||
@@ -37,7 +39,7 @@ export class DirectiveParser implements CompileStep {
|
||||
}
|
||||
}
|
||||
|
||||
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
processElement(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
var attrs = current.attrs();
|
||||
var classList = current.classList();
|
||||
var cssSelector = new CssSelector();
|
||||
|
||||
@@ -25,7 +25,9 @@ var BIND_NAME_REGEXP =
|
||||
export class PropertyBindingParser implements CompileStep {
|
||||
constructor(private _parser: Parser) {}
|
||||
|
||||
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
processStyle(style: string): string { return style; }
|
||||
|
||||
processElement(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
var attrs = current.attrs();
|
||||
var newAttrs = new Map();
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import {CompileStep} from '../compiler/compile_step';
|
||||
import {CompileElement} from '../compiler/compile_element';
|
||||
import {CompileControl} from '../compiler/compile_control';
|
||||
import {ViewDefinition, ViewEncapsulation, ViewType} from '../../api';
|
||||
import {NG_CONTENT_ELEMENT_NAME, isElementWithTag} from '../util';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {isBlank, isPresent} from 'angular2/src/facade/lang';
|
||||
import {ShadowCss} from './shadow_css';
|
||||
|
||||
export class StyleEncapsulator implements CompileStep {
|
||||
constructor(private _appId: string, private _view: ViewDefinition,
|
||||
private _componentUIDsCache: Map<string, string>) {}
|
||||
|
||||
processElement(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
if (isElementWithTag(current.element, NG_CONTENT_ELEMENT_NAME)) {
|
||||
current.inheritedProtoView.bindNgContent();
|
||||
} else {
|
||||
if (this._view.encapsulation === ViewEncapsulation.EMULATED) {
|
||||
this._processEmulatedScopedElement(current, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processStyle(style: string): string {
|
||||
var encapsulation = this._view.encapsulation;
|
||||
if (encapsulation === ViewEncapsulation.EMULATED) {
|
||||
return this._shimCssForComponent(style, this._view.componentId);
|
||||
} else {
|
||||
return style;
|
||||
}
|
||||
}
|
||||
|
||||
_processEmulatedScopedElement(current: CompileElement, parent: CompileElement): void {
|
||||
var element = current.element;
|
||||
var hostComponentId = this._view.componentId;
|
||||
var viewType = current.inheritedProtoView.type;
|
||||
// Shim the element as a child of the compiled component
|
||||
if (viewType !== ViewType.HOST && isPresent(hostComponentId)) {
|
||||
var contentAttribute = getContentAttribute(this._getComponentId(hostComponentId));
|
||||
DOM.setAttribute(element, contentAttribute, '');
|
||||
// also shim the host
|
||||
if (isBlank(parent) && viewType == ViewType.COMPONENT) {
|
||||
var hostAttribute = getHostAttribute(this._getComponentId(hostComponentId));
|
||||
current.inheritedProtoView.setHostAttribute(hostAttribute, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_shimCssForComponent(cssText: string, componentId: string): string {
|
||||
var id = this._getComponentId(componentId);
|
||||
var shadowCss = new ShadowCss();
|
||||
return shadowCss.shimCssText(cssText, getContentAttribute(id), getHostAttribute(id));
|
||||
}
|
||||
|
||||
_getComponentId(componentStringId: string): string {
|
||||
var id = this._componentUIDsCache.get(componentStringId);
|
||||
if (isBlank(id)) {
|
||||
id = `${this._appId}-${this._componentUIDsCache.size}`;
|
||||
this._componentUIDsCache.set(componentStringId, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the attribute to be added to the component
|
||||
function getHostAttribute(compId: string): string {
|
||||
return `_nghost-${compId}`;
|
||||
}
|
||||
|
||||
// Returns the attribute to be added on every single element nodes in the component
|
||||
function getContentAttribute(compId: string): string {
|
||||
return `_ngcontent-${compId}`;
|
||||
}
|
||||
@@ -13,7 +13,9 @@ import {CompileControl} from './compile_control';
|
||||
export class TextInterpolationParser implements CompileStep {
|
||||
constructor(public _parser: Parser) {}
|
||||
|
||||
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
processStyle(style: string): string { return style; }
|
||||
|
||||
processElement(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
if (!current.compileChildren) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -10,14 +10,17 @@ import {
|
||||
import {Map, MapWrapper, ListWrapper, List} from 'angular2/src/facade/collection';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {ViewDefinition} from '../../api';
|
||||
|
||||
import {XHR} from 'angular2/src/render/xhr';
|
||||
|
||||
import {ViewDefinition} from '../../api';
|
||||
|
||||
import {StyleInliner} from './style_inliner';
|
||||
import {StyleUrlResolver} from './style_url_resolver';
|
||||
|
||||
export class TemplateAndStyles {
|
||||
constructor(public template: string, public styles: string[]) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy to load component views.
|
||||
* TODO: Make public API once we are more confident in this approach.
|
||||
@@ -29,33 +32,32 @@ export class ViewLoader {
|
||||
constructor(private _xhr: XHR, private _styleInliner: StyleInliner,
|
||||
private _styleUrlResolver: StyleUrlResolver) {}
|
||||
|
||||
load(view: ViewDefinition): Promise</*element*/ any> {
|
||||
let tplElAndStyles: List<string | Promise<string>> = [this._loadHtml(view)];
|
||||
|
||||
if (isPresent(view.styles)) {
|
||||
view.styles.forEach((cssText: string) => {
|
||||
let textOrPromise = this._resolveAndInlineCssText(cssText, view.templateAbsUrl);
|
||||
tplElAndStyles.push(textOrPromise);
|
||||
load(viewDef: ViewDefinition): Promise<TemplateAndStyles> {
|
||||
let tplAndStyles: List<Promise<TemplateAndStyles>| Promise<string>| string> =
|
||||
[this._loadHtml(viewDef.template, viewDef.templateAbsUrl)];
|
||||
if (isPresent(viewDef.styles)) {
|
||||
viewDef.styles.forEach((cssText: string) => {
|
||||
let textOrPromise = this._resolveAndInlineCssText(cssText, viewDef.templateAbsUrl);
|
||||
tplAndStyles.push(textOrPromise);
|
||||
});
|
||||
}
|
||||
|
||||
if (isPresent(view.styleAbsUrls)) {
|
||||
view.styleAbsUrls.forEach(url => {
|
||||
if (isPresent(viewDef.styleAbsUrls)) {
|
||||
viewDef.styleAbsUrls.forEach(url => {
|
||||
let promise = this._loadText(url).then(
|
||||
cssText => this._resolveAndInlineCssText(cssText, view.templateAbsUrl));
|
||||
tplElAndStyles.push(promise);
|
||||
cssText => this._resolveAndInlineCssText(cssText, viewDef.templateAbsUrl));
|
||||
tplAndStyles.push(promise);
|
||||
});
|
||||
}
|
||||
|
||||
// Inline the styles from the @View annotation and return a template element
|
||||
return PromiseWrapper.all(tplElAndStyles)
|
||||
.then((res: List<string>) => {
|
||||
let tplEl = res[0];
|
||||
let cssTexts = ListWrapper.slice(res, 1);
|
||||
// Inline the styles from the @View annotation
|
||||
return PromiseWrapper.all(tplAndStyles)
|
||||
.then((res: List<TemplateAndStyles | string>) => {
|
||||
let loadedTplAndStyles = <TemplateAndStyles>res[0];
|
||||
let styles = <string[]>ListWrapper.slice(res, 1);
|
||||
|
||||
_insertCssTexts(DOM.content(tplEl), cssTexts);
|
||||
|
||||
return tplEl;
|
||||
return new TemplateAndStyles(loadedTplAndStyles.template,
|
||||
loadedTplAndStyles.styles.concat(styles));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -77,40 +79,54 @@ export class ViewLoader {
|
||||
}
|
||||
|
||||
// Load the html and inline any style tags
|
||||
private _loadHtml(view: ViewDefinition): Promise<any /* element */> {
|
||||
private _loadHtml(template: string, templateAbsUrl: string): Promise<TemplateAndStyles> {
|
||||
let html;
|
||||
|
||||
// Load the HTML
|
||||
if (isPresent(view.template)) {
|
||||
html = PromiseWrapper.resolve(view.template);
|
||||
} else if (isPresent(view.templateAbsUrl)) {
|
||||
html = this._loadText(view.templateAbsUrl);
|
||||
if (isPresent(template)) {
|
||||
html = PromiseWrapper.resolve(template);
|
||||
} else if (isPresent(templateAbsUrl)) {
|
||||
html = this._loadText(templateAbsUrl);
|
||||
} else {
|
||||
throw new BaseException('View should have either the templateUrl or template property set');
|
||||
}
|
||||
|
||||
return html.then(html => {
|
||||
var tplEl = DOM.createTemplate(html);
|
||||
|
||||
// Replace $baseUrl with the base url for the template
|
||||
let templateAbsUrl = view.templateAbsUrl;
|
||||
if (isPresent(templateAbsUrl) && templateAbsUrl.indexOf("/") >= 0) {
|
||||
let baseUrl = templateAbsUrl.substring(0, templateAbsUrl.lastIndexOf("/"));
|
||||
this._substituteBaseUrl(DOM.content(tplEl), baseUrl);
|
||||
}
|
||||
let styleEls = DOM.querySelectorAll(DOM.content(tplEl), 'STYLE');
|
||||
let unresolvedStyles: string[] = [];
|
||||
for (let i = 0; i < styleEls.length; i++) {
|
||||
var styleEl = styleEls[i];
|
||||
unresolvedStyles.push(DOM.getText(styleEl));
|
||||
DOM.remove(styleEl);
|
||||
}
|
||||
|
||||
let syncStyles: string[] = [];
|
||||
let asyncStyles: Promise<string>[] = [];
|
||||
|
||||
// Inline the style tags from the html
|
||||
let styleEls = DOM.querySelectorAll(DOM.content(tplEl), 'STYLE');
|
||||
|
||||
let promises: List<Promise<string>> = [];
|
||||
for (let i = 0; i < styleEls.length; i++) {
|
||||
let promise = this._resolveAndInlineElement(styleEls[i], view.templateAbsUrl);
|
||||
if (isPromise(promise)) {
|
||||
promises.push(promise);
|
||||
let styleEl = styleEls[i];
|
||||
let resolvedStyled = this._resolveAndInlineCssText(DOM.getText(styleEl), templateAbsUrl);
|
||||
if (isPromise(resolvedStyled)) {
|
||||
asyncStyles.push(<Promise<string>>resolvedStyled);
|
||||
} else {
|
||||
syncStyles.push(<string>resolvedStyled);
|
||||
}
|
||||
}
|
||||
|
||||
return promises.length > 0 ? PromiseWrapper.all(promises).then(_ => tplEl) : tplEl;
|
||||
if (asyncStyles.length === 0) {
|
||||
return PromiseWrapper.resolve(new TemplateAndStyles(DOM.getInnerHTML(tplEl), syncStyles));
|
||||
} else {
|
||||
return PromiseWrapper.all(asyncStyles)
|
||||
.then(loadedStyles => new TemplateAndStyles(DOM.getInnerHTML(tplEl),
|
||||
syncStyles.concat(<string[]>loadedStyles)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -139,43 +155,8 @@ export class ViewLoader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlines a style element.
|
||||
*
|
||||
* @param styleEl The style element
|
||||
* @param baseUrl The base url
|
||||
* @returns {Promise<any>} null when no @import rule exist in the css or a Promise
|
||||
* @private
|
||||
*/
|
||||
private _resolveAndInlineElement(styleEl, baseUrl: string): Promise<any> {
|
||||
let textOrPromise = this._resolveAndInlineCssText(DOM.getText(styleEl), baseUrl);
|
||||
|
||||
if (isPromise(textOrPromise)) {
|
||||
return (<Promise<string>>textOrPromise).then(css => { DOM.setText(styleEl, css); });
|
||||
} else {
|
||||
DOM.setText(styleEl, <string>textOrPromise);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private _resolveAndInlineCssText(cssText: string, baseUrl: string): string | Promise<string> {
|
||||
cssText = this._styleUrlResolver.resolveUrls(cssText, baseUrl);
|
||||
return this._styleInliner.inlineImports(cssText, baseUrl);
|
||||
}
|
||||
}
|
||||
|
||||
function _insertCssTexts(element, cssTexts: List<string>): void {
|
||||
if (cssTexts.length == 0) return;
|
||||
|
||||
let insertBefore = DOM.firstChild(element);
|
||||
|
||||
for (let i = cssTexts.length - 1; i >= 0; i--) {
|
||||
let styleEl = DOM.createStyleElement(cssTexts[i]);
|
||||
if (isPresent(insertBefore)) {
|
||||
DOM.insertBefore(insertBefore, styleEl);
|
||||
} else {
|
||||
DOM.appendChild(element, styleEl);
|
||||
}
|
||||
insertBefore = styleEl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@ import {dashCaseToCamelCase} from '../util';
|
||||
export class ViewSplitter implements CompileStep {
|
||||
constructor(public _parser: Parser) {}
|
||||
|
||||
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
processStyle(style: string): string { return style; }
|
||||
|
||||
processElement(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
var attrs = current.attrs();
|
||||
var templateBindings = attrs.get('template');
|
||||
var hasTemplateBinding = isPresent(templateBindings);
|
||||
|
||||
@@ -15,6 +15,7 @@ import {EventManager} from './events/event_manager';
|
||||
import {DomProtoView, DomProtoViewRef, resolveInternalDomProtoView} from './view/proto_view';
|
||||
import {DomView, DomViewRef, resolveInternalDomView} from './view/view';
|
||||
import {DomFragmentRef, resolveInternalDomFragment} from './view/fragment';
|
||||
import {DomSharedStylesHost} from './view/shared_styles_host';
|
||||
import {
|
||||
NG_BINDING_CLASS_SELECTOR,
|
||||
NG_BINDING_CLASS,
|
||||
@@ -31,9 +32,8 @@ import {
|
||||
RenderViewWithFragments
|
||||
} from '../api';
|
||||
|
||||
export const DOCUMENT_TOKEN: OpaqueToken = CONST_EXPR(new OpaqueToken('DocumentToken'));
|
||||
export const DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES: OpaqueToken =
|
||||
CONST_EXPR(new OpaqueToken('DomReflectPropertiesAsAttributes'));
|
||||
import {DOCUMENT_TOKEN, DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES} from './dom_tokens';
|
||||
|
||||
const REFLECT_PREFIX: string = 'ng-reflect-';
|
||||
|
||||
@Injectable()
|
||||
@@ -41,7 +41,8 @@ export class DomRenderer extends Renderer {
|
||||
_document;
|
||||
_reflectPropertiesAsAttributes: boolean;
|
||||
|
||||
constructor(public _eventManager: EventManager, @Inject(DOCUMENT_TOKEN) document,
|
||||
constructor(public _eventManager: EventManager, private _domSharedStylesHost: DomSharedStylesHost,
|
||||
@Inject(DOCUMENT_TOKEN) document,
|
||||
@Inject(DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES) reflectPropertiesAsAttributes:
|
||||
boolean) {
|
||||
super();
|
||||
@@ -65,7 +66,14 @@ export class DomRenderer extends Renderer {
|
||||
}
|
||||
|
||||
destroyView(viewRef: RenderViewRef) {
|
||||
// noop for now
|
||||
var view = resolveInternalDomView(viewRef);
|
||||
var elementBinders = view.proto.elementBinders;
|
||||
for (var i = 0; i < elementBinders.length; i++) {
|
||||
var binder = elementBinders[i];
|
||||
if (binder.hasNativeShadowRoot) {
|
||||
this._domSharedStylesHost.removeHost(DOM.getShadowRoot(view.boundElements[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getNativeElementSync(location: RenderElementRef): any {
|
||||
@@ -226,7 +234,9 @@ export class DomRenderer extends Renderer {
|
||||
// native shadow DOM
|
||||
if (binder.hasNativeShadowRoot) {
|
||||
var shadowRootWrapper = DOM.firstChild(element);
|
||||
moveChildNodes(shadowRootWrapper, DOM.createShadowRoot(element));
|
||||
var shadowRoot = DOM.createShadowRoot(element);
|
||||
this._domSharedStylesHost.addHost(shadowRoot);
|
||||
moveChildNodes(shadowRootWrapper, shadowRoot);
|
||||
DOM.remove(shadowRootWrapper);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import {OpaqueToken, bind, Binding} from 'angular2/di';
|
||||
import {CONST_EXPR, StringWrapper, Math} from 'angular2/src/facade/lang';
|
||||
|
||||
export const DOCUMENT_TOKEN: OpaqueToken = CONST_EXPR(new OpaqueToken('DocumentToken'));
|
||||
|
||||
export const DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES: OpaqueToken =
|
||||
CONST_EXPR(new OpaqueToken('DomReflectPropertiesAsAttributes'));
|
||||
|
||||
|
||||
/**
|
||||
* A unique id (string) for an angular application.
|
||||
*/
|
||||
export const APP_ID_TOKEN: OpaqueToken = CONST_EXPR(new OpaqueToken('AppId'));
|
||||
|
||||
/**
|
||||
* Bindings that will generate a random APP_ID_TOKEN.
|
||||
*/
|
||||
export var APP_ID_RANDOM_BINDING: Binding =
|
||||
bind(APP_ID_TOKEN).toFactory(() => `${randomChar()}${randomChar()}${randomChar()}`, []);
|
||||
|
||||
|
||||
function randomChar(): string {
|
||||
return StringWrapper.fromCharCode(97 + Math.floor(Math.random() * 25));
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
import {isBlank, isPresent} from 'angular2/src/facade/lang';
|
||||
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
|
||||
import {EmulatedUnscopedShadowDomStrategy} from './emulated_unscoped_shadow_dom_strategy';
|
||||
import {
|
||||
getContentAttribute,
|
||||
getHostAttribute,
|
||||
getComponentId,
|
||||
shimCssForComponent,
|
||||
insertStyleElement
|
||||
} from './util';
|
||||
|
||||
/**
|
||||
* This strategy emulates the Shadow DOM for the templates, styles **included**:
|
||||
* - components templates are added as children of their component element,
|
||||
* - both the template and the styles are modified so that styles are scoped to the component
|
||||
* they belong to,
|
||||
* - styles are moved from the templates to the styleHost (i.e. the document head).
|
||||
*
|
||||
* Notes:
|
||||
* - styles are scoped to their component and will apply only to it,
|
||||
* - a common subset of shadow DOM selectors are supported,
|
||||
* - see `ShadowCss` for more information and limitations.
|
||||
*/
|
||||
export class EmulatedScopedShadowDomStrategy extends EmulatedUnscopedShadowDomStrategy {
|
||||
constructor(styleHost) { super(styleHost); }
|
||||
|
||||
processStyleElement(hostComponentId: string, templateUrl: string, styleEl: Element): void {
|
||||
let cssText = DOM.getText(styleEl);
|
||||
cssText = shimCssForComponent(cssText, hostComponentId);
|
||||
DOM.setText(styleEl, cssText);
|
||||
this._moveToStyleHost(styleEl);
|
||||
}
|
||||
|
||||
_moveToStyleHost(styleEl): void {
|
||||
DOM.remove(styleEl);
|
||||
insertStyleElement(this.styleHost, styleEl);
|
||||
}
|
||||
|
||||
processElement(hostComponentId: string, elementComponentId: string, element: Element): void {
|
||||
// Shim the element as a child of the compiled component
|
||||
if (isPresent(hostComponentId)) {
|
||||
var contentAttribute = getContentAttribute(getComponentId(hostComponentId));
|
||||
DOM.setAttribute(element, contentAttribute, '');
|
||||
}
|
||||
// If the current element is also a component, shim it as a host
|
||||
if (isPresent(elementComponentId)) {
|
||||
var hostAttribute = getHostAttribute(getComponentId(elementComponentId));
|
||||
DOM.setAttribute(element, hostAttribute, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
|
||||
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
||||
import {insertSharedStyleText} from './util';
|
||||
|
||||
/**
|
||||
* This strategy emulates the Shadow DOM for the templates, styles **excluded**:
|
||||
* - components templates are added as children of their component element,
|
||||
* - styles are moved from the templates to the styleHost (i.e. the document head).
|
||||
*
|
||||
* Notes:
|
||||
* - styles are **not** scoped to their component and will apply to the whole document,
|
||||
* - you can **not** use shadow DOM specific selectors in the styles
|
||||
*/
|
||||
export class EmulatedUnscopedShadowDomStrategy extends ShadowDomStrategy {
|
||||
constructor(public styleHost) { super(); }
|
||||
|
||||
hasNativeContentElement(): boolean { return false; }
|
||||
|
||||
processStyleElement(hostComponentId: string, templateUrl: string, styleEl: Element): void {
|
||||
var cssText = DOM.getText(styleEl);
|
||||
insertSharedStyleText(cssText, this.styleHost, styleEl);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import {Injectable} from 'angular2/di';
|
||||
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
||||
|
||||
/**
|
||||
* This strategies uses the native Shadow DOM support.
|
||||
*
|
||||
* The templates for the component are inserted in a Shadow Root created on the component element.
|
||||
* Hence they are strictly isolated.
|
||||
*/
|
||||
@Injectable()
|
||||
export class NativeShadowDomStrategy extends ShadowDomStrategy {
|
||||
hasNativeContentElement(): boolean { return true; }
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import {CompileStep} from '../compiler/compile_step';
|
||||
import {CompileElement} from '../compiler/compile_element';
|
||||
import {CompileControl} from '../compiler/compile_control';
|
||||
import {ViewDefinition} from '../../api';
|
||||
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
||||
import {NG_CONTENT_ELEMENT_NAME, isElementWithTag} from '../util';
|
||||
|
||||
export class ShadowDomCompileStep implements CompileStep {
|
||||
constructor(public _shadowDomStrategy: ShadowDomStrategy, public _view: ViewDefinition) {}
|
||||
|
||||
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
|
||||
if (isElementWithTag(current.element, NG_CONTENT_ELEMENT_NAME)) {
|
||||
current.inheritedProtoView.bindNgContent();
|
||||
} else if (isElementWithTag(current.element, 'style')) {
|
||||
this._processStyleElement(current, control);
|
||||
} else {
|
||||
var componentId = current.isBound() ? current.inheritedElementBinder.componentId : null;
|
||||
this._shadowDomStrategy.processElement(this._view.componentId, componentId, current.element);
|
||||
}
|
||||
}
|
||||
|
||||
_processStyleElement(current: CompileElement, control: CompileControl) {
|
||||
this._shadowDomStrategy.processStyleElement(this._view.componentId, this._view.templateAbsUrl,
|
||||
current.element);
|
||||
|
||||
// Style elements should not be further processed by the compiler, as they can not contain
|
||||
// bindings. Skipping further compiler steps allow speeding up the compilation process.
|
||||
control.ignoreCurrentElement();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import {isBlank, isPresent} from 'angular2/src/facade/lang';
|
||||
|
||||
export class ShadowDomStrategy {
|
||||
// Whether the strategy understands the native <content> tag
|
||||
hasNativeContentElement(): boolean { return true; }
|
||||
|
||||
// An optional step that can modify the template style elements.
|
||||
processStyleElement(hostComponentId: string, templateUrl: string, styleElement: HTMLStyleElement):
|
||||
void {}
|
||||
|
||||
// An optional step that can modify the template elements (style elements exlcuded).
|
||||
processElement(hostComponentId: string, elementComponentId: string, element: HTMLElement): void {}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user