fix(core): host bindings and host listeners for animations

Host bindings / listeners for animation properties should use
the renderer of the component view.
This commit is contained in:
Tobias Bosch
2017-02-21 13:56:56 -08:00
committed by Igor Minar
parent 6b7937f112
commit 5049a50bf6
20 changed files with 635 additions and 603 deletions

View File

@ -7,9 +7,10 @@
*/
import {isDevMode} from '../application_ref';
import {RendererTypeV2, RendererV2} from '../render/api';
import {SecurityContext} from '../security';
import {BindingDef, BindingType, DebugContext, DisposableFn, ElementData, ElementHandleEventFn, ElementOutputDef, NodeData, NodeDef, NodeFlags, NodeType, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, asElementData} from './types';
import {BindingDef, BindingType, DebugContext, DisposableFn, ElementData, ElementHandleEventFn, NodeData, NodeDef, NodeFlags, NodeType, OutputDef, OutputType, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, asElementData, asProviderData} from './types';
import {checkAndUpdateBinding, dispatchEvent, elementEventFullName, filterQueryId, getParentRenderElement, resolveViewDefinition, sliceErrorStack, splitMatchedQueriesDsl, splitNamespace} from './util';
const NOOP: any = () => {};
@ -34,20 +35,20 @@ export function anchorDef(
parent: undefined,
renderParent: undefined,
bindingIndex: undefined,
disposableIndex: undefined,
outputIndex: undefined,
// regular values
flags,
childFlags: 0,
childMatchedQueries: 0, matchedQueries, matchedQueryIds, references, ngContentIndex, childCount,
bindings: [],
disposableCount: 0,
outputs: [],
element: {
ns: undefined,
name: undefined,
attrs: undefined,
outputs: [], template, source,
// will bet set by the view definition
component: undefined,
attrs: undefined, template, source,
componentProvider: undefined,
componentView: undefined,
componentRendererType: undefined,
publicProviders: undefined,
allProviders: undefined, handleEvent
},
@ -65,8 +66,13 @@ export function elementDef(
fixedAttrs: [string, string][] = [],
bindings?:
([BindingType.ElementClass, string] | [BindingType.ElementStyle, string, string] |
[BindingType.ElementAttribute | BindingType.ElementProperty, string, SecurityContext])[],
outputs?: (string | [string, string])[], handleEvent?: ElementHandleEventFn): NodeDef {
[
BindingType.ElementAttribute | BindingType.ElementProperty |
BindingType.ComponentHostProperty,
string, SecurityContext
])[],
outputs?: ([string, string])[], handleEvent?: ElementHandleEventFn,
componentView?: () => ViewDefinition, componentRendererType?: RendererTypeV2): NodeDef {
if (!handleEvent) {
handleEvent = NOOP;
}
@ -93,29 +99,35 @@ export function elementDef(
break;
case BindingType.ElementAttribute:
case BindingType.ElementProperty:
case BindingType.ComponentHostProperty:
securityContext = <SecurityContext>entry[2];
break;
}
bindingDefs[i] = {type: bindingType, ns, name, nonMinifiedName: name, securityContext, suffix};
}
outputs = outputs || [];
const outputDefs: ElementOutputDef[] = new Array(outputs.length);
const outputDefs: OutputDef[] = new Array(outputs.length);
for (let i = 0; i < outputs.length; i++) {
const output = outputs[i];
let target: string;
let eventName: string;
if (Array.isArray(output)) {
[target, eventName] = output;
} else {
eventName = output;
}
outputDefs[i] = {eventName: eventName, target: target};
const [target, eventName] = outputs[i];
outputDefs[i] = {
type: OutputType.ElementOutput,
target: <any>target, eventName,
propName: undefined
};
}
fixedAttrs = fixedAttrs || [];
const attrs = <[string, string, string][]>fixedAttrs.map(([namespaceAndName, value]) => {
const [ns, name] = splitNamespace(namespaceAndName);
return [ns, name, value];
});
// This is needed as the jit compiler always uses an empty hash as default RendererTypeV2,
// which is not filled for host views.
if (componentRendererType && componentRendererType.encapsulation == null) {
componentRendererType = null;
}
if (componentView) {
flags |= NodeFlags.HasComponent;
}
return {
type: NodeType.Element,
// will bet set by the view definition
@ -124,21 +136,21 @@ export function elementDef(
parent: undefined,
renderParent: undefined,
bindingIndex: undefined,
disposableIndex: undefined,
outputIndex: undefined,
// regular values
flags,
childFlags: 0,
childMatchedQueries: 0, matchedQueries, matchedQueryIds, references, ngContentIndex, childCount,
bindings: bindingDefs,
disposableCount: outputDefs.length,
outputs: outputDefs,
element: {
ns,
name,
attrs,
outputs: outputDefs, source,
source,
template: undefined,
// will bet set by the view definition
component: undefined,
componentProvider: undefined, componentView, componentRendererType,
publicProviders: undefined,
allProviders: undefined, handleEvent,
},
@ -174,21 +186,24 @@ export function createElement(view: ViewData, renderHost: any, def: NodeDef): El
renderer.setAttribute(el, name, value, ns);
}
}
if (elDef.outputs.length) {
for (let i = 0; i < elDef.outputs.length; i++) {
const output = elDef.outputs[i];
const handleEventClosure = renderEventHandlerClosure(
view, def.index, elementEventFullName(output.target, output.eventName));
const disposable =
<any>renderer.listen(output.target || el, output.eventName, handleEventClosure);
view.disposables[def.disposableIndex + i] = disposable;
return el;
}
export function listenToElementOutputs(view: ViewData, compView: ViewData, def: NodeDef, el: any) {
for (let i = 0; i < def.outputs.length; i++) {
const output = def.outputs[i];
const handleEventClosure = renderEventHandlerClosure(
view, def.index, elementEventFullName(output.target, output.eventName));
let listenTarget = output.target;
let listenerView = view;
if (output.target === 'component') {
listenTarget = null;
listenerView = compView;
}
const disposable =
<any>listenerView.renderer.listen(listenTarget || el, output.eventName, handleEventClosure);
view.disposables[def.outputIndex + i] = disposable;
}
return {
renderElement: el,
embeddedViews: (def.flags & NodeFlags.HasEmbeddedViews) ? [] : undefined,
projectedViews: undefined
};
}
function renderEventHandlerClosure(view: ViewData, index: number, eventName: string) {
@ -223,7 +238,8 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu
return;
}
const binding = def.bindings[bindingIdx];
const renderNode = asElementData(view, def.index).renderElement;
const elData = asElementData(view, def.index);
const renderNode = elData.renderElement;
const name = binding.name;
switch (binding.type) {
case BindingType.ElementAttribute:
@ -238,6 +254,9 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu
case BindingType.ElementProperty:
setElementProperty(view, binding, renderNode, name, value);
break;
case BindingType.ComponentHostProperty:
setElementProperty(elData.componentView, binding, renderNode, name, value);
break;
}
}