Skip to content

Commit

Permalink
Use existing add/removeEventListener for elements
Browse files Browse the repository at this point in the history
This makes it possible to use can-define with HTML elements so that both
property events and DOM events can be listened to and fire correctly.

This is done by using the can-event/lifecycle/lifecycle mixin, and
passing it our existing addEventListener (where it exists), rather than
using canEvent.addEventListener as lifecycle did before.

Closes #145
  • Loading branch information
matthewp committed Feb 8, 2017
1 parent 4fbb7eb commit aead3d7
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 68 deletions.
114 changes: 63 additions & 51 deletions can-define.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,9 @@ module.exports = define = ns.define = function(objPrototype, defines, baseDefine
return data;
});

// Add necessary event methods to this object.
for (var prop in eventsProto) {
Object.defineProperty(objPrototype, prop, {
enumerable: false,
value: eventsProto[prop],
configurable: true,
writable: true
});
}
// Mixin the event methods
define.mixinEvents(objPrototype);

// add so instance defs can be dynamically added
Object.defineProperty(objPrototype,"_define",{
enumerable: false,
Expand Down Expand Up @@ -280,7 +274,7 @@ make = {
if (newVal !== current) {
setData.call(this, newVal);

canEvent.dispatch.call(this, {
canEvent.trigger.call(this, {
type: prop,
target: this
}, [newVal, current]);
Expand Down Expand Up @@ -642,50 +636,12 @@ replaceWith = function(obj, prop, cb, writable) {
eventsProto = assign({}, event);
assign(eventsProto, {
_eventSetup: function() {},
_eventTeardown: function() {},
addEventListener: function(eventName, handler) {

var computedBinding = this._computed && this._computed[eventName];
if (computedBinding && computedBinding.compute) {
if (!computedBinding.count) {
computedBinding.count = 1;
computedBinding.compute.addEventListener("change", computedBinding.handler);
} else {
computedBinding.count++;
}

}

var baseAddEventListener = this.__proto__.addEventListener ||
eventLifecycle.addAndSetup;

return baseAddEventListener.apply(this, arguments);
},

// ### unbind
// Stops listening to an event.
// If this is the last listener of a computed property,
// stop forwarding events of the computed property to this map.
removeEventListener: function(eventName, handler) {
var computedBinding = this._computed && this._computed[eventName];
if (computedBinding) {
if (computedBinding.count === 1) {
computedBinding.count = 0;
computedBinding.compute.removeEventListener("change", computedBinding.handler);
} else {
computedBinding.count--;
}

}

return eventLifecycle.removeAndTeardown.apply(this, arguments);

}
_eventTeardown: function() {}
});
eventsProto.on = eventsProto.bind = eventsProto.addEventListener;
eventsProto.off = eventsProto.unbind = eventsProto.removeEventListener;

delete eventsProto.one;
delete eventsProto.addEventListener;
delete eventsProto.removeEventListener;

define.setup = function(props, sealed) {
defineConfigurableAndNotEnumerable(this, "_cid");
Expand Down Expand Up @@ -721,6 +677,62 @@ define.setup = function(props, sealed) {
};
define.replaceWith = replaceWith;
define.eventsProto = eventsProto;
define.mixinEvents = function(objPrototype, makeEnumerable){
// Add necessary event methods to this object.
for (var prop in eventsProto) {
Object.defineProperty(objPrototype, prop, {
enumerable: !!makeEnumerable,
value: eventsProto[prop],
configurable: true,
writable: true
});
}

var baseAddEventListener = objPrototype.addEventListener ||
canEvent.addEventListener;
var baseRemoveEventListener = objPrototype.removeEventListener ||
canEvent.removeEventListener;

objPrototype.addEventListener = function(eventName, handler) {
var computedBinding = this._computed && this._computed[eventName];
if (computedBinding && computedBinding.compute) {
if (!computedBinding.count) {
computedBinding.count = 1;
computedBinding.compute.addEventListener("change", computedBinding.handler);
} else {
computedBinding.count++;
}
}

eventLifecycle.addAndSetup

return baseAddEventListener.apply(this, arguments);
};

// ### unbind
// Stops listening to an event.
// If this is the last listener of a computed property,
// stop forwarding events of the computed property to this map.
objPrototype.removeEventListener = function(eventName, handler) {
var computedBinding = this._computed && this._computed[eventName];
if (computedBinding) {
if (computedBinding.count === 1) {
computedBinding.count = 0;
computedBinding.compute.removeEventListener("change", computedBinding.handler);
} else {
computedBinding.count--;
}

}

return baseRemoveEventListener.apply(this, arguments);
};

eventLifecycle(objPrototype);

objPrototype.on = objPrototype.bind = objPrototype.addEventListener;
objPrototype.off = objPrototype.unbind = objPrototype.removeEventListener;
};
define.defineConfigurableAndNotEnumerable = defineConfigurableAndNotEnumerable;
define.make = make;
define.getDefinitionOrMethod = getDefinitionOrMethod;
Expand Down
10 changes: 2 additions & 8 deletions list/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -1056,14 +1056,8 @@ assign(DefineList.prototype, {


// Add necessary event methods to this object.
for (var prop in define.eventsProto) {
DefineList[prop] = define.eventsProto[prop];
Object.defineProperty(DefineList.prototype, prop, {
enumerable: false,
value: define.eventsProto[prop],
writable: true
});
}
define.mixinEvents(DefineList, true);
define.mixinEvents(DefineList.prototype);

Object.defineProperty(DefineList.prototype, "length", {
get: function() {
Expand Down
13 changes: 4 additions & 9 deletions map/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ var setProps = function(props, remove) {
}
else if( ("replace" in curVal) && isArray(newVal)) {
curVal.replace(newVal);
}
}
else if( ("set" in curVal) && (isPlainObject(newVal) || isArray(newVal))) {
curVal.set(newVal, remove);
}
Expand Down Expand Up @@ -259,14 +259,9 @@ var DefineMap = Construct.extend("DefineMap",{
});

// Add necessary event methods to this object.
for(var prop in define.eventsProto) {
DefineMap[prop] = define.eventsProto[prop];
Object.defineProperty(DefineMap.prototype, prop, {
enumerable:false,
value: define.eventsProto[prop],
writable: true
});
}
define.mixinEvents(DefineMap, true);
define.mixinEvents(DefineMap.prototype);

types.DefineMap = DefineMap;
types.DefaultMap = DefineMap;

Expand Down

0 comments on commit aead3d7

Please sign in to comment.