perf: delete pre-view-engine core, compiler, platform-browser, etc code (#14788)
After the introduction of the view engine, we can drop a lot of code that is not used any more. This should reduce the size of the app bundles because a lot of this code was not being properly tree-shaken by today's tools even though it was dead code.
This commit is contained in:
@ -9,9 +9,6 @@
|
||||
import {CommonModule, PlatformLocation, ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID} from '@angular/common';
|
||||
import {APP_ID, ApplicationModule, ErrorHandler, ModuleWithProviders, NgModule, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, PlatformRef, Provider, RendererFactoryV2, RootRenderer, Sanitizer, SkipSelf, Testability, createPlatformFactory, platformCore} from '@angular/core';
|
||||
|
||||
import {AnimationDriver} from '../src/dom/animation_driver';
|
||||
import {WebAnimationsDriver} from '../src/dom/web_animations_driver';
|
||||
|
||||
import {BrowserDomAdapter} from './browser/browser_adapter';
|
||||
import {BrowserPlatformLocation} from './browser/location/browser_platform_location';
|
||||
import {Meta} from './browser/meta';
|
||||
@ -20,7 +17,7 @@ import {BrowserGetTestability} from './browser/testability';
|
||||
import {Title} from './browser/title';
|
||||
import {ELEMENT_PROBE_PROVIDERS} from './dom/debug/ng_probe';
|
||||
import {getDOM} from './dom/dom_adapter';
|
||||
import {DomRendererFactoryV2, DomRootRenderer, DomRootRenderer_} from './dom/dom_renderer';
|
||||
import {DomRendererFactoryV2} from './dom/dom_renderer';
|
||||
import {DOCUMENT} from './dom/dom_tokens';
|
||||
import {DomEventsPlugin} from './dom/events/dom_events';
|
||||
import {EVENT_MANAGER_PLUGINS, EventManager} from './dom/events/event_manager';
|
||||
@ -66,13 +63,6 @@ export function _document(): any {
|
||||
return document;
|
||||
}
|
||||
|
||||
export function _resolveDefaultAnimationDriver(): AnimationDriver {
|
||||
if (getDOM().supportsWebAnimation()) {
|
||||
return new WebAnimationsDriver();
|
||||
}
|
||||
return AnimationDriver.NOOP;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ng module for the browser.
|
||||
*
|
||||
@ -86,12 +76,9 @@ export function _resolveDefaultAnimationDriver(): AnimationDriver {
|
||||
{provide: EVENT_MANAGER_PLUGINS, useClass: KeyEventsPlugin, multi: true},
|
||||
{provide: EVENT_MANAGER_PLUGINS, useClass: HammerGesturesPlugin, multi: true},
|
||||
{provide: HAMMER_GESTURE_CONFIG, useClass: HammerGestureConfig},
|
||||
{provide: DomRootRenderer, useClass: DomRootRenderer_},
|
||||
{provide: RootRenderer, useExisting: DomRootRenderer},
|
||||
DomRendererFactoryV2,
|
||||
{provide: RendererFactoryV2, useExisting: DomRendererFactoryV2},
|
||||
{provide: SharedStylesHost, useExisting: DomSharedStylesHost},
|
||||
{provide: AnimationDriver, useFactory: _resolveDefaultAnimationDriver},
|
||||
DomSharedStylesHost,
|
||||
Testability,
|
||||
EventManager,
|
||||
|
@ -1,33 +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 {AnimationPlayer, ɵAnimationKeyframe as AnimationKeyframe, ɵAnimationStyles as AnimationStyles, ɵNoOpAnimationPlayer as NoOpAnimationPlayer} from '@angular/core';
|
||||
|
||||
/**
|
||||
* @experimental
|
||||
*/
|
||||
export class NoOpAnimationDriver implements AnimationDriver {
|
||||
animate(
|
||||
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
|
||||
duration: number, delay: number, easing: string,
|
||||
previousPlayers: AnimationPlayer[] = []): AnimationPlayer {
|
||||
return new NoOpAnimationPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @experimental
|
||||
*/
|
||||
export abstract class AnimationDriver {
|
||||
static NOOP: AnimationDriver = new NoOpAnimationDriver();
|
||||
abstract animate(
|
||||
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
|
||||
duration: number, delay: number, easing: string,
|
||||
previousPlayers?: AnimationPlayer[]): AnimationPlayer;
|
||||
}
|
@ -10,7 +10,6 @@ import * as core from '@angular/core';
|
||||
|
||||
import {StringMapWrapper} from '../../facade/collection';
|
||||
import {getDOM} from '../dom_adapter';
|
||||
import {DomRendererFactoryV2, DomRootRenderer} from '../dom_renderer';
|
||||
|
||||
const CORE_TOKENS = {
|
||||
'ApplicationRef': core.ApplicationRef,
|
||||
@ -37,20 +36,13 @@ export class NgProbeToken {
|
||||
constructor(public name: string, public token: any) {}
|
||||
}
|
||||
|
||||
|
||||
export function _createConditionalRootRenderer(
|
||||
rootRenderer: any, extraTokens: NgProbeToken[], coreTokens: core.NgProbeToken[]) {
|
||||
return core.isDevMode() ?
|
||||
_createRootRenderer(rootRenderer, (extraTokens || []).concat(coreTokens || [])) :
|
||||
rootRenderer;
|
||||
}
|
||||
|
||||
function _createRootRenderer(rootRenderer: any, extraTokens: NgProbeToken[]) {
|
||||
export function _createNgProbe(extraTokens: NgProbeToken[], coreTokens: core.NgProbeToken[]): any {
|
||||
const tokens = (extraTokens || []).concat(coreTokens || []);
|
||||
getDOM().setGlobalVar(INSPECT_GLOBAL_NAME, inspectNativeElement);
|
||||
getDOM().setGlobalVar(
|
||||
CORE_TOKENS_GLOBAL_NAME,
|
||||
StringMapWrapper.merge(CORE_TOKENS, _ngProbeTokensToMap(extraTokens || [])));
|
||||
return new core.ɵDebugDomRootRenderer(rootRenderer);
|
||||
StringMapWrapper.merge(CORE_TOKENS, _ngProbeTokensToMap(tokens || [])));
|
||||
return () => inspectNativeElement;
|
||||
}
|
||||
|
||||
function _ngProbeTokensToMap(tokens: NgProbeToken[]): {[name: string]: any} {
|
||||
@ -62,12 +54,12 @@ function _ngProbeTokensToMap(tokens: NgProbeToken[]): {[name: string]: any} {
|
||||
*/
|
||||
export const ELEMENT_PROBE_PROVIDERS: core.Provider[] = [
|
||||
{
|
||||
provide: core.RootRenderer,
|
||||
useFactory: _createConditionalRootRenderer,
|
||||
provide: core.APP_INITIALIZER,
|
||||
useFactory: _createNgProbe,
|
||||
deps: [
|
||||
DomRootRenderer,
|
||||
[NgProbeToken, new core.Optional()],
|
||||
[core.NgProbeToken, new core.Optional()],
|
||||
],
|
||||
multi: true,
|
||||
},
|
||||
];
|
||||
|
@ -1,19 +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
|
||||
*/
|
||||
|
||||
export interface DomAnimatePlayer {
|
||||
cancel(): void;
|
||||
play(): void;
|
||||
pause(): void;
|
||||
finish(): void;
|
||||
onfinish: Function;
|
||||
position: number;
|
||||
currentTime: number;
|
||||
addEventListener(eventName: string, handler: (event: any) => any): any;
|
||||
dispatchEvent(eventName: string): any;
|
||||
}
|
@ -6,11 +6,10 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {APP_ID, Inject, Injectable, RenderComponentType, Renderer, RendererFactoryV2, RendererTypeV2, RendererV2, RootRenderer, ViewEncapsulation, ɵAnimationKeyframe as AnimationKeyframe, ɵAnimationPlayer as AnimationPlayer, ɵAnimationStyles as AnimationStyles, ɵDirectRenderer as DirectRenderer, ɵNoOpAnimationPlayer as NoOpAnimationPlayer, ɵRenderDebugInfo as RenderDebugInfo} from '@angular/core';
|
||||
import {APP_ID, Inject, Injectable, RenderComponentType, Renderer, RendererFactoryV2, RendererTypeV2, RendererV2, RootRenderer, ViewEncapsulation} from '@angular/core';
|
||||
|
||||
import {isPresent, stringify} from '../facade/lang';
|
||||
|
||||
import {AnimationDriver} from './animation_driver';
|
||||
import {DOCUMENT} from './dom_tokens';
|
||||
import {EventManager} from './events/event_manager';
|
||||
import {DomSharedStylesHost} from './shared_styles_host';
|
||||
@ -21,290 +20,6 @@ export const NAMESPACE_URIS: {[ns: string]: string} = {
|
||||
'xhtml': 'http://www.w3.org/1999/xhtml',
|
||||
'xml': 'http://www.w3.org/XML/1998/namespace'
|
||||
};
|
||||
const TEMPLATE_COMMENT_TEXT = 'template bindings={}';
|
||||
const TEMPLATE_BINDINGS_EXP = /^template bindings=(.*)$/;
|
||||
|
||||
export abstract class DomRootRenderer implements RootRenderer {
|
||||
protected registeredComponents: Map<string, DomRenderer> = new Map<string, DomRenderer>();
|
||||
|
||||
constructor(
|
||||
public document: Document, public eventManager: EventManager,
|
||||
public sharedStylesHost: DomSharedStylesHost, public animationDriver: AnimationDriver,
|
||||
public appId: string) {}
|
||||
|
||||
renderComponent(componentProto: RenderComponentType): Renderer {
|
||||
let renderer = this.registeredComponents.get(componentProto.id);
|
||||
if (!renderer) {
|
||||
renderer = new DomRenderer(
|
||||
this, componentProto, this.animationDriver, `${this.appId}-${componentProto.id}`);
|
||||
this.registeredComponents.set(componentProto.id, renderer);
|
||||
}
|
||||
return renderer;
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class DomRootRenderer_ extends DomRootRenderer {
|
||||
constructor(
|
||||
@Inject(DOCUMENT) _document: any, _eventManager: EventManager,
|
||||
sharedStylesHost: DomSharedStylesHost, animationDriver: AnimationDriver,
|
||||
@Inject(APP_ID) appId: string) {
|
||||
super(_document, _eventManager, sharedStylesHost, animationDriver, appId);
|
||||
throw new Error(
|
||||
'RootRenderer is no longer supported. Please use the `RendererFactoryV2` instead!');
|
||||
}
|
||||
}
|
||||
|
||||
export const DIRECT_DOM_RENDERER: DirectRenderer = {
|
||||
remove(node: Text | Comment | Element) {
|
||||
if (node.parentNode) {
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
},
|
||||
appendChild(node: Node, parent: Element) { parent.appendChild(node);},
|
||||
insertBefore(node: Node, refNode: Node) { refNode.parentNode.insertBefore(node, refNode);},
|
||||
nextSibling(node: Node) { return node.nextSibling;},
|
||||
parentElement(node: Node): Element{return node.parentNode as Element;}
|
||||
};
|
||||
|
||||
export class DomRenderer implements Renderer {
|
||||
private _contentAttr: string;
|
||||
private _hostAttr: string;
|
||||
private _styles: string[];
|
||||
|
||||
directRenderer: DirectRenderer = DIRECT_DOM_RENDERER;
|
||||
|
||||
constructor(
|
||||
private _rootRenderer: DomRootRenderer, private componentProto: RenderComponentType,
|
||||
private _animationDriver: AnimationDriver, styleShimId: string) {
|
||||
this._styles = flattenStyles(styleShimId, componentProto.styles, []);
|
||||
if (componentProto.encapsulation !== ViewEncapsulation.Native) {
|
||||
this._rootRenderer.sharedStylesHost.addStyles(this._styles);
|
||||
}
|
||||
if (this.componentProto.encapsulation === ViewEncapsulation.Emulated) {
|
||||
this._contentAttr = shimContentAttribute(styleShimId);
|
||||
this._hostAttr = shimHostAttribute(styleShimId);
|
||||
} else {
|
||||
this._contentAttr = null;
|
||||
this._hostAttr = null;
|
||||
}
|
||||
}
|
||||
|
||||
selectRootElement(selectorOrNode: string|Element, debugInfo: RenderDebugInfo): Element {
|
||||
let el: Element;
|
||||
if (typeof selectorOrNode === 'string') {
|
||||
el = this._rootRenderer.document.querySelector(selectorOrNode);
|
||||
if (!el) {
|
||||
throw new Error(`The selector "${selectorOrNode}" did not match any elements`);
|
||||
}
|
||||
} else {
|
||||
el = selectorOrNode;
|
||||
}
|
||||
while (el.firstChild) {
|
||||
el.removeChild(el.firstChild);
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
createElement(parent: Element|DocumentFragment, name: string, debugInfo: RenderDebugInfo):
|
||||
Element {
|
||||
let el: Element;
|
||||
if (isNamespaced(name)) {
|
||||
const nsAndName = splitNamespace(name);
|
||||
el = document.createElementNS((NAMESPACE_URIS)[nsAndName[0]], nsAndName[1]);
|
||||
} else {
|
||||
el = document.createElement(name);
|
||||
}
|
||||
if (this._contentAttr) {
|
||||
el.setAttribute(this._contentAttr, '');
|
||||
}
|
||||
if (parent) {
|
||||
parent.appendChild(el);
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
createViewRoot(hostElement: Element): Element|DocumentFragment {
|
||||
let nodesParent: Element|DocumentFragment;
|
||||
if (this.componentProto.encapsulation === ViewEncapsulation.Native) {
|
||||
nodesParent = (hostElement as any).createShadowRoot();
|
||||
this._rootRenderer.sharedStylesHost.addHost(nodesParent);
|
||||
for (let i = 0; i < this._styles.length; i++) {
|
||||
const styleEl = document.createElement('style');
|
||||
styleEl.textContent = this._styles[i];
|
||||
nodesParent.appendChild(styleEl);
|
||||
}
|
||||
} else {
|
||||
if (this._hostAttr) {
|
||||
hostElement.setAttribute(this._hostAttr, '');
|
||||
}
|
||||
nodesParent = hostElement;
|
||||
}
|
||||
return nodesParent;
|
||||
}
|
||||
|
||||
createTemplateAnchor(parentElement: Element|DocumentFragment, debugInfo: RenderDebugInfo):
|
||||
Comment {
|
||||
const comment = document.createComment(TEMPLATE_COMMENT_TEXT);
|
||||
if (parentElement) {
|
||||
parentElement.appendChild(comment);
|
||||
}
|
||||
return comment;
|
||||
}
|
||||
|
||||
createText(parentElement: Element|DocumentFragment, value: string, debugInfo: RenderDebugInfo):
|
||||
any {
|
||||
const node = document.createTextNode(value);
|
||||
if (parentElement) {
|
||||
parentElement.appendChild(node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
projectNodes(parentElement: Element|DocumentFragment, nodes: Node[]) {
|
||||
if (!parentElement) return;
|
||||
appendNodes(parentElement, nodes);
|
||||
}
|
||||
|
||||
attachViewAfter(node: Node, viewRootNodes: Node[]) { moveNodesAfterSibling(node, viewRootNodes); }
|
||||
|
||||
detachView(viewRootNodes: (Element|Text|Comment)[]) {
|
||||
for (let i = 0; i < viewRootNodes.length; i++) {
|
||||
const node = viewRootNodes[i];
|
||||
if (node.parentNode) {
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
destroyView(hostElement: Element|DocumentFragment, viewAllNodes: Node[]) {
|
||||
if (this.componentProto.encapsulation === ViewEncapsulation.Native && hostElement) {
|
||||
this._rootRenderer.sharedStylesHost.removeHost((hostElement as any).shadowRoot);
|
||||
}
|
||||
}
|
||||
|
||||
listen(renderElement: any, name: string, callback: Function): Function {
|
||||
return this._rootRenderer.eventManager.addEventListener(
|
||||
renderElement, name, decoratePreventDefault(callback));
|
||||
}
|
||||
|
||||
listenGlobal(target: string, name: string, callback: Function): Function {
|
||||
return this._rootRenderer.eventManager.addGlobalEventListener(
|
||||
target, name, decoratePreventDefault(callback));
|
||||
}
|
||||
|
||||
setElementProperty(
|
||||
renderElement: Element|DocumentFragment, propertyName: string, propertyValue: any): void {
|
||||
(renderElement as any)[propertyName] = propertyValue;
|
||||
}
|
||||
|
||||
setElementAttribute(renderElement: Element, attributeName: string, attributeValue: string): void {
|
||||
let attrNs: string;
|
||||
let attrNameWithoutNs = attributeName;
|
||||
if (isNamespaced(attributeName)) {
|
||||
const nsAndName = splitNamespace(attributeName);
|
||||
attrNameWithoutNs = nsAndName[1];
|
||||
attributeName = nsAndName[0] + ':' + nsAndName[1];
|
||||
attrNs = NAMESPACE_URIS[nsAndName[0]];
|
||||
}
|
||||
if (isPresent(attributeValue)) {
|
||||
if (attrNs) {
|
||||
renderElement.setAttributeNS(attrNs, attributeName, attributeValue);
|
||||
} else {
|
||||
renderElement.setAttribute(attributeName, attributeValue);
|
||||
}
|
||||
} else {
|
||||
if (isPresent(attrNs)) {
|
||||
renderElement.removeAttributeNS(attrNs, attrNameWithoutNs);
|
||||
} else {
|
||||
renderElement.removeAttribute(attributeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setBindingDebugInfo(renderElement: Element, propertyName: string, propertyValue: string): void {
|
||||
if (renderElement.nodeType === Node.COMMENT_NODE) {
|
||||
const existingBindings =
|
||||
renderElement.nodeValue.replace(/\n/g, '').match(TEMPLATE_BINDINGS_EXP);
|
||||
const parsedBindings = JSON.parse(existingBindings[1]);
|
||||
parsedBindings[propertyName] = propertyValue;
|
||||
renderElement.nodeValue =
|
||||
TEMPLATE_COMMENT_TEXT.replace('{}', JSON.stringify(parsedBindings, null, 2));
|
||||
} else {
|
||||
// Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
|
||||
propertyName = propertyName.replace(/\$/g, '_');
|
||||
this.setElementAttribute(renderElement, propertyName, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
setElementClass(renderElement: Element, className: string, isAdd: boolean): void {
|
||||
if (isAdd) {
|
||||
renderElement.classList.add(className);
|
||||
} else {
|
||||
renderElement.classList.remove(className);
|
||||
}
|
||||
}
|
||||
|
||||
setElementStyle(renderElement: HTMLElement, styleName: string, styleValue: string): void {
|
||||
if (isPresent(styleValue)) {
|
||||
(renderElement.style as any)[styleName] = stringify(styleValue);
|
||||
} else {
|
||||
// IE requires '' instead of null
|
||||
// see https://github.com/angular/angular/issues/7916
|
||||
(renderElement.style as any)[styleName] = '';
|
||||
}
|
||||
}
|
||||
|
||||
invokeElementMethod(renderElement: Element, methodName: string, args: any[]): void {
|
||||
(renderElement as any)[methodName].apply(renderElement, args);
|
||||
}
|
||||
|
||||
setText(renderNode: Text, text: string): void { renderNode.nodeValue = text; }
|
||||
|
||||
animate(
|
||||
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
|
||||
duration: number, delay: number, easing: string,
|
||||
previousPlayers: AnimationPlayer[] = []): AnimationPlayer {
|
||||
if (this._rootRenderer.document.body.contains(element)) {
|
||||
return this._animationDriver.animate(
|
||||
element, startingStyles, keyframes, duration, delay, easing, previousPlayers);
|
||||
}
|
||||
return new NoOpAnimationPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
function moveNodesAfterSibling(sibling: Node, nodes: Node[]) {
|
||||
const parent = sibling.parentNode;
|
||||
if (nodes.length > 0 && parent) {
|
||||
const nextSibling = sibling.nextSibling;
|
||||
if (nextSibling) {
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
parent.insertBefore(nodes[i], nextSibling);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
parent.appendChild(nodes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function appendNodes(parent: Element | DocumentFragment, nodes: Node[]) {
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
parent.appendChild(nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function decoratePreventDefault(eventHandler: Function): Function {
|
||||
return (event: any) => {
|
||||
const allowDefaultBehavior = eventHandler(event);
|
||||
if (allowDefaultBehavior === false) {
|
||||
// TODO(tbosch): move preventDefault into event plugins...
|
||||
event.preventDefault();
|
||||
event.returnValue = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const COMPONENT_REGEX = /%COMP%/g;
|
||||
export const COMPONENT_VARIABLE = '%COMP%';
|
||||
@ -334,18 +49,17 @@ export function flattenStyles(
|
||||
return target;
|
||||
}
|
||||
|
||||
const NS_PREFIX_RE = /^:([^:]+):(.+)$/;
|
||||
|
||||
export function isNamespaced(name: string) {
|
||||
return name[0] === ':';
|
||||
function decoratePreventDefault(eventHandler: Function): Function {
|
||||
return (event: any) => {
|
||||
const allowDefaultBehavior = eventHandler(event);
|
||||
if (allowDefaultBehavior === false) {
|
||||
// TODO(tbosch): move preventDefault into event plugins...
|
||||
event.preventDefault();
|
||||
event.returnValue = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function splitNamespace(name: string): string[] {
|
||||
const match = name.match(NS_PREFIX_RE);
|
||||
return [match[1], match[2]];
|
||||
}
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class DomRendererFactoryV2 implements RendererFactoryV2 {
|
||||
private rendererByCompId = new Map<string, RendererV2>();
|
||||
|
@ -1,81 +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 {AnimationPlayer, ɵAnimationKeyframe as AnimationKeyframe, ɵAnimationStyles as AnimationStyles} from '@angular/core';
|
||||
import {isPresent} from '../facade/lang';
|
||||
|
||||
import {AnimationDriver} from './animation_driver';
|
||||
import {WebAnimationsPlayer} from './web_animations_player';
|
||||
|
||||
export class WebAnimationsDriver implements AnimationDriver {
|
||||
animate(
|
||||
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
|
||||
duration: number, delay: number, easing: string,
|
||||
previousPlayers: AnimationPlayer[] = []): WebAnimationsPlayer {
|
||||
let formattedSteps: {[key: string]: string | number}[] = [];
|
||||
let startingStyleLookup: {[key: string]: string | number} = {};
|
||||
if (isPresent(startingStyles)) {
|
||||
startingStyleLookup = _populateStyles(startingStyles, {});
|
||||
}
|
||||
|
||||
keyframes.forEach((keyframe: AnimationKeyframe) => {
|
||||
const data = _populateStyles(keyframe.styles, startingStyleLookup);
|
||||
data['offset'] = Math.max(0, Math.min(1, keyframe.offset));
|
||||
formattedSteps.push(data);
|
||||
});
|
||||
|
||||
// Styling passed into element.animate() must always be balanced.
|
||||
// The special cases below can occur if only style() calls exist
|
||||
// within an animation or when a style() calls are used prior
|
||||
// to a group() animation being issued or if the renderer is
|
||||
// invoked by the user directly.
|
||||
if (formattedSteps.length == 0) {
|
||||
formattedSteps = [startingStyleLookup, startingStyleLookup];
|
||||
} else if (formattedSteps.length == 1) {
|
||||
const start = startingStyleLookup;
|
||||
const end = formattedSteps[0];
|
||||
end['offset'] = null;
|
||||
formattedSteps = [start, end];
|
||||
}
|
||||
|
||||
const playerOptions: {[key: string]: string | number} = {
|
||||
'duration': duration,
|
||||
'delay': delay,
|
||||
'fill': 'both' // we use `both` because it allows for styling at 0% to work with `delay`
|
||||
};
|
||||
|
||||
// we check for this to avoid having a null|undefined value be present
|
||||
// for the easing (which results in an error for certain browsers #9752)
|
||||
if (easing) {
|
||||
playerOptions['easing'] = easing;
|
||||
}
|
||||
|
||||
// there may be a chance a NoOp player is returned depending
|
||||
// on when the previous animation was cancelled
|
||||
previousPlayers = previousPlayers.filter(filterWebAnimationPlayerFn);
|
||||
return new WebAnimationsPlayer(
|
||||
element, formattedSteps, playerOptions, <WebAnimationsPlayer[]>previousPlayers);
|
||||
}
|
||||
}
|
||||
|
||||
function _populateStyles(styles: AnimationStyles, defaultStyles: {[key: string]: string | number}):
|
||||
{[key: string]: string | number} {
|
||||
const data: {[key: string]: string | number} = {};
|
||||
styles.styles.forEach(
|
||||
(entry) => { Object.keys(entry).forEach(prop => { data[prop] = entry[prop]; }); });
|
||||
Object.keys(defaultStyles).forEach(prop => {
|
||||
if (!isPresent(data[prop])) {
|
||||
data[prop] = defaultStyles[prop];
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
function filterWebAnimationPlayerFn(player: AnimationPlayer) {
|
||||
return player instanceof WebAnimationsPlayer;
|
||||
}
|
@ -1,200 +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 {AUTO_STYLE, ɵAnimationPlayer as AnimationPlayer} from '@angular/core';
|
||||
import {isPresent} from '../facade/lang';
|
||||
import {getDOM} from './dom_adapter';
|
||||
import {DomAnimatePlayer} from './dom_animate_player';
|
||||
|
||||
export class WebAnimationsPlayer implements AnimationPlayer {
|
||||
private _onDoneFns: Function[] = [];
|
||||
private _onStartFns: Function[] = [];
|
||||
private _onDestroyFns: Function[] = [];
|
||||
private _player: DomAnimatePlayer;
|
||||
private _duration: number;
|
||||
private _initialized = false;
|
||||
private _finished = false;
|
||||
private _started = false;
|
||||
private _destroyed = false;
|
||||
private _finalKeyframe: {[key: string]: string | number};
|
||||
|
||||
public parentPlayer: AnimationPlayer = null;
|
||||
public previousStyles: {[styleName: string]: string | number};
|
||||
|
||||
constructor(
|
||||
public element: any, public keyframes: {[key: string]: string | number}[],
|
||||
public options: {[key: string]: string | number},
|
||||
previousPlayers: WebAnimationsPlayer[] = []) {
|
||||
this._duration = <number>options['duration'];
|
||||
|
||||
this.previousStyles = {};
|
||||
previousPlayers.forEach(player => {
|
||||
let styles = player._captureStyles();
|
||||
Object.keys(styles).forEach(prop => this.previousStyles[prop] = styles[prop]);
|
||||
});
|
||||
}
|
||||
|
||||
private _onFinish() {
|
||||
if (!this._finished) {
|
||||
this._finished = true;
|
||||
this._onDoneFns.forEach(fn => fn());
|
||||
this._onDoneFns = [];
|
||||
}
|
||||
}
|
||||
|
||||
init(): void {
|
||||
if (this._initialized) return;
|
||||
this._initialized = true;
|
||||
|
||||
const keyframes = this.keyframes.map(styles => {
|
||||
const formattedKeyframe: {[key: string]: string | number} = {};
|
||||
Object.keys(styles).forEach((prop, index) => {
|
||||
let value = styles[prop];
|
||||
if (value == AUTO_STYLE) {
|
||||
value = _computeStyle(this.element, prop);
|
||||
}
|
||||
if (value != undefined) {
|
||||
formattedKeyframe[prop] = value;
|
||||
}
|
||||
});
|
||||
return formattedKeyframe;
|
||||
});
|
||||
|
||||
const previousStyleProps = Object.keys(this.previousStyles);
|
||||
if (previousStyleProps.length) {
|
||||
let startingKeyframe = keyframes[0];
|
||||
let missingStyleProps: string[] = [];
|
||||
previousStyleProps.forEach(prop => {
|
||||
if (!isPresent(startingKeyframe[prop])) {
|
||||
missingStyleProps.push(prop);
|
||||
}
|
||||
startingKeyframe[prop] = this.previousStyles[prop];
|
||||
});
|
||||
|
||||
if (missingStyleProps.length) {
|
||||
const self = this;
|
||||
// tslint:disable-next-line
|
||||
for (var i = 1; i < keyframes.length; i++) {
|
||||
let kf = keyframes[i];
|
||||
// tslint:disable-next-line
|
||||
missingStyleProps.forEach(function(prop) {
|
||||
kf[prop] = _computeStyle(self.element, prop);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._player = this._triggerWebAnimation(this.element, keyframes, this.options);
|
||||
this._finalKeyframe = _copyKeyframeStyles(keyframes[keyframes.length - 1]);
|
||||
|
||||
// this is required so that the player doesn't start to animate right away
|
||||
this._resetDomPlayerState();
|
||||
this._player.addEventListener('finish', () => this._onFinish());
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_triggerWebAnimation(element: any, keyframes: any[], options: any): DomAnimatePlayer {
|
||||
// jscompiler doesn't seem to know animate is a native property because it's not fully
|
||||
// supported yet across common browsers (we polyfill it for Edge/Safari) [CL #143630929]
|
||||
return <DomAnimatePlayer>element['animate'](keyframes, options);
|
||||
}
|
||||
|
||||
get domPlayer() { return this._player; }
|
||||
|
||||
onStart(fn: () => void): void { this._onStartFns.push(fn); }
|
||||
|
||||
onDone(fn: () => void): void { this._onDoneFns.push(fn); }
|
||||
|
||||
onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); }
|
||||
|
||||
play(): void {
|
||||
this.init();
|
||||
if (!this.hasStarted()) {
|
||||
this._onStartFns.forEach(fn => fn());
|
||||
this._onStartFns = [];
|
||||
this._started = true;
|
||||
}
|
||||
this._player.play();
|
||||
}
|
||||
|
||||
pause(): void {
|
||||
this.init();
|
||||
this._player.pause();
|
||||
}
|
||||
|
||||
finish(): void {
|
||||
this.init();
|
||||
this._onFinish();
|
||||
this._player.finish();
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._resetDomPlayerState();
|
||||
this._destroyed = false;
|
||||
this._finished = false;
|
||||
this._started = false;
|
||||
}
|
||||
|
||||
private _resetDomPlayerState() {
|
||||
if (this._player) {
|
||||
this._player.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
restart(): void {
|
||||
this.reset();
|
||||
this.play();
|
||||
}
|
||||
|
||||
hasStarted(): boolean { return this._started; }
|
||||
|
||||
destroy(): void {
|
||||
if (!this._destroyed) {
|
||||
this._resetDomPlayerState();
|
||||
this._onFinish();
|
||||
this._destroyed = true;
|
||||
this._onDestroyFns.forEach(fn => fn());
|
||||
this._onDestroyFns = [];
|
||||
}
|
||||
}
|
||||
|
||||
get totalTime(): number { return this._duration; }
|
||||
|
||||
setPosition(p: number): void { this._player.currentTime = p * this.totalTime; }
|
||||
|
||||
getPosition(): number { return this._player.currentTime / this.totalTime; }
|
||||
|
||||
private _captureStyles(): {[prop: string]: string | number} {
|
||||
const styles: {[key: string]: string | number} = {};
|
||||
if (this.hasStarted()) {
|
||||
Object.keys(this._finalKeyframe).forEach(prop => {
|
||||
if (prop != 'offset') {
|
||||
styles[prop] =
|
||||
this._finished ? this._finalKeyframe[prop] : _computeStyle(this.element, prop);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return styles;
|
||||
}
|
||||
}
|
||||
|
||||
function _computeStyle(element: any, prop: string): string {
|
||||
return getDOM().getComputedStyle(element)[prop];
|
||||
}
|
||||
|
||||
function _copyKeyframeStyles(styles: {[style: string]: string | number}):
|
||||
{[style: string]: string | number} {
|
||||
const newStyles: {[style: string]: string | number} = {};
|
||||
Object.keys(styles).forEach(prop => {
|
||||
if (prop != 'offset') {
|
||||
newStyles[prop] = styles[prop];
|
||||
}
|
||||
});
|
||||
return newStyles;
|
||||
}
|
@ -10,7 +10,6 @@ export {BrowserModule, platformBrowser} from './browser';
|
||||
export {Meta, MetaDefinition} from './browser/meta';
|
||||
export {Title} from './browser/title';
|
||||
export {disableDebugTools, enableDebugTools} from './browser/tools/tools';
|
||||
export {AnimationDriver} from './dom/animation_driver';
|
||||
export {By} from './dom/debug/by';
|
||||
export {NgProbeToken} from './dom/debug/ng_probe';
|
||||
export {DOCUMENT} from './dom/dom_tokens';
|
||||
|
@ -13,9 +13,8 @@ export {TRANSITION_ID as ɵTRANSITION_ID} from './browser/server-transition';
|
||||
export {BrowserGetTestability as ɵBrowserGetTestability} from './browser/testability';
|
||||
export {ELEMENT_PROBE_PROVIDERS as ɵELEMENT_PROBE_PROVIDERS} from './dom/debug/ng_probe';
|
||||
export {DomAdapter as ɵDomAdapter, getDOM as ɵgetDOM, setRootDomAdapter as ɵsetRootDomAdapter} from './dom/dom_adapter';
|
||||
export {DomRendererFactoryV2 as ɵDomRendererFactoryV2, DomRootRenderer as ɵDomRootRenderer, DomRootRenderer_ as ɵDomRootRenderer_, NAMESPACE_URIS as ɵNAMESPACE_URIS, flattenStyles as ɵflattenStyles, isNamespaced as ɵisNamespaced, shimContentAttribute as ɵshimContentAttribute, shimHostAttribute as ɵshimHostAttribute, splitNamespace as ɵsplitNamespace} from './dom/dom_renderer';
|
||||
export {DomRendererFactoryV2 as ɵDomRendererFactoryV2, NAMESPACE_URIS as ɵNAMESPACE_URIS, flattenStyles as ɵflattenStyles, shimContentAttribute as ɵshimContentAttribute, shimHostAttribute as ɵshimHostAttribute} from './dom/dom_renderer';
|
||||
export {DomEventsPlugin as ɵDomEventsPlugin} from './dom/events/dom_events';
|
||||
export {HammerGesturesPlugin as ɵHammerGesturesPlugin} from './dom/events/hammer_gestures';
|
||||
export {KeyEventsPlugin as ɵKeyEventsPlugin} from './dom/events/key_events';
|
||||
export {DomSharedStylesHost as ɵDomSharedStylesHost, SharedStylesHost as ɵSharedStylesHost} from './dom/shared_styles_host';
|
||||
export {WebAnimationsDriver as ɵWebAnimationsDriver} from './dom/web_animations_driver';
|
||||
|
Reference in New Issue
Block a user