Matias Niemelä 5a582a8afd fix(ivy): ensure element removal triggers host removal animations (#28162)
Prior to this fix Ivy would not execute any animation triggers
that exist as host bindings on an element if it is removed by
the parent template.

PR Close #28162
2019-01-17 09:58:50 -08:00

168 lines
5.6 KiB
TypeScript

/**
* @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
*/
/**
* The goal here is to make sure that the browser DOM API is the Renderer.
* We do this by defining a subset of DOM API to be the renderer and than
* use that time for rendering.
*
* At runtime we can than use the DOM api directly, in server or web-worker
* it will be easy to implement such API.
*/
import {RendererStyleFlags2, RendererType2} from '../../render/api';
// TODO: cleanup once the code is merged in angular/angular
export enum RendererStyleFlags3 {
Important = 1 << 0,
DashCase = 1 << 1
}
export type Renderer3 = ObjectOrientedRenderer3 | ProceduralRenderer3;
export type GlobalTargetName = 'document' | 'window' | 'body';
export type GlobalTargetResolver = (element: any) => {
name: GlobalTargetName, target: EventTarget
};
/**
* Object Oriented style of API needed to create elements and text nodes.
*
* This is the native browser API style, e.g. operations are methods on individual objects
* like HTMLElement. With this style, no additional code is needed as a facade
* (reducing payload size).
* */
export interface ObjectOrientedRenderer3 {
createComment(data: string): RComment;
createElement(tagName: string): RElement;
createElementNS(namespace: string, tagName: string): RElement;
createTextNode(data: string): RText;
querySelector(selectors: string): RElement|null;
}
/** Returns whether the `renderer` is a `ProceduralRenderer3` */
export function isProceduralRenderer(renderer: ProceduralRenderer3 | ObjectOrientedRenderer3):
renderer is ProceduralRenderer3 {
return !!((renderer as any).listen);
}
/**
* Procedural style of API needed to create elements and text nodes.
*
* In non-native browser environments (e.g. platforms such as web-workers), this is the
* facade that enables element manipulation. This also facilitates backwards compatibility
* with Renderer2.
*/
export interface ProceduralRenderer3 {
destroy(): void;
createComment(value: string): RComment;
createElement(name: string, namespace?: string|null): RElement;
createText(value: string): RText;
/**
* This property is allowed to be null / undefined,
* in which case the view engine won't call it.
* This is used as a performance optimization for production mode.
*/
destroyNode?: ((node: RNode) => void)|null;
appendChild(parent: RElement, newChild: RNode): void;
insertBefore(parent: RNode, newChild: RNode, refChild: RNode|null): void;
removeChild(parent: RElement, oldChild: RNode, isHostElement?: boolean): void;
selectRootElement(selectorOrNode: string|any): RElement;
parentNode(node: RNode): RElement|null;
nextSibling(node: RNode): RNode|null;
setAttribute(el: RElement, name: string, value: string, namespace?: string|null): void;
removeAttribute(el: RElement, name: string, namespace?: string|null): void;
addClass(el: RElement, name: string): void;
removeClass(el: RElement, name: string): void;
setStyle(
el: RElement, style: string, value: any,
flags?: RendererStyleFlags2|RendererStyleFlags3): void;
removeStyle(el: RElement, style: string, flags?: RendererStyleFlags2|RendererStyleFlags3): void;
setProperty(el: RElement, name: string, value: any): void;
setValue(node: RText|RComment, value: string): void;
// TODO(misko): Deprecate in favor of addEventListener/removeEventListener
listen(
target: GlobalTargetName|RNode, eventName: string,
callback: (event: any) => boolean | void): () => void;
}
export interface RendererFactory3 {
createRenderer(hostElement: RElement|null, rendererType: RendererType2|null): Renderer3;
begin?(): 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. */
export interface RNode {
parentNode: RNode|null;
nextSibling: RNode|null;
removeChild(oldChild: RNode): void;
/**
* Insert a child node.
*
* Used exclusively for adding View root nodes into ViewAnchor location.
*/
insertBefore(newChild: RNode, refChild: RNode|null, isViewRoot: boolean): void;
/**
* Append a child node.
*
* Used exclusively for building up DOM which are static (ie not View roots)
*/
appendChild(newChild: RNode): RNode;
}
/**
* Subset of API needed for writing attributes, properties, and setting up
* listeners on Element.
*/
export interface RElement extends RNode {
style: RCssStyleDeclaration;
classList: RDomTokenList;
className: string;
setAttribute(name: string, value: string): void;
removeAttribute(name: string): void;
setAttributeNS(namespaceURI: string, qualifiedName: string, value: string): void;
addEventListener(type: string, listener: EventListener, useCapture?: boolean): void;
removeEventListener(type: string, listener?: EventListener, options?: boolean): void;
setProperty?(name: string, value: any): void;
}
export interface RCssStyleDeclaration {
removeProperty(propertyName: string): string;
setProperty(propertyName: string, value: string|null, priority?: string): void;
}
export interface RDomTokenList {
add(token: string): void;
remove(token: string): void;
}
export interface RText extends RNode { textContent: string|null; }
export interface RComment extends RNode { textContent: string|null; }
// Note: This hack is necessary so we don't erroneously get a circular dependency
// failure based on types.
export const unusedValueExportToPlacateAjd = 1;