feat: RendererV2 integration (#14469)
This commit is contained in:

committed by
Igor Minar

parent
b4d444a0a7
commit
bb9c7ae6e7
@ -92,6 +92,8 @@ export const __core_private__: {
|
||||
makeDecorator: typeof decorators.makeDecorator,
|
||||
DebugDomRootRenderer: typeof debug.DebugDomRootRenderer,
|
||||
_DebugDomRootRenderer: debug.DebugDomRootRenderer,
|
||||
DebugDomRendererV2: typeof debug.DebugDomRendererV2,
|
||||
_DebugDomRendererV2: debug.DebugDomRendererV2,
|
||||
Console: typeof console.Console,
|
||||
_Console: console.Console,
|
||||
reflector: typeof reflection.reflector,
|
||||
@ -101,9 +103,6 @@ export const __core_private__: {
|
||||
_NoOpAnimationPlayer: NoOpAnimationPlayer_,
|
||||
AnimationPlayer: typeof AnimationPlayer_,
|
||||
_AnimationPlayer: AnimationPlayer_,
|
||||
|
||||
|
||||
|
||||
AnimationSequencePlayer: typeof AnimationSequencePlayer_,
|
||||
_AnimationSequencePlayer: AnimationSequencePlayer_,
|
||||
AnimationGroupPlayer: typeof AnimationGroupPlayer_,
|
||||
@ -157,6 +156,7 @@ export const __core_private__: {
|
||||
ReflectionCapabilities: reflection_capabilities.ReflectionCapabilities,
|
||||
makeDecorator: decorators.makeDecorator,
|
||||
DebugDomRootRenderer: debug.DebugDomRootRenderer,
|
||||
DebugDomRendererV2: debug.DebugDomRendererV2,
|
||||
Console: console.Console,
|
||||
reflector: reflection.reflector,
|
||||
Reflector: reflection.Reflector,
|
||||
|
@ -85,16 +85,26 @@ export class DebugElement extends DebugNode {
|
||||
insertChildrenAfter(child: DebugNode, newChildren: DebugNode[]) {
|
||||
const siblingIndex = this.childNodes.indexOf(child);
|
||||
if (siblingIndex !== -1) {
|
||||
const previousChildren = this.childNodes.slice(0, siblingIndex + 1);
|
||||
const nextChildren = this.childNodes.slice(siblingIndex + 1);
|
||||
this.childNodes = previousChildren.concat(newChildren, nextChildren);
|
||||
for (let i = 0; i < newChildren.length; ++i) {
|
||||
const newChild = newChildren[i];
|
||||
if (newChild.parent) {
|
||||
newChild.parent.removeChild(newChild);
|
||||
this.childNodes.splice(siblingIndex + 1, 0, ...newChildren);
|
||||
newChildren.forEach(c => {
|
||||
if (c.parent) {
|
||||
c.parent.removeChild(c);
|
||||
}
|
||||
newChild.parent = this;
|
||||
c.parent = this;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
insertBefore(refChild: DebugNode, newChild: DebugNode): void {
|
||||
const refIndex = this.childNodes.indexOf(refChild);
|
||||
if (refIndex === -1) {
|
||||
this.addChild(newChild);
|
||||
} else {
|
||||
if (newChild.parent) {
|
||||
newChild.parent.removeChild(newChild);
|
||||
}
|
||||
newChild.parent = this;
|
||||
this.childNodes.splice(refIndex, 0, newChild);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import {AnimationKeyframe} from '../animation/animation_keyframe';
|
||||
import {AnimationPlayer} from '../animation/animation_player';
|
||||
import {AnimationStyles} from '../animation/animation_styles';
|
||||
import {isPresent} from '../facade/lang';
|
||||
import {RenderComponentType, RenderDebugInfo, Renderer, RootRenderer} from '../render/api';
|
||||
import {RenderComponentType, RenderDebugInfo, Renderer, RendererV2, RootRenderer} from '../render/api';
|
||||
|
||||
import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from './debug_node';
|
||||
|
||||
@ -22,7 +22,7 @@ export class DebugDomRootRenderer implements RootRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
export class DebugDomRenderer {
|
||||
export class DebugDomRenderer implements Renderer {
|
||||
constructor(private _delegate: Renderer) {}
|
||||
|
||||
selectRootElement(selectorOrNode: string|any, debugInfo?: RenderDebugInfo): any {
|
||||
@ -81,7 +81,7 @@ export class DebugDomRenderer {
|
||||
detachView(viewRootNodes: any[]) {
|
||||
viewRootNodes.forEach((node) => {
|
||||
const debugNode = getDebugNode(node);
|
||||
if (isPresent(debugNode) && isPresent(debugNode.parent)) {
|
||||
if (debugNode && debugNode.parent) {
|
||||
debugNode.parent.removeChild(debugNode);
|
||||
}
|
||||
});
|
||||
@ -156,3 +156,151 @@ export class DebugDomRenderer {
|
||||
element, startingStyles, keyframes, duration, delay, easing, previousPlayers);
|
||||
}
|
||||
}
|
||||
|
||||
export class DebugDomRendererV2 implements RendererV2 {
|
||||
constructor(private _delegate: RendererV2) {}
|
||||
|
||||
createElement(name: string, namespace?: string, debugInfo?: any): any {
|
||||
const el = this._delegate.createElement(name, namespace, debugInfo);
|
||||
const debugEl = new DebugElement(el, null, debugInfo);
|
||||
debugEl.name = name;
|
||||
indexDebugNode(debugEl);
|
||||
return el;
|
||||
}
|
||||
|
||||
createComment(value: string, debugInfo?: any): any {
|
||||
const comment = this._delegate.createComment(value, debugInfo);
|
||||
const debugEl = new DebugNode(comment, null, debugInfo);
|
||||
indexDebugNode(debugEl);
|
||||
return comment;
|
||||
}
|
||||
|
||||
createText(value: string, debugInfo?: any): any {
|
||||
const text = this._delegate.createText(value, debugInfo);
|
||||
const debugEl = new DebugNode(text, null, debugInfo);
|
||||
indexDebugNode(debugEl);
|
||||
return text;
|
||||
}
|
||||
|
||||
appendChild(parent: any, newChild: any): void {
|
||||
const debugEl = getDebugNode(parent);
|
||||
const debugChildEl = getDebugNode(newChild);
|
||||
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
|
||||
debugEl.addChild(debugChildEl);
|
||||
}
|
||||
this._delegate.appendChild(parent, newChild);
|
||||
}
|
||||
|
||||
insertBefore(parent: any, newChild: any, refChild: any): void {
|
||||
const debugEl = getDebugNode(parent);
|
||||
const debugChildEl = getDebugNode(newChild);
|
||||
const debugRefEl = getDebugNode(refChild);
|
||||
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
|
||||
debugEl.insertBefore(debugRefEl, debugChildEl);
|
||||
}
|
||||
|
||||
this._delegate.insertBefore(parent, newChild, refChild);
|
||||
}
|
||||
|
||||
removeChild(parent: any, oldChild: any): void {
|
||||
const debugEl = getDebugNode(parent);
|
||||
const debugChildEl = getDebugNode(oldChild);
|
||||
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
|
||||
debugEl.removeChild(debugChildEl);
|
||||
}
|
||||
this._delegate.removeChild(parent, oldChild);
|
||||
}
|
||||
|
||||
selectRootElement(selectorOrNode: string|any, debugInfo?: any): any {
|
||||
const el = this._delegate.selectRootElement(selectorOrNode, debugInfo);
|
||||
const debugEl = new DebugElement(el, null, debugInfo);
|
||||
indexDebugNode(debugEl);
|
||||
return el;
|
||||
}
|
||||
|
||||
parentNode(node: any): any { return this._delegate.parentNode(node); }
|
||||
|
||||
nextSibling(node: any): any { return this._delegate.nextSibling(node); }
|
||||
|
||||
setAttribute(el: any, name: string, value: string, namespace?: string): void {
|
||||
const debugEl = getDebugNode(el);
|
||||
if (debugEl && debugEl instanceof DebugElement) {
|
||||
const fullName = namespace ? namespace + ':' + name : name;
|
||||
debugEl.attributes[fullName] = value;
|
||||
}
|
||||
this._delegate.setAttribute(el, name, value, namespace);
|
||||
}
|
||||
|
||||
removeAttribute(el: any, name: string, namespace?: string): void {
|
||||
const debugEl = getDebugNode(el);
|
||||
if (debugEl && debugEl instanceof DebugElement) {
|
||||
const fullName = namespace ? namespace + ':' + name : name;
|
||||
debugEl.attributes[fullName] = null;
|
||||
}
|
||||
this._delegate.removeAttribute(el, name, namespace);
|
||||
}
|
||||
|
||||
setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void {
|
||||
this._delegate.setBindingDebugInfo(el, propertyName, propertyValue);
|
||||
}
|
||||
|
||||
removeBindingDebugInfo(el: any, propertyName: string): void {
|
||||
this._delegate.removeBindingDebugInfo(el, propertyName);
|
||||
}
|
||||
|
||||
addClass(el: any, name: string): void {
|
||||
const debugEl = getDebugNode(el);
|
||||
if (debugEl && debugEl instanceof DebugElement) {
|
||||
debugEl.classes[name] = true;
|
||||
}
|
||||
this._delegate.addClass(el, name);
|
||||
}
|
||||
|
||||
removeClass(el: any, name: string): void {
|
||||
const debugEl = getDebugNode(el);
|
||||
if (debugEl && debugEl instanceof DebugElement) {
|
||||
debugEl.classes[name] = false;
|
||||
}
|
||||
this._delegate.removeClass(el, name);
|
||||
}
|
||||
|
||||
setStyle(el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean):
|
||||
void {
|
||||
const debugEl = getDebugNode(el);
|
||||
if (debugEl && debugEl instanceof DebugElement) {
|
||||
debugEl.styles[style] = value;
|
||||
}
|
||||
this._delegate.setStyle(el, style, value, hasVendorPrefix, hasImportant);
|
||||
}
|
||||
|
||||
removeStyle(el: any, style: string, hasVendorPrefix: boolean): void {
|
||||
const debugEl = getDebugNode(el);
|
||||
if (debugEl && debugEl instanceof DebugElement) {
|
||||
debugEl.styles[style] = null;
|
||||
}
|
||||
this._delegate.removeStyle(el, style, hasVendorPrefix);
|
||||
}
|
||||
|
||||
setProperty(el: any, name: string, value: any): void {
|
||||
const debugEl = getDebugNode(el);
|
||||
if (debugEl && debugEl instanceof DebugElement) {
|
||||
debugEl.properties[name] = value;
|
||||
}
|
||||
this._delegate.setProperty(el, name, value);
|
||||
}
|
||||
|
||||
setText(node: any, value: string): void { this._delegate.setText(node, value); }
|
||||
|
||||
listen(
|
||||
target: 'document'|'windows'|'body'|any, eventName: string,
|
||||
callback: (event: any) => boolean): () => void {
|
||||
if (typeof target !== 'string') {
|
||||
const debugEl = getDebugNode(target);
|
||||
if (debugEl) {
|
||||
debugEl.listeners.push(new EventListener(eventName, callback));
|
||||
}
|
||||
}
|
||||
|
||||
return this._delegate.listen(target, eventName, callback);
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Type} from './type';
|
||||
import {DebugContext} from './view';
|
||||
|
||||
export const ERROR_TYPE = 'ngType';
|
||||
|
@ -80,8 +80,8 @@ export class ViewContainer {
|
||||
return result;
|
||||
}
|
||||
|
||||
moveView(view: AppView<any>, currentIndex: number) {
|
||||
const previousIndex = this.nestedViews.indexOf(view);
|
||||
moveView(view: AppView<any>, toIndex: number) {
|
||||
const fromIndex = this.nestedViews.indexOf(view);
|
||||
if (view.type === ViewType.COMPONENT) {
|
||||
throw new Error(`Component views can't be moved!`);
|
||||
}
|
||||
@ -90,9 +90,9 @@ export class ViewContainer {
|
||||
nestedViews = [];
|
||||
this.nestedViews = nestedViews;
|
||||
}
|
||||
nestedViews.splice(previousIndex, 1);
|
||||
nestedViews.splice(currentIndex, 0, view);
|
||||
const prevView = currentIndex > 0 ? nestedViews[currentIndex - 1] : null;
|
||||
nestedViews.splice(fromIndex, 1);
|
||||
nestedViews.splice(toIndex, 0, view);
|
||||
const prevView = toIndex > 0 ? nestedViews[toIndex - 1] : null;
|
||||
view.moveAfter(this, prevView);
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import {Injector} from '../di/injector';
|
||||
import {isPresent} from '../facade/lang';
|
||||
import {WtfScopeFn, wtfCreateScope, wtfLeave} from '../profile/profile';
|
||||
|
||||
import {ComponentFactory, ComponentRef} from './component_factory';
|
||||
@ -133,7 +132,7 @@ export class ViewContainerRef_ implements ViewContainerRef {
|
||||
get(index: number): ViewRef { return this._element.nestedViews[index].ref; }
|
||||
get length(): number {
|
||||
const views = this._element.nestedViews;
|
||||
return isPresent(views) ? views.length : 0;
|
||||
return views ? views.length : 0;
|
||||
}
|
||||
|
||||
get element(): ElementRef { return this._element.elementRef; }
|
||||
|
@ -7,4 +7,4 @@
|
||||
*/
|
||||
|
||||
// Public API for render
|
||||
export {RenderComponentType, Renderer, RootRenderer} from './render/api';
|
||||
export {RENDERER_V2_DIRECT, RenderComponentType, Renderer, RendererV2, RootRenderer} from './render/api';
|
||||
|
@ -9,9 +9,16 @@
|
||||
import {AnimationKeyframe} from '../../src/animation/animation_keyframe';
|
||||
import {AnimationPlayer} from '../../src/animation/animation_player';
|
||||
import {AnimationStyles} from '../../src/animation/animation_styles';
|
||||
import {Injector} from '../di/injector';
|
||||
import {InjectionToken, Injector} from '../di';
|
||||
import {ViewEncapsulation} from '../metadata/view';
|
||||
|
||||
/**
|
||||
* Provide a concrete implementation of {@link RendererV2}
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
export const RENDERER_V2_DIRECT = new InjectionToken<RendererV2>('Renderer V2');
|
||||
|
||||
/**
|
||||
* @experimental
|
||||
*/
|
||||
@ -91,6 +98,56 @@ export abstract class Renderer {
|
||||
previousPlayers?: AnimationPlayer[]): AnimationPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @experimental
|
||||
*/
|
||||
export abstract class RendererV2 {
|
||||
abstract createElement(name: string, namespace?: string, debugInfo?: RenderDebugContext): any;
|
||||
abstract createComment(value: string, debugInfo?: RenderDebugContext): any;
|
||||
abstract createText(value: string, debugInfo?: RenderDebugContext): any;
|
||||
abstract appendChild(parent: any, newChild: any): void;
|
||||
abstract insertBefore(parent: any, newChild: any, refChild: any): void;
|
||||
abstract removeChild(parent: any, oldChild: any): void;
|
||||
abstract selectRootElement(selectorOrNode: string|any, debugInfo?: RenderDebugContext): any;
|
||||
/**
|
||||
* Attention: On WebWorkers, this will always return a value,
|
||||
* as we are asking for a result synchronously. I.e.
|
||||
* the caller can't rely on checking whether this is null or not.
|
||||
*/
|
||||
abstract parentNode(node: any): any;
|
||||
/**
|
||||
* Attention: On WebWorkers, this will always return a value,
|
||||
* as we are asking for a result synchronously. I.e.
|
||||
* the caller can't rely on checking whether this is null or not.
|
||||
*/
|
||||
abstract nextSibling(node: any): any;
|
||||
abstract setAttribute(el: any, name: string, value: string, namespace?: string): void;
|
||||
abstract removeAttribute(el: any, name: string, namespace?: string): void;
|
||||
abstract setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void;
|
||||
abstract removeBindingDebugInfo(el: any, propertyName: string): void;
|
||||
abstract addClass(el: any, name: string): void;
|
||||
abstract removeClass(el: any, name: string): void;
|
||||
abstract setStyle(
|
||||
el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean): void;
|
||||
abstract removeStyle(el: any, style: string, hasVendorPrefix: boolean): void;
|
||||
abstract setProperty(el: any, name: string, value: any): void;
|
||||
abstract setText(node: any, value: string): void;
|
||||
abstract listen(
|
||||
target: 'window'|'document'|'body'|any, eventName: string,
|
||||
callback: (event: any) => boolean): () => void;
|
||||
}
|
||||
|
||||
export abstract class RenderDebugContext {
|
||||
abstract get injector(): Injector;
|
||||
abstract get component(): any;
|
||||
abstract get providerTokens(): any[];
|
||||
abstract get references(): {[key: string]: any};
|
||||
abstract get context(): any;
|
||||
abstract get source(): string;
|
||||
abstract get componentRenderElement(): any;
|
||||
abstract get renderNode(): any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injectable service that provides a low-level interface for modifying the UI.
|
||||
*
|
||||
|
@ -137,7 +137,13 @@ export function createElement(view: ViewData, renderHost: any, def: NodeDef): El
|
||||
if (view.parent || !rootSelectorOrNode) {
|
||||
const parentNode =
|
||||
def.parent != null ? asElementData(view, def.parent).renderElement : renderHost;
|
||||
el = elDef.name ? renderer.createElement(elDef.name) : renderer.createComment('');
|
||||
if (elDef.name) {
|
||||
// TODO(vicb): move the namespace to the node definition
|
||||
const nsAndName = splitNamespace(elDef.name);
|
||||
el = renderer.createElement(nsAndName[1], nsAndName[0]);
|
||||
} else {
|
||||
el = renderer.createComment('');
|
||||
}
|
||||
if (parentNode) {
|
||||
renderer.appendChild(parentNode, el);
|
||||
}
|
||||
@ -146,7 +152,9 @@ export function createElement(view: ViewData, renderHost: any, def: NodeDef): El
|
||||
}
|
||||
if (elDef.attrs) {
|
||||
for (let attrName in elDef.attrs) {
|
||||
renderer.setAttribute(el, attrName, elDef.attrs[attrName]);
|
||||
// TODO(vicb): move the namespace to the node definition
|
||||
const nsAndName = splitNamespace(attrName);
|
||||
renderer.setAttribute(el, nsAndName[1], elDef.attrs[attrName], nsAndName[0]);
|
||||
}
|
||||
}
|
||||
if (elDef.outputs.length) {
|
||||
@ -234,10 +242,12 @@ function setElementAttribute(
|
||||
let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value;
|
||||
renderValue = renderValue != null ? renderValue.toString() : null;
|
||||
const renderer = view.root.renderer;
|
||||
// TODO(vicb): move the namespace to the node definition
|
||||
const nsAndName = splitNamespace(name);
|
||||
if (value != null) {
|
||||
renderer.setAttribute(renderNode, name, renderValue);
|
||||
renderer.setAttribute(renderNode, nsAndName[1], renderValue, nsAndName[0]);
|
||||
} else {
|
||||
renderer.removeAttribute(renderNode, name);
|
||||
renderer.removeAttribute(renderNode, nsAndName[1], nsAndName[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,9 +274,9 @@ function setElementStyle(
|
||||
}
|
||||
const renderer = view.root.renderer;
|
||||
if (renderValue != null) {
|
||||
renderer.setStyle(renderNode, name, renderValue);
|
||||
renderer.setStyle(renderNode, name, renderValue, false, false);
|
||||
} else {
|
||||
renderer.removeStyle(renderNode, name);
|
||||
renderer.removeStyle(renderNode, name, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,3 +286,13 @@ function setElementProperty(
|
||||
let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value;
|
||||
view.root.renderer.setProperty(renderNode, name, renderValue);
|
||||
}
|
||||
|
||||
const NS_PREFIX_RE = /^:([^:]+):(.+)$/;
|
||||
|
||||
function splitNamespace(name: string): string[] {
|
||||
if (name[0] === ':') {
|
||||
const match = name.match(NS_PREFIX_RE);
|
||||
return [match[1], match[2]];
|
||||
}
|
||||
return ['', name];
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import {ElementRef} from '../linker/element_ref';
|
||||
import {TemplateRef} from '../linker/template_ref';
|
||||
import {ViewContainerRef} from '../linker/view_container_ref';
|
||||
import * as v1renderer from '../render/api';
|
||||
import {Type} from '../type';
|
||||
|
||||
import {createChangeDetectorRef, createInjector, createTemplateRef, createViewContainerRef} from './refs';
|
||||
import {BindingDef, BindingType, DepDef, DepFlags, DirectiveOutputDef, DisposableFn, NodeData, NodeDef, NodeFlags, NodeType, ProviderData, ProviderType, QueryBindingType, QueryDef, QueryValueType, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewState, asElementData, asProviderData} from './types';
|
||||
|
@ -6,20 +6,16 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {isDevMode} from '../application_ref';
|
||||
import {ChangeDetectorRef} from '../change_detection/change_detection';
|
||||
import {Injectable, Injector} from '../di';
|
||||
import {Injector} from '../di';
|
||||
import {ComponentFactory, ComponentRef} from '../linker/component_factory';
|
||||
import {ElementRef} from '../linker/element_ref';
|
||||
import {TemplateRef} from '../linker/template_ref';
|
||||
import {ViewContainerRef} from '../linker/view_container_ref';
|
||||
import {EmbeddedViewRef, ViewRef} from '../linker/view_ref';
|
||||
import * as v1renderer from '../render/api';
|
||||
import {Sanitizer, SecurityContext} from '../security';
|
||||
import {Type} from '../type';
|
||||
|
||||
import {DirectDomRenderer, LegacyRendererAdapter} from './renderer';
|
||||
import {ArgumentType, BindingType, DebugContext, DepFlags, ElementData, NodeCheckFn, NodeData, NodeDef, NodeFlags, NodeType, RendererV2, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewState, asElementData, asProviderData} from './types';
|
||||
import {ArgumentType, BindingType, DebugContext, DepFlags, ElementData, NodeCheckFn, NodeData, NodeDef, NodeFlags, NodeType, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewState, asElementData, asProviderData} from './types';
|
||||
import {isComponentView, renderNode, resolveViewDefinition, rootRenderNodes, tokenKey, viewParentElIndex} from './util';
|
||||
|
||||
const EMPTY_CONTEXT = new Object();
|
||||
|
@ -1,147 +0,0 @@
|
||||
/**
|
||||
* @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 {ViewEncapsulation} from '../metadata/view';
|
||||
import * as v1 from '../render/api';
|
||||
|
||||
import {DebugContext, RendererV2} from './types';
|
||||
|
||||
export class DirectDomRenderer implements RendererV2 {
|
||||
createElement(name: string): any { return document.createElement(name); }
|
||||
createComment(value: string): any { return document.createComment(value); }
|
||||
createText(value: string): any { return document.createTextNode(value); }
|
||||
appendChild(parent: any, newChild: any): void { parent.appendChild(newChild); }
|
||||
insertBefore(parent: any, newChild: any, refChild: any): void {
|
||||
if (parent) {
|
||||
parent.insertBefore(newChild, refChild);
|
||||
}
|
||||
}
|
||||
removeChild(parent: any, oldChild: any): void {
|
||||
if (parent) {
|
||||
parent.removeChild(oldChild);
|
||||
}
|
||||
}
|
||||
selectRootElement(selectorOrNode: string|any, debugInfo?: DebugContext): any {
|
||||
let el: any;
|
||||
if (typeof selectorOrNode === 'string') {
|
||||
el = document.querySelector(selectorOrNode);
|
||||
} else {
|
||||
el = selectorOrNode;
|
||||
}
|
||||
el.textContent = '';
|
||||
return el;
|
||||
}
|
||||
parentNode(node: any): any { return node.parentNode; }
|
||||
nextSibling(node: any): any { return node.nextSiblibng; }
|
||||
setAttribute(el: any, name: string, value: string): void { return el.setAttribute(name, value); }
|
||||
removeAttribute(el: any, name: string): void { el.removeAttribute(name); }
|
||||
setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void {}
|
||||
removeBindingDebugInfo(el: any, propertyName: string): void {}
|
||||
addClass(el: any, name: string): void { el.classList.add(name); }
|
||||
removeClass(el: any, name: string): void { el.classList.remove(name); }
|
||||
setStyle(el: any, style: string, value: any): void { el.style[style] = value; }
|
||||
removeStyle(el: any, style: string): void {
|
||||
// IE requires '' instead of null
|
||||
// see https://github.com/angular/angular/issues/7916
|
||||
(el.style as any)[style] = '';
|
||||
}
|
||||
setProperty(el: any, name: string, value: any): void { el[name] = value; }
|
||||
setText(node: any, value: string): void { node.nodeValue = value; }
|
||||
listen(target: any, eventName: string, callback: (event: any) => boolean): () => void {
|
||||
let renderTarget: any;
|
||||
switch (target) {
|
||||
case 'window':
|
||||
renderTarget = window;
|
||||
break;
|
||||
case 'document':
|
||||
renderTarget = document;
|
||||
break;
|
||||
default:
|
||||
renderTarget = target;
|
||||
}
|
||||
const closure = (event: any) => {
|
||||
if (callback(event) === false) {
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
renderTarget.addEventListener(eventName, closure);
|
||||
return () => renderTarget.removeEventListener(eventName, closure);
|
||||
}
|
||||
}
|
||||
|
||||
const EMPTY_V1_RENDER_COMPONENT_TYPE =
|
||||
new v1.RenderComponentType('EMPTY', '', 0, ViewEncapsulation.None, [], {});
|
||||
|
||||
/**
|
||||
* A temporal implementation of `Renderer` until we migrated our current renderer
|
||||
* in all packages to the new API.
|
||||
*
|
||||
* Note that this is not complete, e.g. does not support shadow dom, view encapsulation, ...!
|
||||
*/
|
||||
export class LegacyRendererAdapter implements RendererV2 {
|
||||
private _delegate: v1.Renderer;
|
||||
constructor(rootDelegate: v1.RootRenderer) {
|
||||
this._delegate = rootDelegate.renderComponent(EMPTY_V1_RENDER_COMPONENT_TYPE);
|
||||
}
|
||||
createElement(name: string, debugInfo?: DebugContext): any {
|
||||
return this._delegate.createElement(null, name, debugInfo);
|
||||
}
|
||||
createComment(value: string, debugInfo?: DebugContext): any {
|
||||
return this._delegate.createTemplateAnchor(null, debugInfo);
|
||||
}
|
||||
createText(value: string, debugInfo?: DebugContext): any {
|
||||
return this._delegate.createText(null, value, debugInfo);
|
||||
}
|
||||
appendChild(parent: any, newChild: any): void { this._delegate.projectNodes(parent, [newChild]); }
|
||||
insertBefore(parent: any, newChild: any, refChild: any): void {
|
||||
if (refChild) {
|
||||
this._delegate.attachViewAfter(refChild.previousSibling, [newChild]);
|
||||
} else {
|
||||
this.appendChild(parent, newChild);
|
||||
}
|
||||
}
|
||||
removeChild(parent: any, oldChild: any): void {
|
||||
if (parent) {
|
||||
this._delegate.detachView([oldChild]);
|
||||
}
|
||||
}
|
||||
selectRootElement(selectorOrNode: any, debugInfo?: DebugContext): any {
|
||||
return this._delegate.selectRootElement(selectorOrNode, debugInfo);
|
||||
}
|
||||
parentNode(node: any): any { return node.parentNode; }
|
||||
nextSibling(node: any): any { return node.nextSibling; }
|
||||
setAttribute(el: any, name: string, value: string): void {
|
||||
this._delegate.setElementAttribute(el, name, value);
|
||||
}
|
||||
removeAttribute(el: any, name: string): void {
|
||||
this._delegate.setElementAttribute(el, name, null);
|
||||
}
|
||||
setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void {
|
||||
this._delegate.setBindingDebugInfo(el, propertyName, propertyValue);
|
||||
}
|
||||
removeBindingDebugInfo(el: any, propertyName: string): void {
|
||||
this._delegate.setBindingDebugInfo(el, propertyName, null);
|
||||
}
|
||||
addClass(el: any, name: string): void { this._delegate.setElementClass(el, name, true); }
|
||||
removeClass(el: any, name: string): void { this._delegate.setElementClass(el, name, false); }
|
||||
setStyle(el: any, style: string, value: any): void {
|
||||
this._delegate.setElementStyle(el, style, value);
|
||||
}
|
||||
removeStyle(el: any, style: string): void { this._delegate.setElementStyle(el, style, null); }
|
||||
setProperty(el: any, name: string, value: any): void {
|
||||
this._delegate.setElementProperty(el, name, value);
|
||||
}
|
||||
setText(node: any, value: string): void { this._delegate.setText(node, value); }
|
||||
listen(target: any, eventName: string, callback: (event: any) => boolean): () => void {
|
||||
if (typeof target === 'string') {
|
||||
return <any>this._delegate.listenGlobal(target, eventName, callback);
|
||||
} else {
|
||||
return <any>this._delegate.listen(target, eventName, callback);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,20 +7,16 @@
|
||||
*/
|
||||
|
||||
import {isDevMode} from '../application_ref';
|
||||
import {Injectable, Injector} from '../di';
|
||||
import {looseIdentical} from '../facade/lang';
|
||||
import {ElementRef} from '../linker/element_ref';
|
||||
import * as v1renderer from '../render/api';
|
||||
import {Injector} from '../di';
|
||||
import {RendererV2} from '../render/api';
|
||||
import {Sanitizer, SecurityContext} from '../security';
|
||||
import {Type} from '../type';
|
||||
|
||||
import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors';
|
||||
import {resolveDep} from './provider';
|
||||
import {getQueryValue} from './query';
|
||||
import {createInjector} from './refs';
|
||||
import {DirectDomRenderer, LegacyRendererAdapter} from './renderer';
|
||||
import {ArgumentType, BindingType, DebugContext, DepFlags, ElementData, NodeCheckFn, NodeData, NodeDef, NodeFlags, NodeType, RendererV2, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewState, ViewUpdateFn, asElementData, asProviderData} from './types';
|
||||
import {checkBinding, isComponentView, queryIdIsReference, renderNode, resolveViewDefinition, rootRenderNodes, viewParentElIndex} from './util';
|
||||
import {ArgumentType, BindingType, DebugContext, DepFlags, ElementData, NodeCheckFn, NodeData, NodeDef, NodeFlags, NodeType, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewState, asElementData, asProviderData} from './types';
|
||||
import {checkBinding, isComponentView, queryIdIsReference, renderNode, viewParentElIndex} from './util';
|
||||
import {checkAndUpdateView, checkNoChangesView, createEmbeddedView, createRootView, destroyView} from './view';
|
||||
import {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach';
|
||||
|
||||
@ -112,10 +108,8 @@ function debugCreateRootView(
|
||||
function createRootData(
|
||||
injector: Injector, projectableNodes: any[][], rootSelectorOrNode: any): RootData {
|
||||
const sanitizer = injector.get(Sanitizer);
|
||||
// TODO(tbosch): once the new renderer interface is implemented via platform-browser,
|
||||
// just get it via the injector and drop LegacyRendererAdapter and DirectDomRenderer.
|
||||
const renderer = isDevMode() ? new LegacyRendererAdapter(injector.get(v1renderer.RootRenderer)) :
|
||||
new DirectDomRenderer();
|
||||
const renderer = injector.get(RendererV2);
|
||||
|
||||
const rootElement =
|
||||
rootSelectorOrNode ? renderer.selectRootElement(rootSelectorOrNode) : undefined;
|
||||
return {injector, projectableNodes, selectorOrNode: rootSelectorOrNode, sanitizer, renderer};
|
||||
@ -183,7 +177,7 @@ function debugUpdateRenderer(check: NodeCheckFn, view: ViewData) {
|
||||
const result = debugCheckFn(check, view, nodeIndex, argStyle, values);
|
||||
debugSetCurrentNode(view, nextRenderNodeWithBinding(view, nodeIndex));
|
||||
return result;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function debugCheckFn(
|
||||
@ -249,8 +243,9 @@ function nextRenderNodeWithBinding(view: ViewData, nodeIndex: number): number {
|
||||
|
||||
class DebugRenderer implements RendererV2 {
|
||||
constructor(private _delegate: RendererV2) {}
|
||||
createElement(name: string): any {
|
||||
return this._delegate.createElement(name, getCurrentDebugContext());
|
||||
|
||||
createElement(name: string, namespace?: string): any {
|
||||
return this._delegate.createElement(name, namespace, getCurrentDebugContext());
|
||||
}
|
||||
createComment(value: string): any {
|
||||
return this._delegate.createComment(value, getCurrentDebugContext());
|
||||
@ -272,10 +267,12 @@ class DebugRenderer implements RendererV2 {
|
||||
}
|
||||
parentNode(node: any): any { return this._delegate.parentNode(node); }
|
||||
nextSibling(node: any): any { return this._delegate.nextSibling(node); }
|
||||
setAttribute(el: any, name: string, value: string): void {
|
||||
return this._delegate.setAttribute(el, name, value);
|
||||
setAttribute(el: any, name: string, value: string, namespace?: string): void {
|
||||
return this._delegate.setAttribute(el, name, value, namespace);
|
||||
}
|
||||
removeAttribute(el: any, name: string, namespace?: string): void {
|
||||
return this._delegate.removeAttribute(el, name, namespace);
|
||||
}
|
||||
removeAttribute(el: any, name: string): void { return this._delegate.removeAttribute(el, name); }
|
||||
setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void {
|
||||
this._delegate.setBindingDebugInfo(el, propertyName, propertyValue);
|
||||
}
|
||||
@ -284,16 +281,20 @@ class DebugRenderer implements RendererV2 {
|
||||
}
|
||||
addClass(el: any, name: string): void { return this._delegate.addClass(el, name); }
|
||||
removeClass(el: any, name: string): void { return this._delegate.removeClass(el, name); }
|
||||
setStyle(el: any, style: string, value: any): void {
|
||||
return this._delegate.setStyle(el, style, value);
|
||||
setStyle(el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean):
|
||||
void {
|
||||
return this._delegate.setStyle(el, style, value, hasVendorPrefix, hasImportant);
|
||||
}
|
||||
removeStyle(el: any, style: string, hasVendorPrefix: boolean): void {
|
||||
return this._delegate.removeStyle(el, style, hasVendorPrefix);
|
||||
}
|
||||
removeStyle(el: any, style: string): void { return this._delegate.removeStyle(el, style); }
|
||||
setProperty(el: any, name: string, value: any): void {
|
||||
return this._delegate.setProperty(el, name, value);
|
||||
}
|
||||
setText(node: any, value: string): void { return this._delegate.setText(node, value); }
|
||||
listen(target: 'window'|'document'|any, eventName: string, callback: (event: any) => boolean):
|
||||
() => void {
|
||||
listen(
|
||||
target: 'window'|'document'|'body'|any, eventName: string,
|
||||
callback: (event: any) => boolean): () => void {
|
||||
return this._delegate.listen(target, eventName, callback);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import {TemplateRef} from '../linker/template_ref';
|
||||
import {ViewContainerRef} from '../linker/view_container_ref';
|
||||
import {ViewRef} from '../linker/view_ref';
|
||||
import {ViewEncapsulation} from '../metadata/view';
|
||||
import {RenderDebugContext, RendererV2} from '../render/api';
|
||||
import {Sanitizer, SecurityContext} from '../security';
|
||||
|
||||
// -------------------------------------
|
||||
@ -408,61 +409,6 @@ export interface RootData {
|
||||
sanitizer: Sanitizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(tbosch): move this interface into @angular/core/src/render/api,
|
||||
* and implement it in @angular/platform-browser, ...
|
||||
*/
|
||||
export interface RendererV2 {
|
||||
createElement(name: string, debugInfo?: RenderDebugContext): any;
|
||||
createComment(value: string, debugInfo?: RenderDebugContext): any;
|
||||
createText(value: string, debugInfo?: RenderDebugContext): any;
|
||||
appendChild(parent: any, newChild: any): void;
|
||||
insertBefore(parent: any, newChild: any, refChild: any): void;
|
||||
removeChild(parent: any, oldChild: any): void;
|
||||
selectRootElement(selectorOrNode: string|any, debugInfo?: RenderDebugContext): any;
|
||||
/**
|
||||
* Attention: On WebWorkers, this will always return a value,
|
||||
* as we are asking for a result synchronously. I.e.
|
||||
* the caller can't rely on checking whether this is null or not.
|
||||
*/
|
||||
parentNode(node: any): any;
|
||||
/**
|
||||
* Attention: On WebWorkers, this will always return a value,
|
||||
* as we are asking for a result synchronously. I.e.
|
||||
* the caller can't rely on checking whether this is null or not.
|
||||
*/
|
||||
nextSibling(node: any): any;
|
||||
/**
|
||||
* Used only in debug mode to serialize property changes to dom nodes as attributes.
|
||||
*/
|
||||
setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void;
|
||||
/**
|
||||
* Used only in debug mode to serialize property changes to dom nodes as attributes.
|
||||
*/
|
||||
removeBindingDebugInfo(el: any, propertyName: string): void;
|
||||
setAttribute(el: any, name: string, value: string): void;
|
||||
removeAttribute(el: any, name: string): void;
|
||||
addClass(el: any, name: string): void;
|
||||
removeClass(el: any, name: string): void;
|
||||
setStyle(el: any, style: string, value: any): void;
|
||||
removeStyle(el: any, style: string): void;
|
||||
setProperty(el: any, name: string, value: any): void;
|
||||
setText(node: any, value: string): void;
|
||||
listen(target: 'window'|'document'|any, eventName: string, callback: (event: any) => boolean):
|
||||
() => void;
|
||||
}
|
||||
|
||||
export abstract class RenderDebugContext {
|
||||
abstract get injector(): Injector;
|
||||
abstract get component(): any;
|
||||
abstract get providerTokens(): any[];
|
||||
abstract get references(): {[key: string]: any};
|
||||
abstract get context(): any;
|
||||
abstract get source(): string;
|
||||
abstract get componentRenderElement(): any;
|
||||
abstract get renderNode(): any;
|
||||
}
|
||||
|
||||
export abstract class DebugContext extends RenderDebugContext {
|
||||
abstract get view(): ViewData;
|
||||
abstract get nodeIndex(): number;
|
||||
|
@ -183,6 +183,11 @@ export enum RenderNodeAction {
|
||||
|
||||
export function visitRootRenderNodes(
|
||||
view: ViewData, action: RenderNodeAction, parentNode: any, nextSibling: any, target: any[]) {
|
||||
// We need to re-compute the parent node in case the nodes have been moved around manually
|
||||
if (action === RenderNodeAction.RemoveChild) {
|
||||
parentNode = view.root.renderer.parentNode(renderNode(view, view.def.lastRootNode));
|
||||
}
|
||||
|
||||
const len = view.def.nodes.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const nodeDef = view.def.nodes[i];
|
||||
|
Reference in New Issue
Block a user