parent
147aec43bd
commit
d1de587ce0
File diff suppressed because one or more lines are too long
|
@ -17,7 +17,7 @@ function noop() {}
|
||||||
export function main() {
|
export function main() {
|
||||||
let component: LargeTableComponent;
|
let component: LargeTableComponent;
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
component = renderComponent<LargeTableComponent>(LargeTableComponent, {renderer: document});
|
component = renderComponent<LargeTableComponent>(LargeTableComponent);
|
||||||
bindAction('#createDom', () => createDom(component));
|
bindAction('#createDom', () => createDom(component));
|
||||||
bindAction('#destroyDom', () => destroyDom(component));
|
bindAction('#destroyDom', () => destroyDom(component));
|
||||||
bindAction('#updateDomProfile', profile(() => createDom(component), noop, 'update'));
|
bindAction('#updateDomProfile', profile(() => createDom(component), noop, 'update'));
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {C, E, T, V, b, c, defineComponent, detectChanges, e, rC, rc, s, t, v} from '@angular/core/src/render3/index';
|
import {C, E, T, V, b, c, cR, cr, defineComponent, detectChanges, e, s, t, v} from '@angular/core/src/render3/index';
|
||||||
import {ComponentDef} from '@angular/core/src/render3/public_interfaces';
|
import {ComponentDef} from '@angular/core/src/render3/public_interfaces';
|
||||||
|
|
||||||
import {TableCell, buildTable, emptyTable} from '../util';
|
import {TableCell, buildTable, emptyTable} from '../util';
|
||||||
|
@ -31,7 +31,7 @@ export class LargeTableComponent {
|
||||||
}
|
}
|
||||||
e();
|
e();
|
||||||
}
|
}
|
||||||
rC(2);
|
cR(2);
|
||||||
{
|
{
|
||||||
for (let row of ctx.data) {
|
for (let row of ctx.data) {
|
||||||
let cm1 = V(1);
|
let cm1 = V(1);
|
||||||
|
@ -42,7 +42,7 @@ export class LargeTableComponent {
|
||||||
c();
|
c();
|
||||||
e();
|
e();
|
||||||
}
|
}
|
||||||
rC(1);
|
cR(1);
|
||||||
{
|
{
|
||||||
for (let cell of row) {
|
for (let cell of row) {
|
||||||
let cm2 = V(2);
|
let cm2 = V(2);
|
||||||
|
@ -58,12 +58,12 @@ export class LargeTableComponent {
|
||||||
v();
|
v();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc();
|
cr();
|
||||||
}
|
}
|
||||||
v();
|
v();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc();
|
cr();
|
||||||
},
|
},
|
||||||
factory: () => new LargeTableComponent(),
|
factory: () => new LargeTableComponent(),
|
||||||
inputs: {data: 'data'}
|
inputs: {data: 'data'}
|
||||||
|
|
|
@ -15,7 +15,7 @@ function noop() {}
|
||||||
export function main() {
|
export function main() {
|
||||||
let component: TreeComponent;
|
let component: TreeComponent;
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
component = renderComponent(TreeComponent, {renderer: document});
|
component = renderComponent(TreeComponent);
|
||||||
bindAction('#createDom', () => createDom(component));
|
bindAction('#createDom', () => createDom(component));
|
||||||
bindAction('#destroyDom', () => destroyDom(component));
|
bindAction('#destroyDom', () => destroyDom(component));
|
||||||
bindAction('#detectChanges', () => detectChanges(component));
|
bindAction('#detectChanges', () => detectChanges(component));
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {C, D, E, T, V, b, b1, c, defineComponent, detectChanges as _detectChanges, e, p, rC, rc, s, t, v} from '@angular/core/src/render3/index';
|
import {C, D, E, T, V, b, b1, c, cR, cr, defineComponent, detectChanges as _detectChanges, e, p, s, t, v} from '@angular/core/src/render3/index';
|
||||||
import {ComponentDef} from '@angular/core/src/render3/public_interfaces';
|
import {ComponentDef} from '@angular/core/src/render3/public_interfaces';
|
||||||
|
|
||||||
import {TreeNode, buildTree, emptyTree} from '../util';
|
import {TreeNode, buildTree, emptyTree} from '../util';
|
||||||
|
@ -50,7 +50,7 @@ export class TreeComponent {
|
||||||
}
|
}
|
||||||
s(0, 'background-color', b(ctx.data.depth % 2 ? '' : 'grey'));
|
s(0, 'background-color', b(ctx.data.depth % 2 ? '' : 'grey'));
|
||||||
t(1, b1(' ', ctx.data.value, ' '));
|
t(1, b1(' ', ctx.data.value, ' '));
|
||||||
rC(2);
|
cR(2);
|
||||||
{
|
{
|
||||||
if (ctx.data.left != null) {
|
if (ctx.data.left != null) {
|
||||||
let cm0 = V(0);
|
let cm0 = V(0);
|
||||||
|
@ -66,8 +66,8 @@ export class TreeComponent {
|
||||||
v();
|
v();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc();
|
cr();
|
||||||
rC(3);
|
cR(3);
|
||||||
{
|
{
|
||||||
if (ctx.data.right != null) {
|
if (ctx.data.right != null) {
|
||||||
let cm0 = V(0);
|
let cm0 = V(0);
|
||||||
|
@ -83,7 +83,7 @@ export class TreeComponent {
|
||||||
v();
|
v();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc();
|
cr();
|
||||||
},
|
},
|
||||||
factory: () => new TreeComponent,
|
factory: () => new TreeComponent,
|
||||||
inputs: {data: 'data'}
|
inputs: {data: 'data'}
|
||||||
|
@ -118,7 +118,7 @@ export function TreeTpl(ctx: TreeNode, cm: boolean) {
|
||||||
}
|
}
|
||||||
s(0, 'background-color', b(ctx.depth % 2 ? '' : 'grey'));
|
s(0, 'background-color', b(ctx.depth % 2 ? '' : 'grey'));
|
||||||
t(1, b1(' ', ctx.value, ' '));
|
t(1, b1(' ', ctx.value, ' '));
|
||||||
rC(2);
|
cR(2);
|
||||||
{
|
{
|
||||||
if (ctx.left != null) {
|
if (ctx.left != null) {
|
||||||
let cm0 = V(0);
|
let cm0 = V(0);
|
||||||
|
@ -126,8 +126,8 @@ export function TreeTpl(ctx: TreeNode, cm: boolean) {
|
||||||
v();
|
v();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc();
|
cr();
|
||||||
rC(3);
|
cR(3);
|
||||||
{
|
{
|
||||||
if (ctx.right != null) {
|
if (ctx.right != null) {
|
||||||
let cm0 = V(0);
|
let cm0 = V(0);
|
||||||
|
@ -135,5 +135,5 @@ export function TreeTpl(ctx: TreeNode, cm: boolean) {
|
||||||
v();
|
v();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc();
|
cr();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ function noop() {}
|
||||||
export function main() {
|
export function main() {
|
||||||
let component: TreeFunction;
|
let component: TreeFunction;
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
component = renderComponent(TreeFunction, {renderer: document});
|
component = renderComponent(TreeFunction);
|
||||||
bindAction('#createDom', () => createDom(component));
|
bindAction('#createDom', () => createDom(component));
|
||||||
bindAction('#destroyDom', () => destroyDom(component));
|
bindAction('#destroyDom', () => destroyDom(component));
|
||||||
bindAction('#detectChanges', () => detectChanges(component));
|
bindAction('#detectChanges', () => detectChanges(component));
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
import {ComponentRef, EmbeddedViewRef, Injector} from '../core';
|
import {ComponentRef, EmbeddedViewRef, Injector} from '../core';
|
||||||
|
|
||||||
import {assertNotNull} from './assert';
|
import {assertNotNull} from './assert';
|
||||||
import {NG_HOST_SYMBOL, createError, createViewState, directive, elementHost, enterView, leaveView} from './instructions';
|
import {NG_HOST_SYMBOL, createError, createViewState, directive, enterView, hostElement, leaveView, locateHostElement, renderComponentOrTemplate} from './instructions';
|
||||||
import {LElement} from './l_node';
|
import {LElement} from './l_node';
|
||||||
import {ComponentDef, ComponentType} from './public_interfaces';
|
import {ComponentDef, ComponentType} from './public_interfaces';
|
||||||
import {RElement, Renderer3, RendererFactory3} from './renderer';
|
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './renderer';
|
||||||
import {notImplemented, stringify} from './util';
|
import {notImplemented, stringify} from './util';
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,10 +22,8 @@ import {notImplemented, stringify} from './util';
|
||||||
*/
|
*/
|
||||||
export interface CreateComponentOptionArgs {
|
export interface CreateComponentOptionArgs {
|
||||||
/**
|
/**
|
||||||
* Which renderer to use.
|
* Which renderer factory to use.
|
||||||
*/
|
*/
|
||||||
renderer?: Renderer3;
|
|
||||||
|
|
||||||
rendererFactory?: RendererFactory3;
|
rendererFactory?: RendererFactory3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,13 +136,16 @@ export const NULL_INJECTOR: Injector = {
|
||||||
*/
|
*/
|
||||||
export function renderComponent<T>(
|
export function renderComponent<T>(
|
||||||
componentType: ComponentType<T>, opts: CreateComponentOptionArgs = {}): T {
|
componentType: ComponentType<T>, opts: CreateComponentOptionArgs = {}): T {
|
||||||
const renderer = opts.renderer || document;
|
const rendererFactory = opts.rendererFactory || domRendererFactory3;
|
||||||
const componentDef = componentType.ngComponentDef;
|
const componentDef = componentType.ngComponentDef;
|
||||||
let component: T;
|
let component: T;
|
||||||
const oldView = enterView(createViewState(-1, renderer, []), null);
|
const hostNode = locateHostElement(rendererFactory, opts.host || componentDef.tag);
|
||||||
|
const oldView = enterView(
|
||||||
|
createViewState(-1, rendererFactory.createRenderer(hostNode, componentDef.rendererType), []),
|
||||||
|
null !);
|
||||||
try {
|
try {
|
||||||
// Create element node at index 0 in data array
|
// Create element node at index 0 in data array
|
||||||
elementHost(opts.host || componentDef.tag, componentDef);
|
hostElement(hostNode, componentDef);
|
||||||
// Create directive instance with n() and store at index 1 in data array (el is 0)
|
// Create directive instance with n() and store at index 1 in data array (el is 0)
|
||||||
component = directive(1, componentDef.n(), componentDef);
|
component = directive(1, componentDef.n(), componentDef);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -163,15 +164,8 @@ export function detectChanges<T>(component: T) {
|
||||||
createError('Not a directive instance', component);
|
createError('Not a directive instance', component);
|
||||||
}
|
}
|
||||||
ngDevMode && assertNotNull(hostNode.data, 'hostNode.data');
|
ngDevMode && assertNotNull(hostNode.data, 'hostNode.data');
|
||||||
const oldView = enterView(hostNode.view !, hostNode);
|
renderComponentOrTemplate(hostNode, hostNode.view, component);
|
||||||
try {
|
isDirty = false;
|
||||||
// Element was stored at 0 and directive was stored at 1 in renderComponent
|
|
||||||
// so to refresh the component, r() needs to be called with (1, 0)
|
|
||||||
(component.constructor as ComponentType<T>).ngComponentDef.r(1, 0);
|
|
||||||
isDirty = false;
|
|
||||||
} finally {
|
|
||||||
leaveView(oldView);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let isDirty = false;
|
let isDirty = false;
|
||||||
|
|
|
@ -18,9 +18,9 @@ import {NgStaticData, LNodeStatic, LContainerStatic, InitialInputData, InitialIn
|
||||||
import {assertNodeType} from './node_assert';
|
import {assertNodeType} from './node_assert';
|
||||||
import {appendChild, insertChild, insertView, processProjectedNode, removeView} from './node_manipulation';
|
import {appendChild, insertChild, insertView, processProjectedNode, removeView} from './node_manipulation';
|
||||||
import {isNodeMatchingSelector} from './node_selector_matcher';
|
import {isNodeMatchingSelector} from './node_selector_matcher';
|
||||||
import {ComponentDef, ComponentTemplate, DirectiveDef} from './public_interfaces';
|
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef} from './public_interfaces';
|
||||||
import {QueryList, QueryState_} from './query';
|
import {QueryList, QueryState_} from './query';
|
||||||
import {RComment, RElement, RText, Renderer3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './renderer';
|
import {RComment, RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './renderer';
|
||||||
import {isDifferent, stringify} from './util';
|
import {isDifferent, stringify} from './util';
|
||||||
|
|
||||||
export {queryRefresh} from './query';
|
export {queryRefresh} from './query';
|
||||||
|
@ -73,6 +73,7 @@ let nextNgElementId = 0;
|
||||||
* Renderer2.
|
* Renderer2.
|
||||||
*/
|
*/
|
||||||
let renderer: Renderer3;
|
let renderer: Renderer3;
|
||||||
|
let rendererFactory: RendererFactory3;
|
||||||
|
|
||||||
/** Used to set the parent property when nodes are created. */
|
/** Used to set the parent property when nodes are created. */
|
||||||
let previousOrParentNode: LNode;
|
let previousOrParentNode: LNode;
|
||||||
|
@ -278,18 +279,44 @@ export function createLNode(
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param host Existing node to render into.
|
* @param host Existing node to render into.
|
||||||
* @param renderer Renderer to use.
|
|
||||||
* @param template Template function with the instructions.
|
* @param template Template function with the instructions.
|
||||||
* @param context to pass into the template.
|
* @param context to pass into the template.
|
||||||
*/
|
*/
|
||||||
export function renderTemplate<T>(host: LElement, template: ComponentTemplate<T>, context: T) {
|
export function renderTemplate<T>(
|
||||||
|
hostNode: RElement, template: ComponentTemplate<T>, context: T,
|
||||||
|
providedRendererFactory: RendererFactory3, host: LElement | null): LElement {
|
||||||
|
if (host == null) {
|
||||||
|
rendererFactory = providedRendererFactory;
|
||||||
|
host = createLNode(
|
||||||
|
null, LNodeFlags.Element, hostNode,
|
||||||
|
createViewState(-1, providedRendererFactory.createRenderer(null, null), []));
|
||||||
|
}
|
||||||
const hostView = host.data !;
|
const hostView = host.data !;
|
||||||
ngDevMode && assertNotEqual(hostView, null, 'hostView');
|
ngDevMode && assertNotEqual(hostView, null, 'hostView');
|
||||||
hostView.ngStaticData = getTemplateStatic(template);
|
hostView.ngStaticData = getTemplateStatic(template);
|
||||||
const oldView = enterView(hostView, host);
|
renderComponentOrTemplate(host, hostView, context, template);
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderComponentOrTemplate<T>(
|
||||||
|
node: LElement, viewState: ViewState, componentOrContext: T, template?: ComponentTemplate<T>) {
|
||||||
|
const oldView = enterView(viewState, node);
|
||||||
try {
|
try {
|
||||||
template(context, creationMode);
|
if (rendererFactory.begin) {
|
||||||
|
rendererFactory.begin();
|
||||||
|
}
|
||||||
|
if (template) {
|
||||||
|
ngStaticData = template.ngStaticData || (template.ngStaticData = [] as never);
|
||||||
|
template(componentOrContext !, creationMode);
|
||||||
|
} else {
|
||||||
|
// Element was stored at 0 and directive was stored at 1 in renderComponent
|
||||||
|
// so to refresh the component, r() needs to be called with (1, 0)
|
||||||
|
(componentOrContext.constructor as ComponentType<T>).ngComponentDef.r(1, 0);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
if (rendererFactory.end) {
|
||||||
|
rendererFactory.end();
|
||||||
|
}
|
||||||
leaveView(oldView);
|
leaveView(oldView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -406,7 +433,10 @@ export function elementStart(
|
||||||
let componentView: ViewState|null = null;
|
let componentView: ViewState|null = null;
|
||||||
if (isHostElement) {
|
if (isHostElement) {
|
||||||
const ngStaticData = getTemplateStatic((nameOrComponentDef as ComponentDef<any>).template);
|
const ngStaticData = getTemplateStatic((nameOrComponentDef as ComponentDef<any>).template);
|
||||||
componentView = addToViewTree(createViewState(-1, renderer, ngStaticData));
|
componentView = addToViewTree(createViewState(
|
||||||
|
-1, rendererFactory.createRenderer(
|
||||||
|
native, (nameOrComponentDef as ComponentDef<any>).rendererType),
|
||||||
|
ngStaticData));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only component views should be added to the view tree directly. Embedded views are
|
// Only component views should be added to the view tree directly. Embedded views are
|
||||||
|
@ -453,16 +483,19 @@ export function createError(text: string, token: any) {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for bootstrapping existing nodes into rendering pipeline.
|
* Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
|
||||||
*
|
*
|
||||||
* @param elementOrSelector Render element or CSS selector to locate the element.
|
* @param elementOrSelector Render element or CSS selector to locate the element.
|
||||||
*/
|
*/
|
||||||
export function elementHost(elementOrSelector: RElement | string, def: ComponentDef<any>) {
|
export function locateHostElement(
|
||||||
|
factory: RendererFactory3, elementOrSelector: RElement | string): RElement|null {
|
||||||
ngDevMode && assertDataInRange(-1);
|
ngDevMode && assertDataInRange(-1);
|
||||||
|
rendererFactory = factory;
|
||||||
|
const defaultRenderer = factory.createRenderer(null, null);
|
||||||
const rNode = typeof elementOrSelector === 'string' ?
|
const rNode = typeof elementOrSelector === 'string' ?
|
||||||
((renderer as ProceduralRenderer3).selectRootElement ?
|
((defaultRenderer as ProceduralRenderer3).selectRootElement ?
|
||||||
(renderer as ProceduralRenderer3).selectRootElement(elementOrSelector) :
|
(defaultRenderer as ProceduralRenderer3).selectRootElement(elementOrSelector) :
|
||||||
(renderer as ObjectOrientedRenderer3).querySelector !(elementOrSelector)) :
|
(defaultRenderer as ObjectOrientedRenderer3).querySelector !(elementOrSelector)) :
|
||||||
elementOrSelector;
|
elementOrSelector;
|
||||||
if (ngDevMode && !rNode) {
|
if (ngDevMode && !rNode) {
|
||||||
if (typeof elementOrSelector === 'string') {
|
if (typeof elementOrSelector === 'string') {
|
||||||
|
@ -471,6 +504,15 @@ export function elementHost(elementOrSelector: RElement | string, def: Component
|
||||||
throw createError('Host node is required:', elementOrSelector);
|
throw createError('Host node is required:', elementOrSelector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return rNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the host LNode..
|
||||||
|
*
|
||||||
|
* @param rNode Render host element.
|
||||||
|
*/
|
||||||
|
export function hostElement(rNode: RElement | null, def: ComponentDef<any>) {
|
||||||
createLNode(
|
createLNode(
|
||||||
0, LNodeFlags.Element, rNode, createViewState(-1, renderer, getTemplateStatic(def.template)));
|
0, LNodeFlags.Element, rNode, createViewState(-1, renderer, getTemplateStatic(def.template)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Type} from '../core';
|
import {RendererType2, Type} from '../core';
|
||||||
|
import {resolveRendererType2} from '../view/util';
|
||||||
import {componentRefresh, diPublic} from './instructions';
|
import {componentRefresh, diPublic} from './instructions';
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,6 +108,13 @@ export interface ComponentDef<T> extends DirectiveDef<T> {
|
||||||
* NOTE: only used with component directives.
|
* NOTE: only used with component directives.
|
||||||
*/
|
*/
|
||||||
template: ComponentTemplate<T>;
|
template: ComponentTemplate<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renderer type data of the component.
|
||||||
|
*
|
||||||
|
* NOTE: only used with component directives.
|
||||||
|
*/
|
||||||
|
rendererType: RendererType2|null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DirectiveDefArgs<T> {
|
export interface DirectiveDefArgs<T> {
|
||||||
|
@ -125,6 +132,7 @@ export interface ComponentDefArgs<T> extends DirectiveDefArgs<T> {
|
||||||
template: ComponentTemplate<T>;
|
template: ComponentTemplate<T>;
|
||||||
refresh?: (this: ComponentDef<T>, directiveIndex: number, elementIndex: number) => void;
|
refresh?: (this: ComponentDef<T>, directiveIndex: number, elementIndex: number) => void;
|
||||||
features?: ComponentDefFeature[];
|
features?: ComponentDefFeature[];
|
||||||
|
rendererType?: RendererType2;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DirectiveDefFeature = <T>(directiveDef: DirectiveDef<T>) => void;
|
export type DirectiveDefFeature = <T>(directiveDef: DirectiveDef<T>) => void;
|
||||||
|
@ -156,6 +164,7 @@ export function defineComponent<T>(componentDefinition: ComponentDefArgs<T>): Co
|
||||||
inputs: invertObject(componentDefinition.inputs),
|
inputs: invertObject(componentDefinition.inputs),
|
||||||
outputs: invertObject(componentDefinition.outputs),
|
outputs: invertObject(componentDefinition.outputs),
|
||||||
methods: invertObject(componentDefinition.methods),
|
methods: invertObject(componentDefinition.methods),
|
||||||
|
rendererType: resolveRendererType2(componentDefinition.rendererType) || null,
|
||||||
};
|
};
|
||||||
const feature = componentDefinition.features;
|
const feature = componentDefinition.features;
|
||||||
feature && feature.forEach((fn) => fn(def));
|
feature && feature.forEach((fn) => fn(def));
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {DirectiveDef} from '@angular/core/src/render3/public_interfaces';
|
|
||||||
import {Observable} from 'rxjs/Observable';
|
import {Observable} from 'rxjs/Observable';
|
||||||
|
|
||||||
import * as viewEngine from '../core';
|
import * as viewEngine from '../core';
|
||||||
|
@ -15,6 +14,7 @@ import {assertNotNull} from './assert';
|
||||||
import {injectElementRefForNode} from './di';
|
import {injectElementRefForNode} from './di';
|
||||||
import {QueryState} from './interfaces';
|
import {QueryState} from './interfaces';
|
||||||
import {LContainer, LElement, LNode, LNodeFlags, LView} from './l_node';
|
import {LContainer, LElement, LNode, LNodeFlags, LView} from './l_node';
|
||||||
|
import {DirectiveDef} from './public_interfaces';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* it will be easy to implement such API.
|
* it will be easy to implement such API.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {RendererStyleFlags2} from '../core';
|
import {RendererStyleFlags2, RendererType2, ViewEncapsulation} from '../core';
|
||||||
import {ComponentDef} from './public_interfaces';
|
import {ComponentDef} from './public_interfaces';
|
||||||
|
|
||||||
// TODO: cleanup once the code is merged in angular/angular
|
// TODO: cleanup once the code is merged in angular/angular
|
||||||
|
@ -68,11 +68,16 @@ export interface ProceduralRenderer3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RendererFactory3 {
|
export interface RendererFactory3 {
|
||||||
createRenderer(hostElement: RElement, componentDef: ComponentDef<any>): Renderer3;
|
createRenderer(hostElement: RElement|null, rendererType: RendererType2|null): Renderer3;
|
||||||
begin?(): void;
|
begin?(): void;
|
||||||
end?(): void;
|
end?(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const domRendererFactory3: RendererFactory3 = {
|
||||||
|
createRenderer: (hostElement: RElement | null, rendererType: RendererType2 | null):
|
||||||
|
Renderer3 => { return document;}
|
||||||
|
};
|
||||||
|
|
||||||
/** Subset of API needed for appending elements and text nodes. */
|
/** Subset of API needed for appending elements and text nodes. */
|
||||||
export interface RNode {
|
export interface RNode {
|
||||||
removeChild(oldChild: RNode): void;
|
removeChild(oldChild: RNode): void;
|
||||||
|
|
|
@ -6,8 +6,11 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {T, b, defineComponent, markDirty, t} from '../../src/render3/index';
|
import {ViewEncapsulation} from '../../src/core';
|
||||||
|
import {D, E, T, b, defineComponent, e, markDirty, t} from '../../src/render3/index';
|
||||||
|
import {createRendererType2} from '../../src/view';
|
||||||
|
|
||||||
|
import {getRendererFactory2} from './imported_renderer2';
|
||||||
import {containerEl, renderComponent, requestAnimationFrame} from './render_util';
|
import {containerEl, renderComponent, requestAnimationFrame} from './render_util';
|
||||||
|
|
||||||
describe('component', () => {
|
describe('component', () => {
|
||||||
|
@ -60,3 +63,113 @@ describe('component', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: add tests with Native once tests are run in real browser (domino doesn't support shadow
|
||||||
|
// root)
|
||||||
|
describe('encapsulation', () => {
|
||||||
|
class WrapperComponent {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: WrapperComponent,
|
||||||
|
tag: 'wrapper',
|
||||||
|
template: function(ctx: WrapperComponent, cm: boolean) {
|
||||||
|
if (cm) {
|
||||||
|
E(0, EncapsulatedComponent.ngComponentDef);
|
||||||
|
{ D(1, EncapsulatedComponent.ngComponentDef.n(), EncapsulatedComponent.ngComponentDef); }
|
||||||
|
e();
|
||||||
|
}
|
||||||
|
EncapsulatedComponent.ngComponentDef.r(1, 0);
|
||||||
|
},
|
||||||
|
factory: () => new WrapperComponent,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class EncapsulatedComponent {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: EncapsulatedComponent,
|
||||||
|
tag: 'encapsulated',
|
||||||
|
template: function(ctx: EncapsulatedComponent, cm: boolean) {
|
||||||
|
if (cm) {
|
||||||
|
T(0, 'foo');
|
||||||
|
E(1, LeafComponent.ngComponentDef);
|
||||||
|
{ D(2, LeafComponent.ngComponentDef.n(), LeafComponent.ngComponentDef); }
|
||||||
|
e();
|
||||||
|
}
|
||||||
|
LeafComponent.ngComponentDef.r(2, 1);
|
||||||
|
},
|
||||||
|
factory: () => new EncapsulatedComponent,
|
||||||
|
rendererType:
|
||||||
|
createRendererType2({encapsulation: ViewEncapsulation.Emulated, styles: [], data: {}}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class LeafComponent {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: LeafComponent,
|
||||||
|
tag: 'leaf',
|
||||||
|
template: function(ctx: LeafComponent, cm: boolean) {
|
||||||
|
if (cm) {
|
||||||
|
E(0, 'span');
|
||||||
|
{ T(1, 'bar'); }
|
||||||
|
e();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
factory: () => new LeafComponent,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should encapsulate children, but not host nor grand children', () => {
|
||||||
|
renderComponent(WrapperComponent, getRendererFactory2(document));
|
||||||
|
expect(containerEl.outerHTML)
|
||||||
|
.toEqual(
|
||||||
|
'<div host=""><encapsulated _nghost-c0="">foo<leaf _ngcontent-c0=""><span>bar</span></leaf></encapsulated></div>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should encapsulate host', () => {
|
||||||
|
renderComponent(EncapsulatedComponent, getRendererFactory2(document));
|
||||||
|
expect(containerEl.outerHTML)
|
||||||
|
.toEqual(
|
||||||
|
'<div host="" _nghost-c0="">foo<leaf _ngcontent-c0=""><span>bar</span></leaf></div>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should encapsulate host and children with different attributes', () => {
|
||||||
|
class WrapperComponentWith {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: WrapperComponent,
|
||||||
|
tag: 'wrapper',
|
||||||
|
template: function(ctx: WrapperComponentWith, cm: boolean) {
|
||||||
|
if (cm) {
|
||||||
|
E(0, LeafComponentwith.ngComponentDef);
|
||||||
|
{ D(1, LeafComponentwith.ngComponentDef.n(), LeafComponentwith.ngComponentDef); }
|
||||||
|
e();
|
||||||
|
}
|
||||||
|
LeafComponentwith.ngComponentDef.r(1, 0);
|
||||||
|
},
|
||||||
|
factory: () => new WrapperComponentWith,
|
||||||
|
rendererType:
|
||||||
|
createRendererType2({encapsulation: ViewEncapsulation.Emulated, styles: [], data: {}}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class LeafComponentwith {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: LeafComponentwith,
|
||||||
|
tag: 'leaf',
|
||||||
|
template: function(ctx: LeafComponentwith, cm: boolean) {
|
||||||
|
if (cm) {
|
||||||
|
E(0, 'span');
|
||||||
|
{ T(1, 'bar'); }
|
||||||
|
e();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
factory: () => new LeafComponentwith,
|
||||||
|
rendererType:
|
||||||
|
createRendererType2({encapsulation: ViewEncapsulation.Emulated, styles: [], data: {}}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderComponent(WrapperComponentWith, getRendererFactory2(document));
|
||||||
|
expect(containerEl.outerHTML)
|
||||||
|
.toEqual(
|
||||||
|
'<div host="" _nghost-c1=""><leaf _ngcontent-c1="" _nghost-c2=""><span _ngcontent-c2="">bar</span></leaf></div>');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -6,10 +6,9 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {EventEmitter, NgZone, Renderer2} from '@angular/core';
|
import {EventEmitter, NgZone, RendererFactory2} from '@angular/core';
|
||||||
import {EventManager, ɵDomEventsPlugin, ɵDomRendererFactory2, ɵDomSharedStylesHost} from '@angular/platform-browser';
|
import {EventManager, ɵDomEventsPlugin, ɵDomRendererFactory2, ɵDomSharedStylesHost} from '@angular/platform-browser';
|
||||||
|
|
||||||
|
|
||||||
// Adapted renderer: it creates a Renderer2 instance and adapts it to Renderer3
|
// Adapted renderer: it creates a Renderer2 instance and adapts it to Renderer3
|
||||||
// TODO: remove once this code is in angular/angular
|
// TODO: remove once this code is in angular/angular
|
||||||
export class NoopNgZone implements NgZone {
|
export class NoopNgZone implements NgZone {
|
||||||
|
@ -47,11 +46,9 @@ export class SimpleDomEventsPlugin extends ɵDomEventsPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRenderer2(document: any): Renderer2 {
|
export function getRendererFactory2(document: any): RendererFactory2 {
|
||||||
const fakeNgZone: NgZone = new NoopNgZone();
|
const fakeNgZone: NgZone = new NoopNgZone();
|
||||||
const eventManager =
|
const eventManager =
|
||||||
new EventManager([new SimpleDomEventsPlugin(document, fakeNgZone)], fakeNgZone);
|
new EventManager([new SimpleDomEventsPlugin(document, fakeNgZone)], fakeNgZone);
|
||||||
const rendererFactory2 =
|
return new ɵDomRendererFactory2(eventManager, new ɵDomSharedStylesHost(document));
|
||||||
new ɵDomRendererFactory2(eventManager, new ɵDomSharedStylesHost(document));
|
|
||||||
return rendererFactory2.createRenderer(null, null);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,19 +9,17 @@
|
||||||
import {ComponentTemplate, ComponentType, PublicFeature, defineComponent, renderComponent as _renderComponent} from '../../src/render3/index';
|
import {ComponentTemplate, ComponentType, PublicFeature, defineComponent, renderComponent as _renderComponent} from '../../src/render3/index';
|
||||||
import {NG_HOST_SYMBOL, createLNode, createViewState, renderTemplate} from '../../src/render3/instructions';
|
import {NG_HOST_SYMBOL, createLNode, createViewState, renderTemplate} from '../../src/render3/instructions';
|
||||||
import {LElement, LNodeFlags} from '../../src/render3/l_node';
|
import {LElement, LNodeFlags} from '../../src/render3/l_node';
|
||||||
import {RElement, RText, Renderer3} from '../../src/render3/renderer';
|
import {RElement, RText, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/renderer';
|
||||||
import {getRenderer2} from './imported_renderer2';
|
import {getRendererFactory2} from './imported_renderer2';
|
||||||
|
|
||||||
export const document = ((global || window) as any).document;
|
export const document = ((global || window) as any).document;
|
||||||
export let containerEl: HTMLElement = null !;
|
export let containerEl: HTMLElement = null !;
|
||||||
let host: LElement;
|
let host: LElement|null;
|
||||||
let activeRenderer: Renderer3 =
|
const isRenderer2 = process.argv[3] && process.argv[3] === '--r=renderer2';
|
||||||
(typeof process !== 'undefined' && process.argv[3] && process.argv[3] === '--r=renderer2') ?
|
|
||||||
getRenderer2(document) :
|
|
||||||
document;
|
|
||||||
// tslint:disable-next-line:no-console
|
// tslint:disable-next-line:no-console
|
||||||
console.log(
|
console.log(`Running tests with ${!isRenderer2 ? 'document' : 'Renderer2'} renderer...`);
|
||||||
`Running tests with ${activeRenderer === document ? 'document' : 'Renderer2'} renderer...`);
|
const testRendererFactory: RendererFactory3 =
|
||||||
|
isRenderer2 ? getRendererFactory2(document) : domRendererFactory3;
|
||||||
|
|
||||||
export const requestAnimationFrame:
|
export const requestAnimationFrame:
|
||||||
{(fn: () => void): void; flush(): void; queue: (() => void)[];} = function(fn: () => void) {
|
{(fn: () => void): void; flush(): void; queue: (() => void)[];} = function(fn: () => void) {
|
||||||
|
@ -37,20 +35,22 @@ export function resetDOM() {
|
||||||
requestAnimationFrame.queue = [];
|
requestAnimationFrame.queue = [];
|
||||||
containerEl = document.createElement('div');
|
containerEl = document.createElement('div');
|
||||||
containerEl.setAttribute('host', '');
|
containerEl.setAttribute('host', '');
|
||||||
host = createLNode(
|
host = null;
|
||||||
null, LNodeFlags.Element, containerEl, createViewState(-1, activeRenderer, null !));
|
|
||||||
// TODO: assert that the global state is clean (e.g. ngData, previousOrParentNode, etc)
|
// TODO: assert that the global state is clean (e.g. ngData, previousOrParentNode, etc)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderToHtml(template: ComponentTemplate<any>, ctx: any) {
|
export function renderToHtml(
|
||||||
renderTemplate(host, template, ctx);
|
template: ComponentTemplate<any>, ctx: any, providedRendererFactory?: RendererFactory3) {
|
||||||
return toHtml(host.native);
|
host = renderTemplate(
|
||||||
|
containerEl, template, ctx, providedRendererFactory || testRendererFactory, host);
|
||||||
|
return toHtml(containerEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(resetDOM);
|
beforeEach(resetDOM);
|
||||||
|
|
||||||
export function renderComponent<T>(type: ComponentType<T>): T {
|
export function renderComponent<T>(type: ComponentType<T>, rendererFactory?: RendererFactory3): T {
|
||||||
return _renderComponent(type, {renderer: activeRenderer, host: containerEl});
|
return _renderComponent(
|
||||||
|
type, {rendererFactory: rendererFactory || testRendererFactory, host: containerEl});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toHtml<T>(componentOrElement: T | RElement): string {
|
export function toHtml<T>(componentOrElement: T | RElement): string {
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {RendererType2} from '@angular/core';
|
||||||
|
|
||||||
|
import {D, E, e} from '../../src/render3';
|
||||||
|
import {T, defineComponent, detectChanges} from '../../src/render3/index';
|
||||||
|
|
||||||
|
import {getRendererFactory2} from './imported_renderer2';
|
||||||
|
import {document, renderComponent, renderToHtml, resetDOM} from './render_util';
|
||||||
|
|
||||||
|
describe('renderer factory lifecycle', () => {
|
||||||
|
let logs: string[] = [];
|
||||||
|
let rendererFactory = getRendererFactory2(document);
|
||||||
|
const createRender = rendererFactory.createRenderer;
|
||||||
|
rendererFactory.createRenderer = (hostElement: any, type: RendererType2 | null) => {
|
||||||
|
logs.push('create');
|
||||||
|
return createRender.apply(rendererFactory, [hostElement, type]);
|
||||||
|
};
|
||||||
|
rendererFactory.begin = () => logs.push('begin');
|
||||||
|
rendererFactory.end = () => logs.push('end');
|
||||||
|
|
||||||
|
class SomeComponent {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: SomeComponent,
|
||||||
|
tag: 'some-component',
|
||||||
|
template: function(ctx: SomeComponent, cm: boolean) {
|
||||||
|
logs.push('component');
|
||||||
|
if (cm) {
|
||||||
|
T(0, 'foo');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
factory: () => new SomeComponent
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class SomeComponentWhichThrows {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: SomeComponentWhichThrows,
|
||||||
|
tag: 'some-component-with-Error',
|
||||||
|
template: function(ctx: SomeComponentWhichThrows, cm: boolean) {
|
||||||
|
throw(new Error('SomeComponentWhichThrows threw'));
|
||||||
|
},
|
||||||
|
factory: () => new SomeComponentWhichThrows
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function Template(ctx: any, cm: boolean) {
|
||||||
|
logs.push('function');
|
||||||
|
if (cm) {
|
||||||
|
T(0, 'bar');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function TemplateWithComponent(ctx: any, cm: boolean) {
|
||||||
|
logs.push('function_with_component');
|
||||||
|
if (cm) {
|
||||||
|
T(0, 'bar');
|
||||||
|
E(1, SomeComponent.ngComponentDef);
|
||||||
|
{ D(2, SomeComponent.ngComponentDef.n(), SomeComponent.ngComponentDef); }
|
||||||
|
e();
|
||||||
|
}
|
||||||
|
SomeComponent.ngComponentDef.r(2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => { logs = []; });
|
||||||
|
|
||||||
|
it('should work with a component', () => {
|
||||||
|
const component = renderComponent(SomeComponent, rendererFactory);
|
||||||
|
expect(logs).toEqual(['create', 'create', 'begin', 'component', 'end']);
|
||||||
|
|
||||||
|
logs = [];
|
||||||
|
detectChanges(component);
|
||||||
|
expect(logs).toEqual(['begin', 'component', 'end']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work with a component which throws', () => {
|
||||||
|
expect(() => renderComponent(SomeComponentWhichThrows, rendererFactory)).toThrow();
|
||||||
|
expect(logs).toEqual(['create', 'create', 'begin', 'end']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work with a template', () => {
|
||||||
|
renderToHtml(Template, {}, rendererFactory);
|
||||||
|
expect(logs).toEqual(['create', 'begin', 'function', 'end']);
|
||||||
|
|
||||||
|
logs = [];
|
||||||
|
renderToHtml(Template, {});
|
||||||
|
expect(logs).toEqual(['begin', 'function', 'end']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work with a template which contains a component', () => {
|
||||||
|
renderToHtml(TemplateWithComponent, {}, rendererFactory);
|
||||||
|
expect(logs).toEqual(
|
||||||
|
['create', 'begin', 'function_with_component', 'create', 'component', 'end']);
|
||||||
|
|
||||||
|
logs = [];
|
||||||
|
renderToHtml(TemplateWithComponent, {});
|
||||||
|
expect(logs).toEqual(['begin', 'function_with_component', 'component', 'end']);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in New Issue