function updateListener(newVal, oldVal) { if (oldVal) { canEventQueue.off.call(oldVal, event, handler); } if (newVal) { canEventQueue.on.call(newVal, event, handler); currentContext = newVal; } }
event: function(el, data) { var eventBindingData; // Get the `event` name and if we are listening to the element or viewModel. // The attribute name is the name of the event. var attributeName = encoder.decode(data.attributeName), // the name of the event we are binding event, // the context to which we bind the event listener bindingContext, // if the bindingContext is null, then use this observable to watch for changes bindingContextObservable; // check for `on:event:value:to` type things and call data bindings if (attributeName.indexOf(toMatchStr + ":") !== -1 || attributeName.indexOf(fromMatchStr + ":") !== -1 || attributeName.indexOf(bindMatchStr + ":") !== -1 ) { return this.data(el, data); } if (startsWith.call(attributeName, onMatchStr)) { eventBindingData = getEventBindingData(attributeName, el, data.scope); event = eventBindingData.eventName; bindingContext = eventBindingData.bindingContext; bindingContextObservable = eventBindingData.bindingContextObservable; } else { throw new Error("can-stache-bindings - unsupported event bindings " + attributeName); } // This is the method that the event will initially trigger. It will look up the method by the string name // passed in the attribute and call it. var handler = function(ev) { var attrVal = el.getAttribute(encoder.encode(attributeName)); if (!attrVal) { return; } var viewModel = canViewModel(el); // expression.parse will read the attribute // value and parse it identically to how mustache helpers // get parsed. var expr = expression.parse(attrVal, { lookupRule: function() { return expression.Lookup; }, methodRule: "call" }); var runScope = makeScopeFromEvent(el, ev, viewModel, arguments, data, bindingContext); if (expr instanceof expression.Hashes) { var hashExprs = expr.hashExprs; var key = Object.keys(hashExprs)[0]; var value = expr.hashExprs[key].value(runScope); var isObservableValue = canReflect.isObservableLike(value) && canReflect.isValueLike(value); runScope.set(key, isObservableValue ? canReflect.getValue(value) : value); } else if (expr instanceof expression.Call) { runEventCallback(el, ev, data, runScope, expr, attributeName, attrVal); } else { throw new Error("can-stache-bindings: Event bindings must be a call expression. Make sure you have a () in " + data.attributeName + "=" + JSON.stringify(attrVal)); } }; var attributesDisposal, removalDisposal, removeObservation, currentContext; // Unbind the event when the attribute is removed from the DOM var attributesHandler = function(ev) { var isEventAttribute = ev.attributeName === attributeName; var isRemoved = !el.getAttribute(attributeName); var isEventAttributeRemoved = isEventAttribute && isRemoved; if (isEventAttributeRemoved) { unbindEvent(); } }; var removalHandler = function() { var doc = el.ownerDocument; var ownerNode = doc.contains ? doc : doc.documentElement; if (!ownerNode || !ownerNode.contains(el)) { unbindEvent(); } }; var unbindEvent = function() { if (bindingContext) { canEventQueue.off.call(bindingContext, event, handler); } if (attributesDisposal) { attributesDisposal(); attributesDisposal = undefined; } if (removalDisposal) { removalDisposal(); removalDisposal = undefined; } if (removeObservation) { removeObservation(); removeObservation = undefined; } }; function updateListener(newVal, oldVal) { if (oldVal) { canEventQueue.off.call(oldVal, event, handler); } if (newVal) { canEventQueue.on.call(newVal, event, handler); currentContext = newVal; } } // Bind the handler defined above to the element we're currently processing and the event name provided in this // attribute name (can-click="foo") attributesDisposal = domMutate.onNodeAttributeChange(el, attributesHandler); removalDisposal = domMutate.onNodeRemoval(el, removalHandler); if (!bindingContext && bindingContextObservable) { // on value changes of the observation, rebind the listener to the new context removeObservation = function () { if (currentContext) { canEventQueue.off.call(currentContext, event, handler); } canReflect.offValue(bindingContextObservable, updateListener); }; canReflect.onValue(bindingContextObservable, updateListener); } else { canEventQueue.on.call(bindingContext, event, handler); } }