Unbreak accidental back-compat break with event optimization (#2222)

This was supposed to be purely additive. See here for more details:

https://github.com/MithrilJS/mithril.js/pull/1949#issuecomment-417824513
This commit is contained in:
Isiah Meadows 2018-09-18 10:14:21 -04:00 committed by GitHub
parent f4ddcc4b24
commit c703b03253
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 80 additions and 11 deletions

View file

@ -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))

View file

@ -1182,13 +1182,20 @@ var coreRenderer = function($window) {
// 4. The event name is remapped to the handler0 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 handler0 = this["on" + ev.type]
if (typeof handler0 === "function") handler0.call(ev.target, ev)
var result
if (typeof handler0 === "function") result = handler0.call(ev.target, ev)
else if (typeof handler0.handleEvent === "function") handler0.handleEvent(ev)
if (typeof onevent === "function") onevent.call(ev.target, ev)
if (result === false) {
ev.preventDefault()
ev.stopPropagation()
}
}
//event
function updateEvent(vnode, key2, value) {

16
mithril.min.js vendored
View file

@ -35,14 +35,14 @@ typeof d)){if("o"===b[0]&&"n"===b[1])return U(a,b,d);if("xlink:"===b.slice(0,6))
null!==c&&a.dom.value===e||"option"===a.tag&&null!==c&&a.dom.value===e))return;"input"===a.tag&&"type"===b?a.dom.setAttribute(b,d):a.dom[b]=d}}}function w(a){return"oninit"===a||"oncreate"===a||"onupdate"===a||"onremove"===a||"onbeforeremove"===a||"onbeforeupdate"===a}function S(a){return"href"===a||"list"===a||"form"===a||"width"===a||"height"===a}function T(a,b,c){if(null!=b&&null!=c&&"object"===typeof b&&"object"===typeof c&&c!==b){for(var d in c)c[d]!==b[d]&&(a.style[d]=c[d]);for(d in b)d in c||
(a.style[d]="")}else if(b===c&&(a.style.cssText="",b=null),null==c)a.style.cssText="";else if("string"===typeof c)a.style.cssText=c;else for(d in"string"===typeof b&&(a.style.cssText=""),c)a.style[d]=c[d]}function M(){}function U(a,b,c){null!=a.events?a.events[b]!==c&&(null==c||"function"!==typeof c&&"object"!==typeof c?(null!=a.events[b]&&a.dom.removeEventListener(b.slice(2),a.events,!1),a.events[b]=void 0):(null==a.events[b]&&a.dom.addEventListener(b.slice(2),a.events,!1),a.events[b]=c)):null==
c||"function"!==typeof c&&"object"!==typeof c||(a.events=new M,a.dom.addEventListener(b.slice(2),a.events,!1),a.events[b]=c)}function N(a,b,c){"function"===typeof a.oninit&&e.call(a.oninit,b);"function"===typeof a.oncreate&&c.push(e.bind(a.oncreate,b))}function L(a,b,c){"function"===typeof a.onupdate&&c.push(e.bind(a.onupdate,b))}var D=a.document;D.createDocumentFragment();var H={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"},I,J={caption:"table",thead:"table",tbody:"table",
tfoot:"table",tr:"tbody",th:"tr",td:"tr",colgroup:"table",col:"colgroup"};M.prototype=Object.create(null);M.prototype.handleEvent=function(a){var b=this["on"+a.type];"function"===typeof b?b.call(a.target,a):"function"===typeof b.handleEvent&&b.handleEvent(a);"function"===typeof I&&I.call(a.target,a)};return{render:function(a,b){if(!a)throw Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.");var c=[],d=D.activeElement,e=a.namespaceURI;null==a.vnodes&&(a.textContent=
"");Array.isArray(b)||(b=[b]);k(a,a.vnodes,z.normalizeChildren(b),c,null,"http://www.w3.org/1999/xhtml"===e?void 0:e);a.vnodes=b;null!=d&&D.activeElement!==d&&"function"===typeof d.focus&&d.focus();for(d=0;d<c.length;d++)c[d]()},setEventCallback:function(a){return I=a}}},J=function(a,d){function e(a){a=h.indexOf(a);-1<a&&h.splice(a,2)}function g(){if(k)throw Error("Nested m.redraw.sync() call");k=!0;for(var a=1;a<h.length;a+=2)try{h[a]()}catch(l){"undefined"!==typeof console&&console.error(l)}k=!1}
var q=V(a);q.setEventCallback(function(a){!1===a.redraw?a.redraw=void 0:n()});var h=[],k=!1,n=(d||X)(g);n.sync=g;return{subscribe:function(a,d){e(a);h.push(a,d)},unsubscribe:e,redraw:n,render:q.render}}(window);O.setCompletionCallback(J.redraw);w.mount=function(a){return function(d,e){if(null===e)a.render(d,[]),a.unsubscribe(d);else{if(null==e.view&&"function"!==typeof e)throw Error("m.mount(element, component) expects a component, not a vnode");var g=function(){a.render(d,z(e))};a.subscribe(d,g);
g()}}}(J);var ba=p,P=function(a){if(""===a||null==a)return{};"?"===a.charAt(0)&&(a=a.slice(1));a=a.split("&");for(var d={},e={},g=0;g<a.length;g++){var q=a[g].split("="),h=decodeURIComponent(q[0]);q=2===q.length?decodeURIComponent(q[1]):"";"true"===q?q=!0:"false"===q&&(q=!1);var k=h.split(/\]\[?|\[/),n=d;-1<h.indexOf("[")&&k.pop();for(var m=0;m<k.length;m++){h=k[m];var l=k[m+1];l=""==l||!isNaN(parseInt(l,10));var p=m===k.length-1;""===h&&(h=k.slice(0,m).join(),null==e[h]&&(e[h]=0),h=e[h]++);null==
n[h]&&(n[h]=p?q:l?[]:{});n=n[h]}}return d},ca=function(a){function d(d){var e=a.location[d].replace(/(?:%[a-f89][a-f0-9])+/gim,decodeURIComponent);"pathname"===d&&"/"!==e[0]&&(e="/"+e);return e}function e(a){return function(){null==k&&(k=h(function(){k=null;a()}))}}function g(a,d,e){var c=a.indexOf("?"),g=a.indexOf("#"),k=-1<c?c:-1<g?g:a.length;if(-1<c){c=P(a.slice(c+1,-1<g?g:a.length));for(var h in c)d[h]=c[h]}if(-1<g)for(h in d=P(a.slice(g+1)),d)e[h]=d[h];return a.slice(0,k)}var q="function"===
typeof a.history.pushState,h="function"===typeof setImmediate?setImmediate:setTimeout,k,n={prefix:"#!",getPath:function(){switch(n.prefix.charAt(0)){case "#":return d("hash").slice(n.prefix.length);case "?":return d("search").slice(n.prefix.length)+d("hash");default:return d("pathname").slice(n.prefix.length)+d("search")+d("hash")}},setPath:function(d,e,h){var c={},k={};d=g(d,c,k);if(null!=e){for(var m in e)c[m]=e[m];d=d.replace(/:([^\/]+)/g,function(a,d){delete c[d];return e[d]})}(m=I(c))&&(d+="?"+
m);(k=I(k))&&(d+="#"+k);q?(k=h?h.state:null,m=h?h.title:null,a.onpopstate(),h&&h.replace?a.history.replaceState(k,m,n.prefix+d):a.history.pushState(k,m,n.prefix+d)):a.location.href=n.prefix+d},defineRoutes:function(d,k,h){function c(){var c=n.getPath(),e={},m=g(c,e,e),l=a.history.state;if(null!=l)for(var q in l)e[q]=l[q];for(var p in d)if(l=new RegExp("^"+p.replace(/:[^\/]+?\.{3}/g,"(.*?)").replace(/:[^\/]+/g,"([^\\/]+)")+"/?$"),l.test(m)){m.replace(l,function(){for(var a=p.match(/:[^\/]+/g)||[],
g=[].slice.call(arguments,1,-2),h=0;h<a.length;h++)e[a[h].replace(/:|\./g,"")]=decodeURIComponent(g[h]);k(d[p],e,c,p)});return}h(c,e)}q?a.onpopstate=e(c):"#"===n.prefix.charAt(0)&&(a.onhashchange=c);c()}};return n};w.route=function(a,d){var e=ca(a),g=function(a){return a},p,h,k,n,m,l=function(a,l,q){function c(){null!=p&&d.render(a,p(z(h,k.key,k)))}if(null==a)throw Error("Ensure the DOM element that was passed to `m.route` is not undefined");var x=function(){c();x=d.redraw};d.subscribe(a,c);var w=
tfoot:"table",tr:"tbody",th:"tr",td:"tr",colgroup:"table",col:"colgroup"};M.prototype=Object.create(null);M.prototype.handleEvent=function(a){var b=this["on"+a.type],c;"function"===typeof b?c=b.call(a.target,a):"function"===typeof b.handleEvent&&b.handleEvent(a);"function"===typeof I&&I.call(a.target,a);!1===c&&(a.preventDefault(),a.stopPropagation())};return{render:function(a,b){if(!a)throw Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.");var c=[],d=D.activeElement,
e=a.namespaceURI;null==a.vnodes&&(a.textContent="");Array.isArray(b)||(b=[b]);k(a,a.vnodes,z.normalizeChildren(b),c,null,"http://www.w3.org/1999/xhtml"===e?void 0:e);a.vnodes=b;null!=d&&D.activeElement!==d&&"function"===typeof d.focus&&d.focus();for(d=0;d<c.length;d++)c[d]()},setEventCallback:function(a){return I=a}}},J=function(a,d){function e(a){a=h.indexOf(a);-1<a&&h.splice(a,2)}function g(){if(k)throw Error("Nested m.redraw.sync() call");k=!0;for(var a=1;a<h.length;a+=2)try{h[a]()}catch(l){"undefined"!==
typeof console&&console.error(l)}k=!1}var q=V(a);q.setEventCallback(function(a){!1===a.redraw?a.redraw=void 0:n()});var h=[],k=!1,n=(d||X)(g);n.sync=g;return{subscribe:function(a,d){e(a);h.push(a,d)},unsubscribe:e,redraw:n,render:q.render}}(window);O.setCompletionCallback(J.redraw);w.mount=function(a){return function(d,e){if(null===e)a.render(d,[]),a.unsubscribe(d);else{if(null==e.view&&"function"!==typeof e)throw Error("m.mount(element, component) expects a component, not a vnode");var g=function(){a.render(d,
z(e))};a.subscribe(d,g);g()}}}(J);var ba=p,P=function(a){if(""===a||null==a)return{};"?"===a.charAt(0)&&(a=a.slice(1));a=a.split("&");for(var d={},e={},g=0;g<a.length;g++){var q=a[g].split("="),h=decodeURIComponent(q[0]);q=2===q.length?decodeURIComponent(q[1]):"";"true"===q?q=!0:"false"===q&&(q=!1);var k=h.split(/\]\[?|\[/),n=d;-1<h.indexOf("[")&&k.pop();for(var m=0;m<k.length;m++){h=k[m];var l=k[m+1];l=""==l||!isNaN(parseInt(l,10));var p=m===k.length-1;""===h&&(h=k.slice(0,m).join(),null==e[h]&&
(e[h]=0),h=e[h]++);null==n[h]&&(n[h]=p?q:l?[]:{});n=n[h]}}return d},ca=function(a){function d(d){var e=a.location[d].replace(/(?:%[a-f89][a-f0-9])+/gim,decodeURIComponent);"pathname"===d&&"/"!==e[0]&&(e="/"+e);return e}function e(a){return function(){null==k&&(k=h(function(){k=null;a()}))}}function g(a,d,e){var c=a.indexOf("?"),g=a.indexOf("#"),k=-1<c?c:-1<g?g:a.length;if(-1<c){c=P(a.slice(c+1,-1<g?g:a.length));for(var h in c)d[h]=c[h]}if(-1<g)for(h in d=P(a.slice(g+1)),d)e[h]=d[h];return a.slice(0,
k)}var q="function"===typeof a.history.pushState,h="function"===typeof setImmediate?setImmediate:setTimeout,k,n={prefix:"#!",getPath:function(){switch(n.prefix.charAt(0)){case "#":return d("hash").slice(n.prefix.length);case "?":return d("search").slice(n.prefix.length)+d("hash");default:return d("pathname").slice(n.prefix.length)+d("search")+d("hash")}},setPath:function(d,e,h){var c={},k={};d=g(d,c,k);if(null!=e){for(var m in e)c[m]=e[m];d=d.replace(/:([^\/]+)/g,function(a,d){delete c[d];return e[d]})}(m=
I(c))&&(d+="?"+m);(k=I(k))&&(d+="#"+k);q?(k=h?h.state:null,m=h?h.title:null,a.onpopstate(),h&&h.replace?a.history.replaceState(k,m,n.prefix+d):a.history.pushState(k,m,n.prefix+d)):a.location.href=n.prefix+d},defineRoutes:function(d,k,h){function c(){var c=n.getPath(),e={},m=g(c,e,e),l=a.history.state;if(null!=l)for(var q in l)e[q]=l[q];for(var p in d)if(l=new RegExp("^"+p.replace(/:[^\/]+?\.{3}/g,"(.*?)").replace(/:[^\/]+/g,"([^\\/]+)")+"/?$"),l.test(m)){m.replace(l,function(){for(var a=p.match(/:[^\/]+/g)||
[],g=[].slice.call(arguments,1,-2),h=0;h<a.length;h++)e[a[h].replace(/:|\./g,"")]=decodeURIComponent(g[h]);k(d[p],e,c,p)});return}h(c,e)}q?a.onpopstate=e(c):"#"===n.prefix.charAt(0)&&(a.onhashchange=c);c()}};return n};w.route=function(a,d){var e=ca(a),g=function(a){return a},p,h,k,n,m,l=function(a,l,q){function c(){null!=p&&d.render(a,p(z(h,k.key,k)))}if(null==a)throw Error("Ensure the DOM element that was passed to `m.route` is not undefined");var x=function(){c();x=d.redraw};d.subscribe(a,c);var w=
function(a){if(a!==l)e.setPath(l,null,{replace:!0});else throw Error("Could not resolve default route "+l);};e.defineRoutes(q,function(a,c,d){var e=m=function(a,l){e===m&&(h=null==l||"function"!==typeof l.view&&"function"!==typeof l?"div":l,k=c,n=d,m=null,p=(a.render||g).bind(a),x())};a.view||"function"===typeof a?e({},a):a.onmatch?ba.resolve(a.onmatch(c,d)).then(function(c){e(a,c)},w):e(a,"div")},w)};l.set=function(a,d,g){null!=m&&(g=g||{},g.replace=!0);m=null;e.setPath(a,d,g)};l.get=function(){return n};
l.prefix=function(a){e.prefix=a};var w=function(a,d){d.dom.setAttribute("href",e.prefix+d.attrs.href);d.dom.onclick=function(c){c.ctrlKey||c.metaKey||c.shiftKey||2===c.which||(c.preventDefault(),c.redraw=!1,c=this.getAttribute("href"),0===c.indexOf(e.prefix)&&(c=c.slice(e.prefix.length)),l.set(c,void 0,a))}};l.link=function(a){return null==a.tag?w.bind(w,a):w({},a)};l.param=function(a){return"undefined"!==typeof k&&"undefined"!==typeof a?k[a]:k};return l}(window,J);w.withAttr=function(a,d,e){return function(g){d.call(e||
this,a in g.currentTarget?g.currentTarget[a]:g.currentTarget.getAttribute(a))}};var da=V(window);w.render=da.render;w.redraw=J.redraw;w.request=O.request;w.jsonp=O.jsonp;w.parseQueryString=P;w.buildQueryString=I;w.version="1.1.3";w.vnode=z;w.PromisePolyfill=p;"undefined"!==typeof module?module.exports=w:window.m=w})();

View file

@ -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

View file

@ -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() {
@ -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() {

View file

@ -364,10 +364,18 @@ module.exports = function(options) {
e.preventDefault = function() {
prevented = true
}
Object.defineProperty(e, "$defaultPrevented", {
configurable: true,
get: function () { return prevented }
})
var stopped = false
e.stopPropagation = function() {
stopped = true
}
Object.defineProperty(e, "$propagationStopped", {
configurable: true,
get: function () { return prevented }
})
e.eventPhase = 1
try {
for (var i = parents.length - 1; 0 <= i; i--) {