Skip to content

Commit

Permalink
Unbreak accidental back-compat break with event optimization
Browse files Browse the repository at this point in the history
This was supposed to be purely additive. See here for more details:

#1949 (comment)
  • Loading branch information
dead-claudia committed Sep 3, 2018
1 parent aa7f562 commit d618f48
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 2 deletions.
2 changes: 1 addition & 1 deletion docs/change-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#### News

- API: Introduction of `m.redraw.sync()` ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592))
- API: Event handlers may also be objects with `handleEvent` methods ([#1939](https://github.com/MithrilJS/mithril.js/issues/1939)).
- API: Event handlers may also be objects with `handleEvent` methods ([#1949](https://github.com/MithrilJS/mithril.js/pull/1949), [#2222](https://github.com/MithrilJS/mithril.js/pull/2222)).
- API: `m.route.link` accepts an optional `options` object ([#1930](https://github.com/MithrilJS/mithril.js/pull/1930))
- API: `m.request` better error message on JSON parse error - ([#2195](https://github.com/MithrilJS/mithril.js/pull/2195), [@codeclown](https://github.com/codeclown))
- API: `m.request` supports `timeout` as attr - ([#1966](https://github.com/MithrilJS/mithril.js/pull/1966))
Expand Down
9 changes: 8 additions & 1 deletion render/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -802,13 +802,20 @@ module.exports = function($window) {
// 4. The event name is remapped to the handler before calling it.
// 5. In function-based event handlers, `ev.target === this`. We replicate
// that below.
// 6. In function-based event handlers, `return false` prevents the default
// action and stops event propagation. We replicate that below.
function EventDict() {}
EventDict.prototype = Object.create(null)
EventDict.prototype.handleEvent = function (ev) {
var handler = this["on" + ev.type]
if (typeof handler === "function") handler.call(ev.target, ev)
var result
if (typeof handler === "function") result = handler.call(ev.target, ev)
else if (typeof handler.handleEvent === "function") handler.handleEvent(ev)
if (typeof onevent === "function") onevent.call(ev.target, ev)
if (result === false) {
ev.preventDefault()
ev.stopPropagation()
}
}

//event
Expand Down
47 changes: 47 additions & 0 deletions render/tests/test-event.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,29 @@ o.spec("event", function() {
o(onevent.this).equals(div.dom)
o(onevent.args[0].type).equals("click")
o(onevent.args[0].target).equals(div.dom)
o(e.defaultPrevented).equals(false)
o(e.$propagationStopped).equals(false)
})

o("handles onclick returning false", function() {
var spy = o.spy(function () { return false })
var div = {tag: "div", attrs: {onclick: spy}}
var e = $window.document.createEvent("MouseEvents")
e.initEvent("click", true, true)

render(root, [div])
div.dom.dispatchEvent(e)

o(spy.callCount).equals(1)
o(spy.this).equals(div.dom)
o(spy.args[0].type).equals("click")
o(spy.args[0].target).equals(div.dom)
o(onevent.callCount).equals(1)
o(onevent.this).equals(div.dom)
o(onevent.args[0].type).equals("click")
o(onevent.args[0].target).equals(div.dom)
o(e.defaultPrevented).equals(true)
o(e.$propagationStopped).equals(true)
})

o("handles click EventListener object", function() {
Expand All @@ -52,6 +75,30 @@ o.spec("event", function() {
o(onevent.this).equals(div.dom)
o(onevent.args[0].type).equals("click")
o(onevent.args[0].target).equals(div.dom)
o(e.defaultPrevented).equals(false)
o(e.$propagationStopped).equals(false)
})

o("handles click EventListener object returning false", function() {
var spy = o.spy(function () { return false })
var listener = {handleEvent: spy}
var div = {tag: "div", attrs: {onclick: listener}}
var e = $window.document.createEvent("MouseEvents")
e.initEvent("click", true, true)

render(root, [div])
div.dom.dispatchEvent(e)

o(spy.callCount).equals(1)
o(spy.this).equals(listener)
o(spy.args[0].type).equals("click")
o(spy.args[0].target).equals(div.dom)
o(onevent.callCount).equals(1)
o(onevent.this).equals(div.dom)
o(onevent.args[0].type).equals("click")
o(onevent.args[0].target).equals(div.dom)
o(e.defaultPrevented).equals(false)
o(e.$propagationStopped).equals(false)
})

o("removes event", function() {
Expand Down
8 changes: 8 additions & 0 deletions test-utils/domMock.js
Original file line number Diff line number Diff line change
Expand Up @@ -364,10 +364,18 @@ module.exports = function(options) {
e.preventDefault = function() {
prevented = true
}
Object.defineProperty(e, "defaultPrevented", {
enumerable: true,
get: function () { return prevented }
})
var stopped = false
e.stopPropagation = function() {
stopped = true
}
Object.defineProperty(e, "$propagationStopped", {
enumerable: true,
get: function () { return prevented }
})
e.eventPhase = 1
try {
for (var i = parents.length - 1; 0 <= i; i--) {
Expand Down

0 comments on commit d618f48

Please sign in to comment.