feat: RendererV2 integration (#14469)

This commit is contained in:
Victor Berchet
2017-02-14 21:03:18 -08:00
committed by Igor Minar
parent b4d444a0a7
commit bb9c7ae6e7
38 changed files with 888 additions and 607 deletions

View File

@ -9,8 +9,8 @@
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry';
import {TEST_COMPILER_PROVIDERS} from '@angular/compiler/testing/test_bindings';
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, DebugElement, Directive, DoCheck, Injectable, Input, OnChanges, OnDestroy, OnInit, Output, Pipe, PipeTransform, RenderComponentType, Renderer, RootRenderer, SimpleChange, SimpleChanges, TemplateRef, Type, ViewChild, ViewContainerRef, WrappedValue} from '@angular/core';
import {DebugDomRenderer} from '@angular/core/src/debug/debug_renderer';
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, DebugElement, Directive, DoCheck, Inject, Injectable, Input, OnChanges, OnDestroy, OnInit, Output, Pipe, PipeTransform, RENDERER_V2_DIRECT, RenderComponentType, Renderer, RendererV2, RootRenderer, SimpleChange, SimpleChanges, TemplateRef, Type, ViewChild, ViewContainerRef, WrappedValue} from '@angular/core';
import {DebugDomRenderer, DebugDomRendererV2} from '@angular/core/src/debug/debug_renderer';
import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing';
import {By} from '@angular/platform-browser/src/dom/debug/by';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
@ -24,8 +24,12 @@ export function main() {
describe('View Engine compiler', () => {
beforeEach(() => {
TestBed.configureCompiler(
{useJit: true, providers: [{provide: USE_VIEW_ENGINE, useValue: true}]});
TestBed.configureCompiler({
useJit: true,
providers: [
{provide: USE_VIEW_ENGINE, useValue: true},
]
});
});
createTests({viewEngine: true});
@ -115,8 +119,16 @@ function createTests({viewEngine}: {viewEngine: boolean}) {
IdentityPipe,
WrappedPipe,
],
providers:
[RenderLog, DirectiveLog, {provide: RootRenderer, useClass: LoggingRootRenderer}]
providers: [
RenderLog,
DirectiveLog,
{provide: RootRenderer, useClass: LoggingRootRenderer},
{
provide: RendererV2,
useFactory: (r: RendererV2, log: RenderLog) => new LoggingRendererV2(r, log),
deps: [[new Inject(RENDERER_V2_DIRECT)], [RenderLog]],
},
],
});
});
@ -1303,6 +1315,20 @@ class DirectiveLogEntry {
constructor(public directiveName: string, public method: string) {}
}
class LoggingRendererV2 extends DebugDomRendererV2 {
constructor(private delegate: RendererV2, private log: RenderLog) { super(delegate); }
setProperty(el: any, name: string, value: any): void {
this.log.setElementProperty(el, name, value);
super.setProperty(el, name, value);
}
setText(node: any, value: string): void {
this.log.setText(node, value);
super.setText(node, value);
}
}
@Injectable()
class DirectiveLog {
entries: DirectiveLogEntry[] = [];

View File

@ -18,7 +18,6 @@ import {TemplateRef, TemplateRef_} from '@angular/core/src/linker/template_ref';
import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref';
import {EmbeddedViewRef} from '@angular/core/src/linker/view_ref';
import {Attribute, Component, ContentChildren, Directive, HostBinding, HostListener, Input, Output, Pipe} from '@angular/core/src/metadata';
import {Renderer} from '@angular/core/src/render';
import {TestBed, async, fakeAsync, getTestBed, tick} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {DOCUMENT} from '@angular/platform-browser/src/dom/dom_tokens';
@ -26,7 +25,7 @@ import {dispatchEvent, el} from '@angular/platform-browser/testing/browser_util'
import {expect} from '@angular/platform-browser/testing/matchers';
import {EventEmitter} from '../../src/facade/async';
import {isBlank, isPresent, stringify} from '../../src/facade/lang';
import {stringify} from '../../src/facade/lang';
const ANCHOR_ELEMENT = new InjectionToken('AnchorElement');
@ -37,18 +36,24 @@ export function main() {
describe('view engine', () => {
beforeEach(() => {
TestBed.configureCompiler(
{useJit: true, providers: [{provide: USE_VIEW_ENGINE, useValue: true}]});
TestBed.configureCompiler({
useJit: true,
providers: [{
provide: USE_VIEW_ENGINE,
useValue: true,
}],
});
});
declareTests({useJit: true, viewEngine: true});
});
}
function declareTests({useJit, viewEngine}: {useJit: boolean, viewEngine: boolean}) {
describe('integration tests', function() {
beforeEach(() => { TestBed.configureCompiler({useJit: useJit}); });
beforeEach(() => { TestBed.configureCompiler({useJit}); });
describe('react to record changes', function() {
it('should consume text node changes', () => {
@ -1472,7 +1477,7 @@ function declareTests({useJit, viewEngine}: {useJit: boolean, viewEngine: boolea
fixture.detectChanges();
const el = getDOM().querySelector(fixture.nativeElement, 'span');
expect(isBlank(el.title) || el.title == '').toBeTruthy();
expect(el.title).toBeFalsy();
});
it('should work when a directive uses hostProperty to update the DOM element', () => {
@ -2084,8 +2089,7 @@ class ToolbarPart {
@Directive({selector: '[toolbarVc]', inputs: ['toolbarVc']})
class ToolbarViewContainer {
vc: ViewContainerRef;
constructor(vc: ViewContainerRef) { this.vc = vc; }
constructor(public vc: ViewContainerRef) {}
set toolbarVc(part: ToolbarPart) {
this.vc.createEmbeddedView(part.templateRef, new ToolbarContext('From toolbar'), 0);
@ -2098,9 +2102,9 @@ class ToolbarViewContainer {
})
class ToolbarComponent {
@ContentChildren(ToolbarPart) query: QueryList<ToolbarPart>;
ctxProp: string;
ctxProp: string = 'hello world';
constructor() { this.ctxProp = 'hello world'; }
constructor() {}
}
@Directive({selector: '[two-way]', inputs: ['control'], outputs: ['controlChange']})
@ -2238,10 +2242,11 @@ class SomeImperativeViewport {
}
set someImpvp(value: boolean) {
if (isPresent(this.view)) {
if (this.view) {
this.vc.clear();
this.view = null;
}
if (value) {
this.view = this.vc.createEmbeddedView(this.templateRef);
const nodes = this.view.rootNodes;

View File

@ -8,7 +8,6 @@
import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation, getDebugNode} from '@angular/core';
import {DebugContext, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {inject} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {createRootView, isBrowser} from './helper';

View File

@ -8,7 +8,6 @@
import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation} from '@angular/core';
import {ArgumentType, BindingType, NodeCheckFn, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn, anchorDef, asProviderData, directiveDef, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {inject} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {createRootView, isBrowser, removeNodes} from './helper';
@ -182,23 +181,19 @@ export function main() {
const update = jasmine.createSpy('updater');
const addListenerSpy = spyOn(HTMLElement.prototype, 'addEventListener').and.callThrough();
const {view, rootNodes} =
createAndGetRootNodes(
compViewDef(
[
elementDef(NodeFlags.None, null, null, 1, 'div'),
directiveDef(
NodeFlags.None, null, 0, AComp, [], {a: [0, 'a']}, null,
() =>
compViewDef(
[
elementDef(NodeFlags.None, null, null, 0, 'span', null, null, ['click']),
],
update, null, null, ViewFlags.OnPush)),
],
(check, view) => { check(view, 1, ArgumentType.Inline, compInputValue); }));
const compView = asProviderData(view, 1).componentView;
const {view} = createAndGetRootNodes(compViewDef(
[
elementDef(NodeFlags.None, null, null, 1, 'div'),
directiveDef(
NodeFlags.None, null, 0, AComp, [], {a: [0, 'a']}, null,
() => compViewDef(
[
elementDef(NodeFlags.None, null, null, 0, 'span', null, null, ['click']),
],
update, null, null, ViewFlags.OnPush)),
],
(check, view) => { check(view, 1, ArgumentType.Inline, compInputValue); }));
Services.checkAndUpdateView(view);

View File

@ -9,7 +9,6 @@
import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation, WrappedValue, getDebugNode} from '@angular/core';
import {getDebugContext} from '@angular/core/src/errors';
import {ArgumentType, BindingType, DebugContext, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {inject} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, isBrowser, removeNodes} from './helper';

View File

@ -36,7 +36,7 @@ export function main() {
const parentContext = new Object();
const childContext = new Object();
const {view: parentView, rootNodes} = createAndGetRootNodes(
const {view: parentView} = createAndGetRootNodes(
compViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
anchorDef(
@ -146,7 +146,6 @@ export function main() {
const childView0 = Services.createEmbeddedView(parentView, parentView.def.nodes[1]);
const rootEl = rootNodes[0];
attachEmbeddedView(asElementData(parentView, 1), 0, childView0);
Services.checkAndUpdateView(parentView);
@ -171,7 +170,7 @@ export function main() {
ngOnDestroy() { log.push('ngOnDestroy'); };
}
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
const {view: parentView} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 1, 'span'),

View File

@ -8,7 +8,6 @@
import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, TemplateRef, ViewContainerRef, ViewEncapsulation, getDebugNode} from '@angular/core';
import {DebugContext, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, asProviderData, asTextData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, ngContentDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {inject} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {createRootView, isBrowser} from './helper';
@ -104,14 +103,18 @@ export function main() {
it('should include projected nodes when attaching / detaching embedded views', () => {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(hostElDef([textDef(0, ['a'])], [
elementDef(NodeFlags.None, null, null, 1, 'div'),
anchorDef(NodeFlags.HasEmbeddedViews, null, 0, 0, embeddedViewDef([ngContentDef(null, 0)])),
anchorDef(NodeFlags.HasEmbeddedViews, null, 0, 0, embeddedViewDef([
ngContentDef(null, 0),
// The anchor would be added by the compiler after the ngContent
anchorDef(NodeFlags.None, null, null, 0),
])),
])));
const componentView = asProviderData(view, 1).componentView;
const view0 = Services.createEmbeddedView(componentView, componentView.def.nodes[1]);
attachEmbeddedView(asElementData(componentView, 1), 0, view0);
expect(getDOM().childNodes(getDOM().firstChild(rootNodes[0])).length).toBe(2);
expect(getDOM().childNodes(getDOM().firstChild(rootNodes[0])).length).toBe(3);
expect(getDOM().childNodes(getDOM().firstChild(rootNodes[0]))[1])
.toBe(asTextData(view, 2).renderText);