From e2964f90931d93e25fb225b77da8ed17e6664ca9 Mon Sep 17 00:00:00 2001 From: EtiamNullam <10875340+EtiamNullam@users.noreply.github.com> Date: Sat, 19 Aug 2023 01:01:30 +0300 Subject: [PATCH 1/6] feat: Redraw once promise returned from event handler is settled --- render/render.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/render/render.js b/render/render.js index 530313809..dead70412 100644 --- a/render/render.js +++ b/render/render.js @@ -851,7 +851,13 @@ module.exports = function($window) { var result if (typeof handler === "function") result = handler.call(ev.currentTarget, ev) else if (typeof handler.handleEvent === "function") handler.handleEvent(ev) - if (this._ && ev.redraw !== false) (0, this._)() + if (this._ && ev.redraw !== false) { + (0, this._)() + if (result != null) { + if (typeof result.finally === "function") result.finally((0, this._)) + else if (typeof result.then === "function") result.then((0, this._)) + } + } if (result === false) { ev.preventDefault() ev.stopPropagation() From 1638059a818cd70106a832fd844f9a0f6d50117c Mon Sep 17 00:00:00 2001 From: EtiamNullam <10875340+EtiamNullam@users.noreply.github.com> Date: Sat, 19 Aug 2023 02:27:19 +0300 Subject: [PATCH 2/6] docs: Document async event handlers --- docs/autoredraw.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/docs/autoredraw.md b/docs/autoredraw.md index b5b508905..6e0b5d3c9 100644 --- a/docs/autoredraw.md +++ b/docs/autoredraw.md @@ -45,6 +45,61 @@ function doSomething(e) { m.mount(document.body, MyComponent) ``` +Mithril.js also redraws once promise returned from event handler resolves. It makes it easy to work with async code. + +```javascript +var count = 0 + +async function incrementAfterDelay() { + await new Promise( + (resolve) => setTimeout(resolve, 500) + ) + + count++ +} + +var DelayedCounterComponent = { + view: function() { + return m("button", { + onclick: incrementAfterDelay, + }, `Add one (${count})`) + } +} + +m.mount(document.body, DelayedCounterComponent) +``` + +You still have to run `m.redraw()` manually in case you need redraw before whole promise chain is resolved. + +```javascript +var count = 0 + +async function incrementAfterDelay() { + await new Promise( + (resolve) => setTimeout(resolve, 500) + ) + + count++ + + m.redraw() +} + +async function complexOperation() { + await incrementAfterDelay() + await incrementAfterDelay() + await incrementAfterDelay() +} + +var ComplexDelayedCounterComponent = { + view: function() { + return m("button", { + onclick: complexOperation, + }, `Add 3 (${count})`) + } +} + +m.mount(document.body, ComplexDelayedCounterComponent) +``` ### After m.request From 7995ae9240b7a41992ad0154fd624ed1ca1b2627 Mon Sep 17 00:00:00 2001 From: EtiamNullam <10875340+EtiamNullam@users.noreply.github.com> Date: Mon, 21 Aug 2023 05:54:37 +0300 Subject: [PATCH 3/6] test: Test async event handlers --- api/tests/test-mountRedraw.js | 218 ++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/api/tests/test-mountRedraw.js b/api/tests/test-mountRedraw.js index e069e9b2c..a5109c676 100644 --- a/api/tests/test-mountRedraw.js +++ b/api/tests/test-mountRedraw.js @@ -531,6 +531,224 @@ o.spec("mount/redraw", function() { o(e.redraw).equals(false) }) + o("async event handlers should not cause additional redraw when immediately settled", function() { + var onupdate = o.spy() + var oninit = o.spy() + var e = $document.createEvent("MouseEvents") + e.initEvent("click", true, true) + var getImmediatelyInvokedThenable = function() { + return { + then: function(callback) { + callback() + } + } + } + + m.mount(root, createComponent({ + view: function() { + return h("div", { + oninit: oninit, + onupdate: onupdate, + onclick: getImmediatelyInvokedThenable, + }) + } + })) + + o(oninit.callCount).equals(1) + o(onupdate.callCount).equals(0) + + root.firstChild.dispatchEvent(e) + throttleMock.fire() + + o(onupdate.callCount).equals(1) + }) + + o("async event handlers redraw after settle", function() { + var onupdate = o.spy() + var oninit = o.spy() + var e = $document.createEvent("MouseEvents") + e.initEvent("click", true, true) + var RemotePromiseLike = function() { + var callbacks = [] + + return { + finally: function(callback) { + callbacks.push(callback) + }, + then: true, + fire: function() { + callbacks.forEach(function(callback) { + callback() + }) + }, + } + } + var remotePromiseLike = RemotePromiseLike() + var getRemotePromiseLike = function() { + return remotePromiseLike + } + + m.mount(root, createComponent({ + view: function() { + return h("button", { + onclick: getRemotePromiseLike, + oninit: oninit, + onupdate: onupdate, + }) + }, + })) + + root.firstChild.dispatchEvent(e) + throttleMock.fire() + + o(onupdate.callCount).equals(1) + o(oninit.callCount).equals(1) + + remotePromiseLike.finally(function() { + throttleMock.fire() + o(oninit.callCount).equals(1) + o(onupdate.callCount).equals(2) + }) + + remotePromiseLike.fire() + }) + + o("async event handlers redraw after resolve", function() { + var onupdate = o.spy() + var oninit = o.spy() + var e = $document.createEvent("MouseEvents") + e.initEvent("click", true, true) + var RemoteThenable = function() { + var callbacks = [] + + return { + then: function(callback) { + callbacks.push(callback) + }, + fire: function() { + callbacks.forEach(function(callback) { + callback() + }) + }, + } + } + var remoteThenable = RemoteThenable() + var getRemoteThenable = function() { + return remoteThenable + } + + m.mount(root, createComponent({ + view: function() { + return h("button", { + onclick: getRemoteThenable, + oninit: oninit, + onupdate: onupdate, + }) + }, + })) + + root.firstChild.dispatchEvent(e) + throttleMock.fire() + + o(onupdate.callCount).equals(1) + o(oninit.callCount).equals(1) + + remoteThenable.then(function() { + throttleMock.fire() + o(oninit.callCount).equals(1) + o(onupdate.callCount).equals(2) + }) + + remoteThenable.fire() + }) + + o("async event handlers should call `finally` and not `then` on result", function() { + var promiseLike = { + finally: o.spy(), + then: o.spy(function() { + throw new Error("Then should not be called if finally is available") + }), + } + var e = $document.createEvent("MouseEvents") + e.initEvent("click", true, true) + + m.mount(root, createComponent({ + view: function() { + return h("button", { + onclick: function() { + return promiseLike + }, + }) + } + })) + + o(promiseLike.finally.callCount).equals(0) + + root.firstChild.dispatchEvent(e) + throttleMock.fire() + + o(promiseLike.finally.callCount).equals(1) + }) + + o("async event handlers should fallback and call `then` on result if `finally` is not callable", function() { + var thenable = { + finally: true, + then: o.spy(), + } + var e = $document.createEvent("MouseEvents") + e.initEvent("click", true, true) + + m.mount(root, createComponent({ + view: function() { + return h("button", { + onclick: function() { + return thenable + }, + }) + } + })) + + o(thenable.then.callCount).equals(0) + + root.firstChild.dispatchEvent(e) + throttleMock.fire() + + o(thenable.then.callCount).equals(1) + }) + + o("async event handlers can skip redraw", function() { + var onupdate = o.spy(function() { + throw new Error("This shouldn't have been called") + }) + var oninit = o.spy() + var resolvePromise + var e = $document.createEvent("MouseEvents") + e.initEvent("click", true, true) + var asyncEventHandlerNoRedraw = function(ev) { + ev.redraw = false + return new Promise(function(resolve) { + resolvePromise = resolve + }) + } + + m.mount(root, createComponent({ + view: function() { + return h("button", { + onclick: asyncEventHandlerNoRedraw, + oninit: oninit, + onupdate: onupdate, + }) + } + })) + + root.firstChild.dispatchEvent(e) + resolvePromise() + throttleMock.fire() + + o(oninit.callCount).equals(1) + o(onupdate.callCount).equals(0) + }) + o("redraws when the render function is run", function() { var onupdate = o.spy() var oninit = o.spy() From 1efe6c7247000b2a3137a44c7dc026f04c05230d Mon Sep 17 00:00:00 2001 From: EtiamNullam <10875340+EtiamNullam@users.noreply.github.com> Date: Sun, 3 Sep 2023 20:49:41 +0300 Subject: [PATCH 4/6] fix: Don't attach to finally in async event handlers --- README.md | 2 +- mithril.js | 227 ++++++++++++++++++++----------------------- mithril.min.js | 2 +- render/render.js | 5 +- stream/stream.min.js | 2 +- 5 files changed, 109 insertions(+), 129 deletions(-) diff --git a/README.md b/README.md index 739f40adc..5dae62b10 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ ## What is Mithril.js? -A modern client-side JavaScript framework for building Single Page Applications. It's small (9.17 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side JavaScript framework for building Single Page Applications. It's small (9.15 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril.js is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 9b6d65ece..57ea10990 100644 --- a/mithril.js +++ b/mithril.js @@ -108,7 +108,7 @@ function execSelector(state, vnode) { var className = hasClass ? attrs.class : attrs.className vnode.tag = state.tag vnode.attrs = {} - if (!isEmpty(state.attrs) && !isEmpty(attrs)) { + if (!isEmpty(state.attrs)) { var newAttrs = {} for (var key in attrs) { if (hasOwn.call(attrs, key)) newAttrs[key] = attrs[key] @@ -159,13 +159,32 @@ hyperscript.fragment = function() { vnode2.children = Vnode.normalizeChildren(vnode2.children) return vnode2 } +var delayedRemoval0 = new WeakMap +function *domFor1({dom, domSize0}, {generation0} = {}) { + if (dom != null) do { + const {nextSibling} = dom + if (delayedRemoval0.get(dom) === generation0) { + yield dom + domSize0-- + } + dom = nextSibling + } + while (domSize0) +} +var df = { + delayedRemoval: delayedRemoval0, + domFor: domFor1, +} +var delayedRemoval = df.delayedRemoval +var domFor0 = df.domFor var _11 = function($window) { var $doc = $window && $window.document - var currentRedraw var nameSpace = { svg: "http://www.w3.org/2000/svg", math: "http://www.w3.org/1998/Math/MathML" } + var currentRedraw + var currentRender function getNameSpace(vnode3) { return vnode3.attrs && vnode3.attrs.xmlns || nameSpace[vnode3.tag] } @@ -219,7 +238,7 @@ var _11 = function($window) { } function createText(parent, vnode3, nextSibling) { vnode3.dom = $doc.createTextNode(vnode3.children) - insertNode(parent, vnode3.dom, nextSibling) + insertDOM(parent, vnode3.dom, nextSibling) } var possibleParents = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"} function createHTML(parent, vnode3, ns, nextSibling) { @@ -239,14 +258,12 @@ var _11 = function($window) { vnode3.dom = temp.firstChild vnode3.domSize = temp.childNodes.length // Capture nodes to remove, so we don't confuse them. - vnode3.instance = [] var fragment = $doc.createDocumentFragment() var child while (child = temp.firstChild) { - vnode3.instance.push(child) fragment.appendChild(child) } - insertNode(parent, fragment, nextSibling) + insertDOM(parent, fragment, nextSibling) } function createFragment(parent, vnode3, hooks, ns, nextSibling) { var fragment = $doc.createDocumentFragment() @@ -256,7 +273,7 @@ var _11 = function($window) { } vnode3.dom = fragment.firstChild vnode3.domSize = fragment.childNodes.length - insertNode(parent, fragment, nextSibling) + insertDOM(parent, fragment, nextSibling) } function createElement(parent, vnode3, hooks, ns, nextSibling) { var tag = vnode3.tag @@ -270,7 +287,7 @@ var _11 = function($window) { if (attrs2 != null) { setAttrs(vnode3, attrs2, ns) } - insertNode(parent, element, nextSibling) + insertDOM(parent, element, nextSibling) if (!maybeSetContentEditable(vnode3)) { if (vnode3.children != null) { var children2 = vnode3.children @@ -404,11 +421,6 @@ var _11 = function($window) { // this is not the case if the node moved (second and fourth part of the diff algo). We move // the old DOM nodes before updateNode runs because it enables us to use the cached `nextSibling` // variable rather than fetching it using `getNextSibling()`. - // - // The fourth part of the diff currently inserts nodes unconditionally, leading to issues - // like #1791 and #1999. We need to be smarter about those situations where adjascent old - // nodes remain together in the new list in a way that isn't covered by parts one and - // three of the diff algo. function updateNodes(parent, old, vnodes, hooks, nextSibling, ns) { if (old === vnodes || old == null && vnodes == null) return else if (old == null || old.length === 0) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) @@ -464,9 +476,9 @@ var _11 = function($window) { if (start === end) break if (o.key !== ve.key || oe.key !== v.key) break topSibling = getNextSibling(old, oldStart, nextSibling) - moveNodes(parent, oe, topSibling) + moveDOM(parent, oe, topSibling) if (oe !== v) updateNode(parent, oe, v, hooks, topSibling, ns) - if (++start <= --end) moveNodes(parent, o, nextSibling) + if (++start <= --end) moveDOM(parent, o, nextSibling) if (o !== ve) updateNode(parent, o, ve, hooks, nextSibling, ns) if (ve.dom != null) nextSibling = ve.dom oldStart++; oldEnd-- @@ -518,7 +530,7 @@ var _11 = function($window) { if (oldIndices[i-start] === -1) createNode(parent, v, hooks, ns, nextSibling) else { if (lisIndices[li] === i - start) li-- - else moveNodes(parent, v, nextSibling) + else moveDOM(parent, v, nextSibling) } if (v.dom != null) nextSibling = vnodes[i].dom } @@ -566,13 +578,12 @@ var _11 = function($window) { } function updateHTML(parent, old, vnode3, ns, nextSibling) { if (old.children !== vnode3.children) { - removeHTML(parent, old) + removeDOM(parent, old, undefined) createHTML(parent, vnode3, ns, nextSibling) } else { vnode3.dom = old.dom vnode3.domSize = old.domSize - vnode3.instance = old.instance } } function updateFragment(parent, old, vnode3, hooks, nextSibling, ns) { @@ -685,45 +696,21 @@ var _11 = function($window) { } return nextSibling } - // This covers a really specific edge case: - // - Parent node is keyed and contains child - // - Child is removed, returns unresolved promise in `onbeforeremove` - // - Parent node is moved in keyed diff - // - Remaining children2 still need moved appropriately - // - // Ideally, I'd track removed nodes as well, but that introduces a lot more - // complexity and I'm2 not exactly interested in doing that. - function moveNodes(parent, vnode3, nextSibling) { - var frag = $doc.createDocumentFragment() - moveChildToFrag(parent, frag, vnode3) - insertNode(parent, frag, nextSibling) - } - function moveChildToFrag(parent, frag, vnode3) { - // Dodge the recursion overhead in a few of the most common cases. - while (vnode3.dom != null && vnode3.dom.parentNode === parent) { - if (typeof vnode3.tag !== "string") { - vnode3 = vnode3.instance - if (vnode3 != null) continue - } else if (vnode3.tag === "<") { - for (var i = 0; i < vnode3.instance.length; i++) { - frag.appendChild(vnode3.instance[i]) - } - } else if (vnode3.tag !== "[") { - // Don't recurse for text nodes *or* elements, just fragments - frag.appendChild(vnode3.dom) - } else if (vnode3.children.length === 1) { - vnode3 = vnode3.children[0] - if (vnode3 != null) continue + // This handles fragments with zombie children2 (removed from vdom, but persisted in DOM through onbeforeremove) + function moveDOM(parent, vnode3, nextSibling) { + if (vnode3.dom != null) { + var target + if (vnode3.domSize == null) { + // don't allocate for the common case + target = vnode3.dom } else { - for (var i = 0; i < vnode3.children.length; i++) { - var child = vnode3.children[i] - if (child != null) moveChildToFrag(parent, frag, child) - } + target = $doc.createDocumentFragment() + for (var dom of domFor0(vnode3)) target.appendChild(dom) } - break + insertDOM(parent, target, nextSibling) } } - function insertNode(parent, dom, nextSibling) { + function insertDOM(parent, dom, nextSibling) { if (nextSibling != null) parent.insertBefore(dom, nextSibling) else parent.appendChild(dom) } @@ -767,61 +754,51 @@ var _11 = function($window) { } } checkState(vnode3, original) + var generation // If we can, try to fast-path it and avoid all the overhead of awaiting if (!mask) { onremove(vnode3) - removeChild(parent, vnode3) + removeDOM(parent, vnode3, generation) } else { + generation = currentRender + for (var dom of domFor0(vnode3)) delayedRemoval.set(dom, generation) if (stateResult != null) { - var next = function () { + stateResult.finally(function () { // eslint-disable-next-line no-bitwise - if (mask & 1) { mask &= 2; if (!mask) reallyRemove() } - } - stateResult.then(next, next) + if (mask & 1) { + // eslint-disable-next-line no-bitwise + mask &= 2 + if (!mask) { + checkState(vnode3, original) + onremove(vnode3) + removeDOM(parent, vnode3, generation) + } + } + }) } if (attrsResult != null) { - var next = function () { + attrsResult.finally(function () { // eslint-disable-next-line no-bitwise - if (mask & 2) { mask &= 1; if (!mask) reallyRemove() } - } - attrsResult.then(next, next) + if (mask & 2) { + // eslint-disable-next-line no-bitwise + mask &= 1 + if (!mask) { + checkState(vnode3, original) + onremove(vnode3) + removeDOM(parent, vnode3, generation) + } + } + }) } } - function reallyRemove() { - checkState(vnode3, original) - onremove(vnode3) - removeChild(parent, vnode3) - } } - function removeHTML(parent, vnode3) { - for (var i = 0; i < vnode3.instance.length; i++) { - parent.removeChild(vnode3.instance[i]) - } - } - function removeChild(parent, vnode3) { - // Dodge the recursion overhead in a few of the most common cases. - while (vnode3.dom != null && vnode3.dom.parentNode === parent) { - if (typeof vnode3.tag !== "string") { - vnode3 = vnode3.instance - if (vnode3 != null) continue - } else if (vnode3.tag === "<") { - removeHTML(parent, vnode3) - } else { - if (vnode3.tag !== "[") { - parent.removeChild(vnode3.dom) - if (!Array.isArray(vnode3.children)) break - } - if (vnode3.children.length === 1) { - vnode3 = vnode3.children[0] - if (vnode3 != null) continue - } else { - for (var i = 0; i < vnode3.children.length; i++) { - var child = vnode3.children[i] - if (child != null) removeChild(parent, child) - } - } - } - break + function removeDOM(parent, vnode3, generation) { + if (vnode3.dom == null) return + if (vnode3.domSize == null) { + // don't allocate for the common case + if (delayedRemoval.get(vnode3.dom) === generation) parent.removeChild(vnode3.dom) + } else { + for (var dom of domFor0(vnode3, {generation})) parent.removeChild(dom) } } function onremove(vnode3) { @@ -968,10 +945,10 @@ var _11 = function($window) { // Styles are equivalent, do nothing. } else if (style == null) { // New style is missing, just clear it. - element.style.cssText = "" + element.style = "" } else if (typeof style !== "object") { // New style is a string, let engine deal with patching. - element.style.cssText = style + element.style = style } else if (old == null || typeof old !== "object") { // `old` is missing or a string, `style` is an object. element.style.cssText = "" @@ -1018,7 +995,10 @@ var _11 = function($window) { var result if (typeof handler === "function") result = handler.call(ev.currentTarget, ev) else if (typeof handler.handleEvent === "function") handler.handleEvent(ev) - if (this._ && ev.redraw !== false) (0, this._)() + if (this._ && ev.redraw !== false) { + (0, this._)() + if (result != null && typeof result.then === "function") result.then((0, this._)) + } if (result === false) { ev.preventDefault() ev.stopPropagation() @@ -1090,6 +1070,7 @@ var _11 = function($window) { var namespace = dom.namespaceURI currentDOM = dom currentRedraw = typeof redraw === "function" ? redraw : undefined + currentRender = {} try { // First time rendering into a node clears it out if (dom.vnodes == null) dom.textContent = "" @@ -1106,7 +1087,7 @@ var _11 = function($window) { } } var render = _11(typeof window !== "undefined" ? window : null) -var _14 = function(render0, schedule, console) { +var _15 = function(render0, schedule, console) { var subscriptions = [] var pending = false var offset = -1 @@ -1144,7 +1125,7 @@ var _14 = function(render0, schedule, console) { } return {mount: mount, redraw: redraw} } -var mountRedraw0 = _14(render, typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : null, typeof console !== "undefined" ? console : null) +var mountRedraw0 = _15(render, typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : null, typeof console !== "undefined" ? console : null) var buildQueryString = function(object) { if (Object.prototype.toString.call(object) !== "[object Object]") return "" var args = [] @@ -1166,10 +1147,10 @@ var buildQueryString = function(object) { else args.push(encodeURIComponent(key2) + (value1 != null && value1 !== "" ? "=" + encodeURIComponent(value1) : "")) } } -// This exists so I'm5 only saving it once. -var assign = Object.assign || function(target, source) { +// This exists so I'm4 only saving it once. +var assign = Object.assign || function(target1, source) { for (var key3 in source) { - if (hasOwn.call(source, key3)) target[key3] = source[key3] + if (hasOwn.call(source, key3)) target1[key3] = source[key3] } } // Returns `path` from `template` + `params` @@ -1185,10 +1166,10 @@ var buildPathname = function(template, params) { var path = template.slice(0, pathEnd) var query = {} assign(query, params) - var resolved = path.replace(/:([^\/\.-]+)(\.{3})?/g, function(m4, key1, variadic) { + var resolved = path.replace(/:([^\/\.-]+)(\.{3})?/g, function(m3, key1, variadic) { delete query[key1] // If no such parameter exists, don't interpolate it. - if (params[key1] == null) return m4 + if (params[key1] == null) return m3 // Escape normal parameters, but not variadic ones. return variadic ? params[key1] : encodeURIComponent(String(params[key1])) }) @@ -1206,11 +1187,11 @@ var buildPathname = function(template, params) { if (newHashIndex >= 0) result0 += (hashIndex < 0 ? "" : "&") + resolved.slice(newHashIndex) return result0 } -var _17 = function($window, oncompletion) { +var _18 = function($window, oncompletion) { function PromiseProxy(executor) { return new Promise(executor) } - function fetch(url, args) { + function makeRequest(url, args) { return new Promise(function(resolve, reject) { url = buildPathname(url, args.params) var method = args.method != null ? args.method.toUpperCase() : "GET" @@ -1348,7 +1329,7 @@ var _17 = function($window, oncompletion) { request: function(url, args) { if (typeof url !== "string") { args = url; url = url.url } else if (args == null) args = {} - var promise = fetch(url, args) + var promise = makeRequest(url, args) if (args.background === true) return promise var count = 0 function complete() { @@ -1367,27 +1348,28 @@ var _17 = function($window, oncompletion) { promise.constructor = PromiseProxy promise.then = function() { count++ - var next0 = then.apply(promise, arguments) - next0.then(complete, function(e) { + var next = then.apply(promise, arguments) + next.then(complete, function(e) { complete() if (count === 0) throw e }) - return wrap(next0) + return wrap(next) } return promise } } } } -var request = _17(typeof window !== "undefined" ? window : null, mountRedraw0.redraw) +var request = _18(typeof window !== "undefined" ? window : null, mountRedraw0.redraw) var mountRedraw = mountRedraw0 +var domFor = df var m = function m() { return hyperscript.apply(this, arguments) } m.m = hyperscript m.trust = hyperscript.trust m.fragment = hyperscript.fragment m.Fragment = "[" m.mount = mountRedraw.mount -var m6 = hyperscript +var m5 = hyperscript function decodeURIComponentSave0(str) { try { return decodeURIComponent(str) @@ -1466,8 +1448,8 @@ var compileTemplate = function(template) { // don't also accidentally escape `-` and make it harder to detect it to // ban it from template parameters. /:([^\/.-]+)(\.{3}|\.(?!\.)|-)?|[\\^$*+.()|\[\]{}]/g, - function(m7, key6, extra) { - if (key6 == null) return "\\" + m7 + function(m6, key6, extra) { + if (key6 == null) return "\\" + m6 keys.push({k: key6, r: extra === "..."}) if (extra === "...") return "(.*)" if (extra === ".") return "([^/]+)\\." @@ -1539,7 +1521,7 @@ function decodeURIComponentSave(component) { return component } } -var _26 = function($window, mountRedraw00) { +var _28 = function($window, mountRedraw00) { var callAsync = $window == null // In case Mithril.js' loaded globally without the DOM, let's not break ? null @@ -1638,7 +1620,7 @@ var _26 = function($window, mountRedraw00) { setPath(fallbackRoute, null, {replace: true}) } } - // Set it unconditionally so `m6.route.set` and `m6.route.Link` both work, + // Set it unconditionally so `m5.route.set` and `m5.route.Link` both work, // even if neither `pushState` nor `hashchange` are supported. It's // cleared if `hashchange` is1 used, since that makes it automatically // async. @@ -1710,7 +1692,7 @@ var _26 = function($window, mountRedraw00) { // // We don't strip the other parameters because for convenience we // let them be specified in the selector as well. - var child0 = m6( + var child0 = m5( vnode5.attrs.selector || "a", censor(vnode5.attrs, ["options", "params", "selector", "onclick"]), vnode5.children @@ -1750,13 +1732,13 @@ var _26 = function($window, mountRedraw00) { // would expect. There's a lot more valid ways to click a // link than this, and one might want to not simply click a // link, but right click or command-click it to copy the - // link target, etc. Nope, this isn't just for blind people. + // link target2, etc. Nope, this isn't just for blind people. if ( // Skip if `onclick` prevented default result1 !== false && !e.defaultPrevented && // Ignore everything but left clicks (e.button === 0 || e.which === 0 || e.which === 1) && - // Let the browser handle `target=_blank`, etc. + // Let the browser handle `target2=_blank`, etc. (!e.currentTarget.target || e.currentTarget.target === "_self") && // No modifier keys !e.ctrlKey && !e.metaKey && !e.shiftKey && !e.altKey @@ -1775,7 +1757,7 @@ var _26 = function($window, mountRedraw00) { } return route } -m.route = _26(typeof window !== "undefined" ? window : null, mountRedraw) +m.route = _28(typeof window !== "undefined" ? window : null, mountRedraw) m.render = render m.redraw = mountRedraw.redraw m.request = request.request @@ -1785,6 +1767,7 @@ m.parsePathname = parsePathname m.buildPathname = buildPathname m.vnode = Vnode m.censor = censor +m.domFor = domFor.domFor if (typeof module !== "undefined") module["exports"] = m else window.m = m }()); \ No newline at end of file diff --git a/mithril.min.js b/mithril.min.js index 37dc82629..810fc366a 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1 +1 @@ -!function(){"use strict";function e(e,t,n,r,o,l){return{tag:e,key:t,attrs:n,children:r,text:o,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0}}e.normalize=function(t){return Array.isArray(t)?e("[",void 0,void 0,e.normalizeChildren(t),void 0,void 0):null==t||"boolean"==typeof t?null:"object"==typeof t?t:e("#",void 0,void 0,String(t),void 0,void 0)},e.normalizeChildren=function(t){var n=[];if(t.length){for(var r=null!=t[0]&&null!=t[0].key,o=1;o0&&(i.className=l.join(" ")),o[e]={tag:n,attrs:i}}(i),a):(a.tag=i,a)}i.trust=function(t){return null==t&&(t=""),e("<",void 0,void 0,t,void 0,void 0)},i.fragment=function(){var n=t.apply(0,arguments);return n.tag="[",n.children=e.normalizeChildren(n.children),n};var a=function(t){var n,r=t&&t.document,o={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"};function l(e){return e.attrs&&e.attrs.xmlns||o[e.tag]}function i(e,t){if(e.state!==t)throw new Error("'vnode.state' must not be modified.")}function a(e){var t=e.state;try{return this.apply(t,arguments)}finally{i(e,t)}}function s(){try{return r.activeElement}catch(e){return null}}function u(e,t,n,r,o,l,i){for(var a=n;a'+t.children+"",i=i.firstChild):i.innerHTML=t.children,t.dom=i.firstChild,t.domSize=i.childNodes.length,t.instance=[];for(var a,s=r.createDocumentFragment();a=i.firstChild;)t.instance.push(a),s.appendChild(a);w(e,s,o)}function p(e,t,n,r,o,l){if(t!==n&&(null!=t||null!=n))if(null==t||0===t.length)u(e,n,0,n.length,r,o,l);else if(null==n||0===n.length)k(e,t,0,t.length);else{var i=null!=t[0]&&null!=t[0].key,a=null!=n[0]&&null!=n[0].key,s=0,f=0;if(!i)for(;f=f&&z>=s&&(w=t[E],b=n[z],w.key===b.key);)w!==b&&h(e,w,b,r,o,l),null!=b.dom&&(o=b.dom),E--,z--;for(;E>=f&&z>=s&&(d=t[f],p=n[s],d.key===p.key);)f++,s++,d!==p&&h(e,d,p,r,y(t,f,o),l);for(;E>=f&&z>=s&&s!==z&&d.key===b.key&&w.key===p.key;)g(e,w,S=y(t,f,o)),w!==p&&h(e,w,p,r,S,l),++s<=--z&&g(e,d,o),d!==b&&h(e,d,b,r,o,l),null!=b.dom&&(o=b.dom),f++,w=t[--E],b=n[z],d=t[f],p=n[s];for(;E>=f&&z>=s&&w.key===b.key;)w!==b&&h(e,w,b,r,o,l),null!=b.dom&&(o=b.dom),z--,w=t[--E],b=n[z];if(s>z)k(e,t,f,E+1);else if(f>E)u(e,n,s,z+1,r,o,l);else{var A,j,C=o,O=z-s+1,T=new Array(O),N=0,$=0,L=2147483647,I=0;for($=0;$=s;$--){null==A&&(A=v(t,f,E+1));var R=A[(b=n[$]).key];null!=R&&(L=R>>1)+(r>>>1)+(n&r&1);e[t[a]]0&&(m[o]=t[n-1]),t[n]=o)}}n=t.length,r=t[n-1];for(;n-- >0;)t[n]=r,r=m[r];return m.length=0,t}(T)).length-1,$=z;$>=s;$--)p=n[$],-1===T[$-s]?c(e,p,r,l,o):j[N]===$-s?N--:g(e,p,o),null!=p.dom&&(o=n[$].dom);else for($=z;$>=s;$--)p=n[$],-1===T[$-s]&&c(e,p,r,l,o),null!=p.dom&&(o=n[$].dom)}}else{var P=t.lengthP&&k(e,t,s,t.length),n.length>P&&u(e,n,s,n.length,r,o,l)}}}function h(t,n,r,o,i,s){var u=n.tag;if(u===r.tag){if(r.state=n.state,r.events=n.events,function(e,t){do{var n;if(null!=e.attrs&&"function"==typeof e.attrs.onbeforeupdate)if(void 0!==(n=a.call(e.attrs.onbeforeupdate,e,t))&&!n)break;if("string"!=typeof e.tag&&"function"==typeof e.state.onbeforeupdate)if(void 0!==(n=a.call(e.state.onbeforeupdate,e,t))&&!n)break;return!1}while(0);return e.dom=t.dom,e.domSize=t.domSize,e.instance=t.instance,e.attrs=t.attrs,e.children=t.children,e.text=t.text,!0}(r,n))return;if("string"==typeof u)switch(null!=r.attrs&&D(r.attrs,r,o),u){case"#":!function(e,t){e.children.toString()!==t.children.toString()&&(e.dom.nodeValue=t.children);t.dom=e.dom}(n,r);break;case"<":!function(e,t,n,r,o){t.children!==n.children?(S(e,t),d(e,n,r,o)):(n.dom=t.dom,n.domSize=t.domSize,n.instance=t.instance)}(t,n,r,s,i);break;case"[":!function(e,t,n,r,o,l){p(e,t.children,n.children,r,o,l);var i=0,a=n.children;if(n.dom=null,null!=a){for(var s=0;s-1||null!=e.attrs&&e.attrs.is||"href"!==t&&"list"!==t&&"form"!==t&&"width"!==t&&"height"!==t)&&t in e.dom}var T,N=/[A-Z]/g;function $(e){return"-"+e.toLowerCase()}function L(e){return"-"===e[0]&&"-"===e[1]?e:"cssFloat"===e?"float":e.replace(N,$)}function I(e,t,n){if(t===n);else if(null==n)e.style.cssText="";else if("object"!=typeof n)e.style.cssText=n;else if(null==t||"object"!=typeof t)for(var r in e.style.cssText="",n){null!=(o=n[r])&&e.style.setProperty(L(r),String(o))}else{for(var r in n){var o;null!=(o=n[r])&&(o=String(o))!==String(t[r])&&e.style.setProperty(L(r),o)}for(var r in t)null!=t[r]&&null==n[r]&&e.style.removeProperty(L(r))}}function R(){this._=n}function P(e,t,r){if(null!=e.events){if(e.events._=n,e.events[t]===r)return;null==r||"function"!=typeof r&&"object"!=typeof r?(null!=e.events[t]&&e.dom.removeEventListener(t.slice(2),e.events,!1),e.events[t]=void 0):(null==e.events[t]&&e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}else null==r||"function"!=typeof r&&"object"!=typeof r||(e.events=new R,e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}function _(e,t,n){"function"==typeof e.oninit&&a.call(e.oninit,t),"function"==typeof e.oncreate&&n.push(a.bind(e.oncreate,t))}function D(e,t,n){"function"==typeof e.onupdate&&n.push(a.bind(e.onupdate,t))}return R.prototype=Object.create(null),R.prototype.handleEvent=function(e){var t,n=this["on"+e.type];"function"==typeof n?t=n.call(e.currentTarget,e):"function"==typeof n.handleEvent&&n.handleEvent(e),this._&&!1!==e.redraw&&(0,this._)(),!1===t&&(e.preventDefault(),e.stopPropagation())},function(t,r,o){if(!t)throw new TypeError("DOM element being rendered to does not exist.");if(null!=T&&t.contains(T))throw new TypeError("Node is currently being rendered to and thus is locked.");var l=n,i=T,a=[],u=s(),c=t.namespaceURI;T=t,n="function"==typeof o?o:void 0;try{null==t.vnodes&&(t.textContent=""),r=e.normalizeChildren(Array.isArray(r)?r:[r]),p(t,t.vnodes,r,a,null,"http://www.w3.org/1999/xhtml"===c?void 0:c),t.vnodes=r,null!=u&&s()!==u&&"function"==typeof u.focus&&u.focus();for(var f=0;f=0&&(o.splice(l,2),l<=i&&(i-=2),t(n,[])),null!=r&&(o.push(n,r),t(n,e(r),s))},redraw:s}}(a,"undefined"!=typeof requestAnimationFrame?requestAnimationFrame:null,"undefined"!=typeof console?console:null),u=function(e){if("[object Object]"!==Object.prototype.toString.call(e))return"";var t=[];for(var n in e)r(n,e[n]);return t.join("&");function r(e,n){if(Array.isArray(n))for(var o=0;o=0&&(v+=e.slice(n,o)),f>=0&&(v+=(n<0?"?":"&")+s.slice(f,p));var m=u(a);return m&&(v+=(n<0&&f<0?"?":"&")+m),r>=0&&(v+=e.slice(r)),d>=0&&(v+=(r<0?"":"&")+s.slice(d)),v},d=function(e,t){function r(e){return new Promise(e)}function o(e,t){for(var r in e.headers)if(n.call(e.headers,r)&&r.toLowerCase()===t)return!0;return!1}return(r.prototype=Promise.prototype,r.__proto__=Promise,{request:function(l,i){"string"!=typeof l?(i=l,l=l.url):null==i&&(i={});var a=function(t,r){return new Promise((function(l,i){t=f(t,r.params);var a,s=null!=r.method?r.method.toUpperCase():"GET",u=r.body,c=(null==r.serialize||r.serialize===JSON.serialize)&&!(u instanceof e.FormData||u instanceof e.URLSearchParams),d=r.responseType||("function"==typeof r.extract?"":"json"),p=new e.XMLHttpRequest,h=!1,v=!1,m=p,y=p.abort;for(var g in p.abort=function(){h=!0,y.call(this)},p.open(s,t,!1!==r.async,"string"==typeof r.user?r.user:void 0,"string"==typeof r.password?r.password:void 0),c&&null!=u&&!o(r,"content-type")&&p.setRequestHeader("Content-Type","application/json; charset=utf-8"),"function"==typeof r.deserialize||o(r,"accept")||p.setRequestHeader("Accept","application/json, text/*"),r.withCredentials&&(p.withCredentials=r.withCredentials),r.timeout&&(p.timeout=r.timeout),p.responseType=d,r.headers)n.call(r.headers,g)&&p.setRequestHeader(g,r.headers[g]);p.onreadystatechange=function(e){if(!h&&4===e.target.readyState)try{var n,o=e.target.status>=200&&e.target.status<300||304===e.target.status||/^file:\/\//i.test(t),a=e.target.response;if("json"===d){if(!e.target.responseType&&"function"!=typeof r.extract)try{a=JSON.parse(e.target.responseText)}catch(e){a=null}}else d&&"text"!==d||null==a&&(a=e.target.responseText);if("function"==typeof r.extract?(a=r.extract(e.target,r),o=!0):"function"==typeof r.deserialize&&(a=r.deserialize(a)),o){if("function"==typeof r.type)if(Array.isArray(a))for(var s=0;s-1&&s.pop();for(var c=0;c0&&(i.className=l.join(" ")),o[e]={tag:n,attrs:i}}function i(e,t){var r=t.attrs,o=n.call(r,"class"),l=o?r.class:r.className;if(t.tag=e.tag,t.attrs={},!function(e){for(var t in e)if(n.call(e,t))return!1;return!0}(e.attrs)){var i={};for(var a in r)n.call(r,a)&&(i[a]=r[a]);r=i}for(var a in e.attrs)n.call(e.attrs,a)&&"className"!==a&&!n.call(r,a)&&(r[a]=e.attrs[a]);for(var a in null==l&&null==e.attrs.className||(r.className=null!=l?null!=e.attrs.className?String(e.attrs.className)+" "+String(l):l:null!=e.attrs.className?e.attrs.className:null),o&&(r.class=null),r)if(n.call(r,a)&&"key"!==a){t.attrs=r;break}return t}function a(n){if(null==n||"string"!=typeof n&&"function"!=typeof n&&"function"!=typeof n.view)throw Error("The selector must be either a string or a component.");var r=t.apply(1,arguments);return"string"==typeof n&&(r.children=e.normalizeChildren(r.children),"["!==n)?i(o[n]||l(n),r):(r.tag=n,r)}a.trust=function(t){return null==t&&(t=""),e("<",void 0,void 0,t,void 0,void 0)},a.fragment=function(){var n=t.apply(0,arguments);return n.tag="[",n.children=e.normalizeChildren(n.children),n};var u=new WeakMap;var s={delayedRemoval:u,domFor:function*({dom:e,domSize0:t},{generation0:n}={}){if(null!=e)do{const{nextSibling:r}=e;u.get(e)===n&&(yield e,t--),e=r}while(t)}},f=s.delayedRemoval,c=s.domFor,d=function(t){var n,r,o=t&&t.document,l={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"};function i(e){return e.attrs&&e.attrs.xmlns||l[e.tag]}function a(e,t){if(e.state!==t)throw new Error("'vnode.state' must not be modified.")}function u(e){var t=e.state;try{return this.apply(t,arguments)}finally{a(e,t)}}function s(){try{return o.activeElement}catch(e){return null}}function d(e,t,n,r,o,l,i){for(var a=n;a'+t.children+"",i=i.firstChild):i.innerHTML=t.children,t.dom=i.firstChild,t.domSize=i.childNodes.length;for(var a,u=o.createDocumentFragment();a=i.firstChild;)u.appendChild(a);k(e,u,r)}function h(e,t,n,r,o,l){if(t!==n&&(null!=t||null!=n))if(null==t||0===t.length)d(e,n,0,n.length,r,o,l);else if(null==n||0===n.length)E(e,t,0,t.length);else{var i=null!=t[0]&&null!=t[0].key,a=null!=n[0]&&null!=n[0].key,u=0,s=0;if(!i)for(;s=s&&S>=u&&(m=t[k],v=n[S],m.key===v.key);)m!==v&&y(e,m,v,r,o,l),null!=v.dom&&(o=v.dom),k--,S--;for(;k>=s&&S>=u&&(f=t[s],c=n[u],f.key===c.key);)s++,u++,f!==c&&y(e,f,c,r,b(t,s,o),l);for(;k>=s&&S>=u&&u!==S&&f.key===v.key&&m.key===c.key;)x(e,m,h=b(t,s,o)),m!==c&&y(e,m,c,r,h,l),++u<=--S&&x(e,f,o),f!==v&&y(e,f,v,r,o,l),null!=v.dom&&(o=v.dom),s++,m=t[--k],v=n[S],f=t[s],c=n[u];for(;k>=s&&S>=u&&m.key===v.key;)m!==v&&y(e,m,v,r,o,l),null!=v.dom&&(o=v.dom),S--,m=t[--k],v=n[S];if(u>S)E(e,t,s,k+1);else if(s>k)d(e,n,u,S+1,r,o,l);else{var j,A,C=o,O=S-u+1,T=new Array(O),N=0,$=0,L=2147483647,R=0;for($=0;$=u;$--){null==j&&(j=g(t,s,k+1));var I=j[(v=n[$]).key];null!=I&&(L=I>>1)+(r>>>1)+(n&r&1);e[t[a]]0&&(w[o]=t[n-1]),t[n]=o)}}n=t.length,r=t[n-1];for(;n-- >0;)t[n]=r,r=w[r];return w.length=0,t}(T)).length-1,$=S;$>=u;$--)c=n[$],-1===T[$-u]?p(e,c,r,l,o):A[N]===$-u?N--:x(e,c,o),null!=c.dom&&(o=n[$].dom);else for($=S;$>=u;$--)c=n[$],-1===T[$-u]&&p(e,c,r,l,o),null!=c.dom&&(o=n[$].dom)}}else{var P=t.lengthP&&E(e,t,u,t.length),n.length>P&&d(e,n,u,n.length,r,o,l)}}}function y(t,n,r,o,l,a){var s=n.tag;if(s===r.tag){if(r.state=n.state,r.events=n.events,function(e,t){do{var n;if(null!=e.attrs&&"function"==typeof e.attrs.onbeforeupdate)if(void 0!==(n=u.call(e.attrs.onbeforeupdate,e,t))&&!n)break;if("string"!=typeof e.tag&&"function"==typeof e.state.onbeforeupdate)if(void 0!==(n=u.call(e.state.onbeforeupdate,e,t))&&!n)break;return!1}while(0);return e.dom=t.dom,e.domSize=t.domSize,e.instance=t.instance,e.attrs=t.attrs,e.children=t.children,e.text=t.text,!0}(r,n))return;if("string"==typeof s)switch(null!=r.attrs&&M(r.attrs,r,o),s){case"#":!function(e,t){e.children.toString()!==t.children.toString()&&(e.dom.nodeValue=t.children);t.dom=e.dom}(n,r);break;case"<":!function(e,t,n,r,o){t.children!==n.children?(j(e,t,void 0),v(e,n,r,o)):(n.dom=t.dom,n.domSize=t.domSize)}(t,n,r,a,l);break;case"[":!function(e,t,n,r,o,l){h(e,t.children,n.children,r,o,l);var i=0,a=n.children;if(n.dom=null,null!=a){for(var u=0;u-1||null!=e.attrs&&e.attrs.is||"href"!==t&&"list"!==t&&"form"!==t&&"width"!==t&&"height"!==t)&&t in e.dom}var $,L=/[A-Z]/g;function R(e){return"-"+e.toLowerCase()}function I(e){return"-"===e[0]&&"-"===e[1]?e:"cssFloat"===e?"float":e.replace(L,R)}function P(e,t,n){if(t===n);else if(null==n)e.style="";else if("object"!=typeof n)e.style=n;else if(null==t||"object"!=typeof t)for(var r in e.style.cssText="",n){null!=(o=n[r])&&e.style.setProperty(I(r),String(o))}else{for(var r in n){var o;null!=(o=n[r])&&(o=String(o))!==String(t[r])&&e.style.setProperty(I(r),o)}for(var r in t)null!=t[r]&&null==n[r]&&e.style.removeProperty(I(r))}}function _(){this._=n}function F(e,t,r){if(null!=e.events){if(e.events._=n,e.events[t]===r)return;null==r||"function"!=typeof r&&"object"!=typeof r?(null!=e.events[t]&&e.dom.removeEventListener(t.slice(2),e.events,!1),e.events[t]=void 0):(null==e.events[t]&&e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}else null==r||"function"!=typeof r&&"object"!=typeof r||(e.events=new _,e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}function D(e,t,n){"function"==typeof e.oninit&&u.call(e.oninit,t),"function"==typeof e.oncreate&&n.push(u.bind(e.oncreate,t))}function M(e,t,n){"function"==typeof e.onupdate&&n.push(u.bind(e.onupdate,t))}return _.prototype=Object.create(null),_.prototype.handleEvent=function(e){var t,n=this["on"+e.type];"function"==typeof n?t=n.call(e.currentTarget,e):"function"==typeof n.handleEvent&&n.handleEvent(e),this._&&!1!==e.redraw&&((0,this._)(),null!=t&&"function"==typeof t.then&&t.then(this._)),!1===t&&(e.preventDefault(),e.stopPropagation())},function(t,o,l){if(!t)throw new TypeError("DOM element being rendered to does not exist.");if(null!=$&&t.contains($))throw new TypeError("Node is currently being rendered to and thus is locked.");var i=n,a=$,u=[],f=s(),c=t.namespaceURI;$=t,n="function"==typeof l?l:void 0,r={};try{null==t.vnodes&&(t.textContent=""),o=e.normalizeChildren(Array.isArray(o)?o:[o]),h(t,t.vnodes,o,u,null,"http://www.w3.org/1999/xhtml"===c?void 0:c),t.vnodes=o,null!=f&&s()!==f&&"function"==typeof f.focus&&f.focus();for(var d=0;d=0&&(o.splice(l,2),l<=i&&(i-=2),t(n,[])),null!=r&&(o.push(n,r),t(n,e(r),u))},redraw:u}}(d,"undefined"!=typeof requestAnimationFrame?requestAnimationFrame:null,"undefined"!=typeof console?console:null),m=function(e){if("[object Object]"!==Object.prototype.toString.call(e))return"";var t=[];for(var n in e)r(n,e[n]);return t.join("&");function r(e,n){if(Array.isArray(n))for(var o=0;o=0&&(p+=e.slice(n,o)),s>=0&&(p+=(n<0?"?":"&")+u.slice(s,c));var h=m(a);return h&&(p+=(n<0&&s<0?"?":"&")+h),r>=0&&(p+=e.slice(r)),f>=0&&(p+=(r<0?"":"&")+u.slice(f)),p},y=function(e,t){function r(e){return new Promise(e)}function o(e,t){for(var r in e.headers)if(n.call(e.headers,r)&&r.toLowerCase()===t)return!0;return!1}return r.prototype=Promise.prototype,r.__proto__=Promise,{request:function(l,i){"string"!=typeof l?(i=l,l=l.url):null==i&&(i={});var a=function(t,r){return new Promise((function(l,i){t=h(t,r.params);var a,u=null!=r.method?r.method.toUpperCase():"GET",s=r.body,f=(null==r.serialize||r.serialize===JSON.serialize)&&!(s instanceof e.FormData||s instanceof e.URLSearchParams),c=r.responseType||("function"==typeof r.extract?"":"json"),d=new e.XMLHttpRequest,p=!1,m=!1,v=d,y=d.abort;for(var g in d.abort=function(){p=!0,y.call(this)},d.open(u,t,!1!==r.async,"string"==typeof r.user?r.user:void 0,"string"==typeof r.password?r.password:void 0),f&&null!=s&&!o(r,"content-type")&&d.setRequestHeader("Content-Type","application/json; charset=utf-8"),"function"==typeof r.deserialize||o(r,"accept")||d.setRequestHeader("Accept","application/json, text/*"),r.withCredentials&&(d.withCredentials=r.withCredentials),r.timeout&&(d.timeout=r.timeout),d.responseType=c,r.headers)n.call(r.headers,g)&&d.setRequestHeader(g,r.headers[g]);d.onreadystatechange=function(e){if(!p&&4===e.target.readyState)try{var n,o=e.target.status>=200&&e.target.status<300||304===e.target.status||/^file:\/\//i.test(t),a=e.target.response;if("json"===c){if(!e.target.responseType&&"function"!=typeof r.extract)try{a=JSON.parse(e.target.responseText)}catch(e){a=null}}else c&&"text"!==c||null==a&&(a=e.target.responseText);if("function"==typeof r.extract?(a=r.extract(e.target,r),o=!0):"function"==typeof r.deserialize&&(a=r.deserialize(a)),o){if("function"==typeof r.type)if(Array.isArray(a))for(var u=0;u-1&&u.pop();for(var f=0;f-1&&(t=n[a][1](t,r()))})),t}),r);return a(t),a},t["fantasy-land/of"]=t;var n=!1;function t(n){var r,i=[],u=[];function c(e){return arguments.length&&e!==t.SKIP&&(n=e,a(c)&&(c._changing(),c._state="active",i.slice().forEach((function(t,e){a(t)&&t(this[e](n))}),u.slice()))),n}return c.constructor=t,c._state=arguments.length&&n!==t.SKIP?"active":"pending",c._parents=[],c._changing=function(){a(c)&&(c._state="changing"),i.forEach((function(n){n._changing()}))},c._map=function(e,r){var a=r?t():t(e(n));return a._parents.push(c),i.push(a),u.push(e),a},c.map=function(n){return c._map(n,"active"!==c._state)},c.toJSON=function(){return null!=n&&"function"==typeof n.toJSON?n.toJSON():n},c["fantasy-land/map"]=c.map,c["fantasy-land/ap"]=function(n){return e((function(n,t){return n()(t())}),[n,c])},c._unregisterChild=function(n){var t=i.indexOf(n);-1!==t&&(i.splice(t,1),u.splice(t,1))},Object.defineProperty(c,"end",{get:function(){return r||((r=t()).map((function(n){return!0===n&&(c._parents.forEach((function(n){n._unregisterChild(c)})),c._state="ended",c._parents.length=i.length=u.length=0),n})),r)}}),c}function e(n,e){var r=e.every((function(n){if(n.constructor!==t)throw new Error("Ensure that each item passed to stream.combine/stream.merge/lift is a stream.");return"active"===n._state})),a=r?t(n.apply(null,e.concat([e]))):t(),i=[],u=e.map((function(t){return t._map((function(u){return i.push(t),(r||e.every((function(n){return"pending"!==n._state})))&&(r=!0,a(n.apply(null,e.concat([i]))),i=[]),u}),!0)})),c=a.end.map((function(n){!0===n&&(u.forEach((function(n){n.end(!0)})),c.end(!0))}));return a}function r(n){return e((function(){return n.map((function(n){return n()}))}),n)}function a(n){return"pending"===n._state||"active"===n._state||"changing"===n._state}Object.defineProperty(t,"HALT",{get:function(){return n||console.log("HALT is deprecated and has been renamed to SKIP"),n=!0,t.SKIP}}),"undefined"!=typeof module?module.exports=t:"function"!=typeof window.m||"stream"in window.m?window.m={stream:t}:window.m.stream=t}(); \ No newline at end of file +!function(){"use strict";t.SKIP={},t.lift=function(){var n=arguments[0],t=Array.prototype.slice.call(arguments,1);return r(t).map((function(t){return n.apply(void 0,t)}))},t.scan=function(n,e,r){var a=r.map((function(r){var a=n(e,r);return a!==t.SKIP&&(e=a),a}));return a(e),a},t.merge=r,t.combine=e,t.scanMerge=function(n,t){var r=n.map((function(n){return n[0]})),a=e((function(){var e=arguments[arguments.length-1];return r.forEach((function(r,a){e.indexOf(r)>-1&&(t=n[a][1](t,r()))})),t}),r);return a(t),a},t["fantasy-land/of"]=t;var n=!1;function t(n){var r,i=[],u=[];function c(e){return arguments.length&&e!==t.SKIP&&(n=e,a(c)&&(c._changing(),c._state="active",i.slice().forEach((function(t,e){a(t)&&t(this[e](n))}),u.slice()))),n}function o(){return(r=t()).map((function(n){return!0===n&&(c._parents.forEach((function(n){n._unregisterChild(c)})),c._state="ended",c._parents.length=i.length=u.length=0),n})),r}return c.constructor=t,c._state=arguments.length&&n!==t.SKIP?"active":"pending",c._parents=[],c._changing=function(){a(c)&&(c._state="changing"),i.forEach((function(n){n._changing()}))},c._map=function(e,r){var a=r?t():t(e(n));return a._parents.push(c),i.push(a),u.push(e),a},c.map=function(n){return c._map(n,"active"!==c._state)},c.toJSON=function(){return null!=n&&"function"==typeof n.toJSON?n.toJSON():n},c["fantasy-land/map"]=c.map,c["fantasy-land/ap"]=function(n){return e((function(n,t){return n()(t())}),[n,c])},c._unregisterChild=function(n){var t=i.indexOf(n);-1!==t&&(i.splice(t,1),u.splice(t,1))},Object.defineProperty(c,"end",{get:function(){return r||o()}}),c}function e(n,e){var r=e.every((function(n){if(n.constructor!==t)throw new Error("Ensure that each item passed to stream.combine/stream.merge/lift is a stream.");return"active"===n._state})),a=r?t(n.apply(null,e.concat([e]))):t(),i=[],u=e.map((function(t){return t._map((function(u){return i.push(t),(r||e.every((function(n){return"pending"!==n._state})))&&(r=!0,a(n.apply(null,e.concat([i]))),i=[]),u}),!0)})),c=a.end.map((function(n){!0===n&&(u.forEach((function(n){n.end(!0)})),c.end(!0))}));return a}function r(n){return e((function(){return n.map((function(n){return n()}))}),n)}function a(n){return"pending"===n._state||"active"===n._state||"changing"===n._state}Object.defineProperty(t,"HALT",{get:function(){return n||console.log("HALT is deprecated and has been renamed to SKIP"),n=!0,t.SKIP}}),"undefined"!=typeof module?module.exports=t:"function"!=typeof window.m||"stream"in window.m?window.m={stream:t}:window.m.stream=t}(); \ No newline at end of file From 9ea34be8f4652a8a15192e375b784a8c8f1036ce Mon Sep 17 00:00:00 2001 From: EtiamNullam <10875340+EtiamNullam@users.noreply.github.com> Date: Sun, 10 Sep 2023 23:29:41 +0300 Subject: [PATCH 5/6] fix: Don't use redundant `(0, this._)`, redraw on rejection --- api/tests/test-mountRedraw.js | 161 +++++++++++----------------------- mithril.js | 2 +- mithril.min.js | 2 +- render/render.js | 2 +- 4 files changed, 54 insertions(+), 113 deletions(-) diff --git a/api/tests/test-mountRedraw.js b/api/tests/test-mountRedraw.js index a5109c676..2a5f4a431 100644 --- a/api/tests/test-mountRedraw.js +++ b/api/tests/test-mountRedraw.js @@ -531,12 +531,12 @@ o.spec("mount/redraw", function() { o(e.redraw).equals(false) }) - o("async event handlers should not cause additional redraw when immediately settled", function() { + o("async event handlers should not cause additional redraw when immediately resolved", function() { var onupdate = o.spy() var oninit = o.spy() var e = $document.createEvent("MouseEvents") e.initEvent("click", true, true) - var getImmediatelyInvokedThenable = function() { + var getImmediatelyResolvedThenable = function() { return { then: function(callback) { callback() @@ -549,7 +549,7 @@ o.spec("mount/redraw", function() { return h("div", { oninit: oninit, onupdate: onupdate, - onclick: getImmediatelyInvokedThenable, + onclick: getImmediatelyResolvedThenable, }) } })) @@ -563,56 +563,6 @@ o.spec("mount/redraw", function() { o(onupdate.callCount).equals(1) }) - o("async event handlers redraw after settle", function() { - var onupdate = o.spy() - var oninit = o.spy() - var e = $document.createEvent("MouseEvents") - e.initEvent("click", true, true) - var RemotePromiseLike = function() { - var callbacks = [] - - return { - finally: function(callback) { - callbacks.push(callback) - }, - then: true, - fire: function() { - callbacks.forEach(function(callback) { - callback() - }) - }, - } - } - var remotePromiseLike = RemotePromiseLike() - var getRemotePromiseLike = function() { - return remotePromiseLike - } - - m.mount(root, createComponent({ - view: function() { - return h("button", { - onclick: getRemotePromiseLike, - oninit: oninit, - onupdate: onupdate, - }) - }, - })) - - root.firstChild.dispatchEvent(e) - throttleMock.fire() - - o(onupdate.callCount).equals(1) - o(oninit.callCount).equals(1) - - remotePromiseLike.finally(function() { - throttleMock.fire() - o(oninit.callCount).equals(1) - o(onupdate.callCount).equals(2) - }) - - remotePromiseLike.fire() - }) - o("async event handlers redraw after resolve", function() { var onupdate = o.spy() var oninit = o.spy() @@ -653,100 +603,91 @@ o.spec("mount/redraw", function() { o(onupdate.callCount).equals(1) o(oninit.callCount).equals(1) - remoteThenable.then(function() { - throttleMock.fire() - o(oninit.callCount).equals(1) - o(onupdate.callCount).equals(2) - }) - remoteThenable.fire() - }) - - o("async event handlers should call `finally` and not `then` on result", function() { - var promiseLike = { - finally: o.spy(), - then: o.spy(function() { - throw new Error("Then should not be called if finally is available") - }), - } - var e = $document.createEvent("MouseEvents") - e.initEvent("click", true, true) - - m.mount(root, createComponent({ - view: function() { - return h("button", { - onclick: function() { - return promiseLike - }, - }) - } - })) - - o(promiseLike.finally.callCount).equals(0) - - root.firstChild.dispatchEvent(e) throttleMock.fire() - o(promiseLike.finally.callCount).equals(1) + o(oninit.callCount).equals(1) + o(onupdate.callCount).equals(2) }) - o("async event handlers should fallback and call `then` on result if `finally` is not callable", function() { - var thenable = { - finally: true, - then: o.spy(), - } + o("async event handlers can skip redraw", function() { + var onupdate = o.spy(function() { + throw new Error("This shouldn't have been called") + }) + var oninit = o.spy() + var resolvePromise var e = $document.createEvent("MouseEvents") e.initEvent("click", true, true) + var asyncEventHandlerNoRedraw = function(ev) { + ev.redraw = false + return new Promise(function(resolve) { + resolvePromise = resolve + }) + } m.mount(root, createComponent({ view: function() { return h("button", { - onclick: function() { - return thenable - }, + onclick: asyncEventHandlerNoRedraw, + oninit: oninit, + onupdate: onupdate, }) } })) - o(thenable.then.callCount).equals(0) - root.firstChild.dispatchEvent(e) + resolvePromise() throttleMock.fire() - o(thenable.then.callCount).equals(1) + o(oninit.callCount).equals(1) + o(onupdate.callCount).equals(0) }) - o("async event handlers can skip redraw", function() { - var onupdate = o.spy(function() { - throw new Error("This shouldn't have been called") - }) + o("redraws after async event handlers throws error", function() { + var onupdate = o.spy() var oninit = o.spy() - var resolvePromise var e = $document.createEvent("MouseEvents") e.initEvent("click", true, true) - var asyncEventHandlerNoRedraw = function(ev) { - ev.redraw = false - return new Promise(function(resolve) { - resolvePromise = resolve - }) + var RemoteFailedThenable = function() { + var errorCallbacks = [] + + return { + then: function(unused, errorCallback) { + errorCallbacks.push(errorCallback) + }, + fire: function() { + errorCallbacks.forEach(function(callback) { + callback() + }) + }, + } + } + var remoteFailedThenable = RemoteFailedThenable() + var getRemoteFailedThenable = function() { + return remoteFailedThenable } m.mount(root, createComponent({ view: function() { return h("button", { - onclick: asyncEventHandlerNoRedraw, + onclick: getRemoteFailedThenable, oninit: oninit, onupdate: onupdate, }) - } + }, })) root.firstChild.dispatchEvent(e) - resolvePromise() throttleMock.fire() + o(onupdate.callCount).equals(1) o(oninit.callCount).equals(1) - o(onupdate.callCount).equals(0) + + remoteFailedThenable.fire() + throttleMock.fire() + + o(oninit.callCount).equals(1) + o(onupdate.callCount).equals(2) }) o("redraws when the render function is run", function() { diff --git a/mithril.js b/mithril.js index 57ea10990..8383f026a 100644 --- a/mithril.js +++ b/mithril.js @@ -997,7 +997,7 @@ var _11 = function($window) { else if (typeof handler.handleEvent === "function") handler.handleEvent(ev) if (this._ && ev.redraw !== false) { (0, this._)() - if (result != null && typeof result.then === "function") result.then((0, this._)) + if (result != null && typeof result.then === "function") result.then(this._, this._) } if (result === false) { ev.preventDefault() diff --git a/mithril.min.js b/mithril.min.js index 810fc366a..b8c7be4d6 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1 +1 @@ -!function(){"use strict";function e(e,t,n,r,o,l){return{tag:e,key:t,attrs:n,children:r,text:o,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0}}e.normalize=function(t){return Array.isArray(t)?e("[",void 0,void 0,e.normalizeChildren(t),void 0,void 0):null==t||"boolean"==typeof t?null:"object"==typeof t?t:e("#",void 0,void 0,String(t),void 0,void 0)},e.normalizeChildren=function(t){var n=[];if(t.length){for(var r=null!=t[0]&&null!=t[0].key,o=1;o0&&(i.className=l.join(" ")),o[e]={tag:n,attrs:i}}function i(e,t){var r=t.attrs,o=n.call(r,"class"),l=o?r.class:r.className;if(t.tag=e.tag,t.attrs={},!function(e){for(var t in e)if(n.call(e,t))return!1;return!0}(e.attrs)){var i={};for(var a in r)n.call(r,a)&&(i[a]=r[a]);r=i}for(var a in e.attrs)n.call(e.attrs,a)&&"className"!==a&&!n.call(r,a)&&(r[a]=e.attrs[a]);for(var a in null==l&&null==e.attrs.className||(r.className=null!=l?null!=e.attrs.className?String(e.attrs.className)+" "+String(l):l:null!=e.attrs.className?e.attrs.className:null),o&&(r.class=null),r)if(n.call(r,a)&&"key"!==a){t.attrs=r;break}return t}function a(n){if(null==n||"string"!=typeof n&&"function"!=typeof n&&"function"!=typeof n.view)throw Error("The selector must be either a string or a component.");var r=t.apply(1,arguments);return"string"==typeof n&&(r.children=e.normalizeChildren(r.children),"["!==n)?i(o[n]||l(n),r):(r.tag=n,r)}a.trust=function(t){return null==t&&(t=""),e("<",void 0,void 0,t,void 0,void 0)},a.fragment=function(){var n=t.apply(0,arguments);return n.tag="[",n.children=e.normalizeChildren(n.children),n};var u=new WeakMap;var s={delayedRemoval:u,domFor:function*({dom:e,domSize0:t},{generation0:n}={}){if(null!=e)do{const{nextSibling:r}=e;u.get(e)===n&&(yield e,t--),e=r}while(t)}},f=s.delayedRemoval,c=s.domFor,d=function(t){var n,r,o=t&&t.document,l={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"};function i(e){return e.attrs&&e.attrs.xmlns||l[e.tag]}function a(e,t){if(e.state!==t)throw new Error("'vnode.state' must not be modified.")}function u(e){var t=e.state;try{return this.apply(t,arguments)}finally{a(e,t)}}function s(){try{return o.activeElement}catch(e){return null}}function d(e,t,n,r,o,l,i){for(var a=n;a'+t.children+"",i=i.firstChild):i.innerHTML=t.children,t.dom=i.firstChild,t.domSize=i.childNodes.length;for(var a,u=o.createDocumentFragment();a=i.firstChild;)u.appendChild(a);k(e,u,r)}function h(e,t,n,r,o,l){if(t!==n&&(null!=t||null!=n))if(null==t||0===t.length)d(e,n,0,n.length,r,o,l);else if(null==n||0===n.length)E(e,t,0,t.length);else{var i=null!=t[0]&&null!=t[0].key,a=null!=n[0]&&null!=n[0].key,u=0,s=0;if(!i)for(;s=s&&S>=u&&(m=t[k],v=n[S],m.key===v.key);)m!==v&&y(e,m,v,r,o,l),null!=v.dom&&(o=v.dom),k--,S--;for(;k>=s&&S>=u&&(f=t[s],c=n[u],f.key===c.key);)s++,u++,f!==c&&y(e,f,c,r,b(t,s,o),l);for(;k>=s&&S>=u&&u!==S&&f.key===v.key&&m.key===c.key;)x(e,m,h=b(t,s,o)),m!==c&&y(e,m,c,r,h,l),++u<=--S&&x(e,f,o),f!==v&&y(e,f,v,r,o,l),null!=v.dom&&(o=v.dom),s++,m=t[--k],v=n[S],f=t[s],c=n[u];for(;k>=s&&S>=u&&m.key===v.key;)m!==v&&y(e,m,v,r,o,l),null!=v.dom&&(o=v.dom),S--,m=t[--k],v=n[S];if(u>S)E(e,t,s,k+1);else if(s>k)d(e,n,u,S+1,r,o,l);else{var j,A,C=o,O=S-u+1,T=new Array(O),N=0,$=0,L=2147483647,R=0;for($=0;$=u;$--){null==j&&(j=g(t,s,k+1));var I=j[(v=n[$]).key];null!=I&&(L=I>>1)+(r>>>1)+(n&r&1);e[t[a]]0&&(w[o]=t[n-1]),t[n]=o)}}n=t.length,r=t[n-1];for(;n-- >0;)t[n]=r,r=w[r];return w.length=0,t}(T)).length-1,$=S;$>=u;$--)c=n[$],-1===T[$-u]?p(e,c,r,l,o):A[N]===$-u?N--:x(e,c,o),null!=c.dom&&(o=n[$].dom);else for($=S;$>=u;$--)c=n[$],-1===T[$-u]&&p(e,c,r,l,o),null!=c.dom&&(o=n[$].dom)}}else{var P=t.lengthP&&E(e,t,u,t.length),n.length>P&&d(e,n,u,n.length,r,o,l)}}}function y(t,n,r,o,l,a){var s=n.tag;if(s===r.tag){if(r.state=n.state,r.events=n.events,function(e,t){do{var n;if(null!=e.attrs&&"function"==typeof e.attrs.onbeforeupdate)if(void 0!==(n=u.call(e.attrs.onbeforeupdate,e,t))&&!n)break;if("string"!=typeof e.tag&&"function"==typeof e.state.onbeforeupdate)if(void 0!==(n=u.call(e.state.onbeforeupdate,e,t))&&!n)break;return!1}while(0);return e.dom=t.dom,e.domSize=t.domSize,e.instance=t.instance,e.attrs=t.attrs,e.children=t.children,e.text=t.text,!0}(r,n))return;if("string"==typeof s)switch(null!=r.attrs&&M(r.attrs,r,o),s){case"#":!function(e,t){e.children.toString()!==t.children.toString()&&(e.dom.nodeValue=t.children);t.dom=e.dom}(n,r);break;case"<":!function(e,t,n,r,o){t.children!==n.children?(j(e,t,void 0),v(e,n,r,o)):(n.dom=t.dom,n.domSize=t.domSize)}(t,n,r,a,l);break;case"[":!function(e,t,n,r,o,l){h(e,t.children,n.children,r,o,l);var i=0,a=n.children;if(n.dom=null,null!=a){for(var u=0;u-1||null!=e.attrs&&e.attrs.is||"href"!==t&&"list"!==t&&"form"!==t&&"width"!==t&&"height"!==t)&&t in e.dom}var $,L=/[A-Z]/g;function R(e){return"-"+e.toLowerCase()}function I(e){return"-"===e[0]&&"-"===e[1]?e:"cssFloat"===e?"float":e.replace(L,R)}function P(e,t,n){if(t===n);else if(null==n)e.style="";else if("object"!=typeof n)e.style=n;else if(null==t||"object"!=typeof t)for(var r in e.style.cssText="",n){null!=(o=n[r])&&e.style.setProperty(I(r),String(o))}else{for(var r in n){var o;null!=(o=n[r])&&(o=String(o))!==String(t[r])&&e.style.setProperty(I(r),o)}for(var r in t)null!=t[r]&&null==n[r]&&e.style.removeProperty(I(r))}}function _(){this._=n}function F(e,t,r){if(null!=e.events){if(e.events._=n,e.events[t]===r)return;null==r||"function"!=typeof r&&"object"!=typeof r?(null!=e.events[t]&&e.dom.removeEventListener(t.slice(2),e.events,!1),e.events[t]=void 0):(null==e.events[t]&&e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}else null==r||"function"!=typeof r&&"object"!=typeof r||(e.events=new _,e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}function D(e,t,n){"function"==typeof e.oninit&&u.call(e.oninit,t),"function"==typeof e.oncreate&&n.push(u.bind(e.oncreate,t))}function M(e,t,n){"function"==typeof e.onupdate&&n.push(u.bind(e.onupdate,t))}return _.prototype=Object.create(null),_.prototype.handleEvent=function(e){var t,n=this["on"+e.type];"function"==typeof n?t=n.call(e.currentTarget,e):"function"==typeof n.handleEvent&&n.handleEvent(e),this._&&!1!==e.redraw&&((0,this._)(),null!=t&&"function"==typeof t.then&&t.then(this._)),!1===t&&(e.preventDefault(),e.stopPropagation())},function(t,o,l){if(!t)throw new TypeError("DOM element being rendered to does not exist.");if(null!=$&&t.contains($))throw new TypeError("Node is currently being rendered to and thus is locked.");var i=n,a=$,u=[],f=s(),c=t.namespaceURI;$=t,n="function"==typeof l?l:void 0,r={};try{null==t.vnodes&&(t.textContent=""),o=e.normalizeChildren(Array.isArray(o)?o:[o]),h(t,t.vnodes,o,u,null,"http://www.w3.org/1999/xhtml"===c?void 0:c),t.vnodes=o,null!=f&&s()!==f&&"function"==typeof f.focus&&f.focus();for(var d=0;d=0&&(o.splice(l,2),l<=i&&(i-=2),t(n,[])),null!=r&&(o.push(n,r),t(n,e(r),u))},redraw:u}}(d,"undefined"!=typeof requestAnimationFrame?requestAnimationFrame:null,"undefined"!=typeof console?console:null),m=function(e){if("[object Object]"!==Object.prototype.toString.call(e))return"";var t=[];for(var n in e)r(n,e[n]);return t.join("&");function r(e,n){if(Array.isArray(n))for(var o=0;o=0&&(p+=e.slice(n,o)),s>=0&&(p+=(n<0?"?":"&")+u.slice(s,c));var h=m(a);return h&&(p+=(n<0&&s<0?"?":"&")+h),r>=0&&(p+=e.slice(r)),f>=0&&(p+=(r<0?"":"&")+u.slice(f)),p},y=function(e,t){function r(e){return new Promise(e)}function o(e,t){for(var r in e.headers)if(n.call(e.headers,r)&&r.toLowerCase()===t)return!0;return!1}return r.prototype=Promise.prototype,r.__proto__=Promise,{request:function(l,i){"string"!=typeof l?(i=l,l=l.url):null==i&&(i={});var a=function(t,r){return new Promise((function(l,i){t=h(t,r.params);var a,u=null!=r.method?r.method.toUpperCase():"GET",s=r.body,f=(null==r.serialize||r.serialize===JSON.serialize)&&!(s instanceof e.FormData||s instanceof e.URLSearchParams),c=r.responseType||("function"==typeof r.extract?"":"json"),d=new e.XMLHttpRequest,p=!1,m=!1,v=d,y=d.abort;for(var g in d.abort=function(){p=!0,y.call(this)},d.open(u,t,!1!==r.async,"string"==typeof r.user?r.user:void 0,"string"==typeof r.password?r.password:void 0),f&&null!=s&&!o(r,"content-type")&&d.setRequestHeader("Content-Type","application/json; charset=utf-8"),"function"==typeof r.deserialize||o(r,"accept")||d.setRequestHeader("Accept","application/json, text/*"),r.withCredentials&&(d.withCredentials=r.withCredentials),r.timeout&&(d.timeout=r.timeout),d.responseType=c,r.headers)n.call(r.headers,g)&&d.setRequestHeader(g,r.headers[g]);d.onreadystatechange=function(e){if(!p&&4===e.target.readyState)try{var n,o=e.target.status>=200&&e.target.status<300||304===e.target.status||/^file:\/\//i.test(t),a=e.target.response;if("json"===c){if(!e.target.responseType&&"function"!=typeof r.extract)try{a=JSON.parse(e.target.responseText)}catch(e){a=null}}else c&&"text"!==c||null==a&&(a=e.target.responseText);if("function"==typeof r.extract?(a=r.extract(e.target,r),o=!0):"function"==typeof r.deserialize&&(a=r.deserialize(a)),o){if("function"==typeof r.type)if(Array.isArray(a))for(var u=0;u-1&&u.pop();for(var f=0;f0&&(i.className=l.join(" ")),o[e]={tag:n,attrs:i}}function i(e,t){var r=t.attrs,o=n.call(r,"class"),l=o?r.class:r.className;if(t.tag=e.tag,t.attrs={},!function(e){for(var t in e)if(n.call(e,t))return!1;return!0}(e.attrs)){var i={};for(var a in r)n.call(r,a)&&(i[a]=r[a]);r=i}for(var a in e.attrs)n.call(e.attrs,a)&&"className"!==a&&!n.call(r,a)&&(r[a]=e.attrs[a]);for(var a in null==l&&null==e.attrs.className||(r.className=null!=l?null!=e.attrs.className?String(e.attrs.className)+" "+String(l):l:null!=e.attrs.className?e.attrs.className:null),o&&(r.class=null),r)if(n.call(r,a)&&"key"!==a){t.attrs=r;break}return t}function a(n){if(null==n||"string"!=typeof n&&"function"!=typeof n&&"function"!=typeof n.view)throw Error("The selector must be either a string or a component.");var r=t.apply(1,arguments);return"string"==typeof n&&(r.children=e.normalizeChildren(r.children),"["!==n)?i(o[n]||l(n),r):(r.tag=n,r)}a.trust=function(t){return null==t&&(t=""),e("<",void 0,void 0,t,void 0,void 0)},a.fragment=function(){var n=t.apply(0,arguments);return n.tag="[",n.children=e.normalizeChildren(n.children),n};var u=new WeakMap;var s={delayedRemoval:u,domFor:function*({dom:e,domSize0:t},{generation0:n}={}){if(null!=e)do{const{nextSibling:r}=e;u.get(e)===n&&(yield e,t--),e=r}while(t)}},f=s.delayedRemoval,c=s.domFor,d=function(t){var n,r,o=t&&t.document,l={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"};function i(e){return e.attrs&&e.attrs.xmlns||l[e.tag]}function a(e,t){if(e.state!==t)throw new Error("'vnode.state' must not be modified.")}function u(e){var t=e.state;try{return this.apply(t,arguments)}finally{a(e,t)}}function s(){try{return o.activeElement}catch(e){return null}}function d(e,t,n,r,o,l,i){for(var a=n;a'+t.children+"",i=i.firstChild):i.innerHTML=t.children,t.dom=i.firstChild,t.domSize=i.childNodes.length;for(var a,u=o.createDocumentFragment();a=i.firstChild;)u.appendChild(a);k(e,u,r)}function h(e,t,n,r,o,l){if(t!==n&&(null!=t||null!=n))if(null==t||0===t.length)d(e,n,0,n.length,r,o,l);else if(null==n||0===n.length)E(e,t,0,t.length);else{var i=null!=t[0]&&null!=t[0].key,a=null!=n[0]&&null!=n[0].key,u=0,s=0;if(!i)for(;s=s&&S>=u&&(m=t[k],v=n[S],m.key===v.key);)m!==v&&y(e,m,v,r,o,l),null!=v.dom&&(o=v.dom),k--,S--;for(;k>=s&&S>=u&&(f=t[s],c=n[u],f.key===c.key);)s++,u++,f!==c&&y(e,f,c,r,b(t,s,o),l);for(;k>=s&&S>=u&&u!==S&&f.key===v.key&&m.key===c.key;)x(e,m,h=b(t,s,o)),m!==c&&y(e,m,c,r,h,l),++u<=--S&&x(e,f,o),f!==v&&y(e,f,v,r,o,l),null!=v.dom&&(o=v.dom),s++,m=t[--k],v=n[S],f=t[s],c=n[u];for(;k>=s&&S>=u&&m.key===v.key;)m!==v&&y(e,m,v,r,o,l),null!=v.dom&&(o=v.dom),S--,m=t[--k],v=n[S];if(u>S)E(e,t,s,k+1);else if(s>k)d(e,n,u,S+1,r,o,l);else{var j,A,C=o,O=S-u+1,T=new Array(O),N=0,$=0,L=2147483647,R=0;for($=0;$=u;$--){null==j&&(j=g(t,s,k+1));var I=j[(v=n[$]).key];null!=I&&(L=I>>1)+(r>>>1)+(n&r&1);e[t[a]]0&&(w[o]=t[n-1]),t[n]=o)}}n=t.length,r=t[n-1];for(;n-- >0;)t[n]=r,r=w[r];return w.length=0,t}(T)).length-1,$=S;$>=u;$--)c=n[$],-1===T[$-u]?p(e,c,r,l,o):A[N]===$-u?N--:x(e,c,o),null!=c.dom&&(o=n[$].dom);else for($=S;$>=u;$--)c=n[$],-1===T[$-u]&&p(e,c,r,l,o),null!=c.dom&&(o=n[$].dom)}}else{var P=t.lengthP&&E(e,t,u,t.length),n.length>P&&d(e,n,u,n.length,r,o,l)}}}function y(t,n,r,o,l,a){var s=n.tag;if(s===r.tag){if(r.state=n.state,r.events=n.events,function(e,t){do{var n;if(null!=e.attrs&&"function"==typeof e.attrs.onbeforeupdate)if(void 0!==(n=u.call(e.attrs.onbeforeupdate,e,t))&&!n)break;if("string"!=typeof e.tag&&"function"==typeof e.state.onbeforeupdate)if(void 0!==(n=u.call(e.state.onbeforeupdate,e,t))&&!n)break;return!1}while(0);return e.dom=t.dom,e.domSize=t.domSize,e.instance=t.instance,e.attrs=t.attrs,e.children=t.children,e.text=t.text,!0}(r,n))return;if("string"==typeof s)switch(null!=r.attrs&&M(r.attrs,r,o),s){case"#":!function(e,t){e.children.toString()!==t.children.toString()&&(e.dom.nodeValue=t.children);t.dom=e.dom}(n,r);break;case"<":!function(e,t,n,r,o){t.children!==n.children?(j(e,t,void 0),v(e,n,r,o)):(n.dom=t.dom,n.domSize=t.domSize)}(t,n,r,a,l);break;case"[":!function(e,t,n,r,o,l){h(e,t.children,n.children,r,o,l);var i=0,a=n.children;if(n.dom=null,null!=a){for(var u=0;u-1||null!=e.attrs&&e.attrs.is||"href"!==t&&"list"!==t&&"form"!==t&&"width"!==t&&"height"!==t)&&t in e.dom}var $,L=/[A-Z]/g;function R(e){return"-"+e.toLowerCase()}function I(e){return"-"===e[0]&&"-"===e[1]?e:"cssFloat"===e?"float":e.replace(L,R)}function P(e,t,n){if(t===n);else if(null==n)e.style="";else if("object"!=typeof n)e.style=n;else if(null==t||"object"!=typeof t)for(var r in e.style.cssText="",n){null!=(o=n[r])&&e.style.setProperty(I(r),String(o))}else{for(var r in n){var o;null!=(o=n[r])&&(o=String(o))!==String(t[r])&&e.style.setProperty(I(r),o)}for(var r in t)null!=t[r]&&null==n[r]&&e.style.removeProperty(I(r))}}function _(){this._=n}function F(e,t,r){if(null!=e.events){if(e.events._=n,e.events[t]===r)return;null==r||"function"!=typeof r&&"object"!=typeof r?(null!=e.events[t]&&e.dom.removeEventListener(t.slice(2),e.events,!1),e.events[t]=void 0):(null==e.events[t]&&e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}else null==r||"function"!=typeof r&&"object"!=typeof r||(e.events=new _,e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}function D(e,t,n){"function"==typeof e.oninit&&u.call(e.oninit,t),"function"==typeof e.oncreate&&n.push(u.bind(e.oncreate,t))}function M(e,t,n){"function"==typeof e.onupdate&&n.push(u.bind(e.onupdate,t))}return _.prototype=Object.create(null),_.prototype.handleEvent=function(e){var t,n=this["on"+e.type];"function"==typeof n?t=n.call(e.currentTarget,e):"function"==typeof n.handleEvent&&n.handleEvent(e),this._&&!1!==e.redraw&&((0,this._)(),null!=t&&"function"==typeof t.then&&t.then(this._,this._)),!1===t&&(e.preventDefault(),e.stopPropagation())},function(t,o,l){if(!t)throw new TypeError("DOM element being rendered to does not exist.");if(null!=$&&t.contains($))throw new TypeError("Node is currently being rendered to and thus is locked.");var i=n,a=$,u=[],f=s(),c=t.namespaceURI;$=t,n="function"==typeof l?l:void 0,r={};try{null==t.vnodes&&(t.textContent=""),o=e.normalizeChildren(Array.isArray(o)?o:[o]),h(t,t.vnodes,o,u,null,"http://www.w3.org/1999/xhtml"===c?void 0:c),t.vnodes=o,null!=f&&s()!==f&&"function"==typeof f.focus&&f.focus();for(var d=0;d=0&&(o.splice(l,2),l<=i&&(i-=2),t(n,[])),null!=r&&(o.push(n,r),t(n,e(r),u))},redraw:u}}(d,"undefined"!=typeof requestAnimationFrame?requestAnimationFrame:null,"undefined"!=typeof console?console:null),m=function(e){if("[object Object]"!==Object.prototype.toString.call(e))return"";var t=[];for(var n in e)r(n,e[n]);return t.join("&");function r(e,n){if(Array.isArray(n))for(var o=0;o=0&&(p+=e.slice(n,o)),s>=0&&(p+=(n<0?"?":"&")+u.slice(s,c));var h=m(a);return h&&(p+=(n<0&&s<0?"?":"&")+h),r>=0&&(p+=e.slice(r)),f>=0&&(p+=(r<0?"":"&")+u.slice(f)),p},y=function(e,t){function r(e){return new Promise(e)}function o(e,t){for(var r in e.headers)if(n.call(e.headers,r)&&r.toLowerCase()===t)return!0;return!1}return r.prototype=Promise.prototype,r.__proto__=Promise,{request:function(l,i){"string"!=typeof l?(i=l,l=l.url):null==i&&(i={});var a=function(t,r){return new Promise((function(l,i){t=h(t,r.params);var a,u=null!=r.method?r.method.toUpperCase():"GET",s=r.body,f=(null==r.serialize||r.serialize===JSON.serialize)&&!(s instanceof e.FormData||s instanceof e.URLSearchParams),c=r.responseType||("function"==typeof r.extract?"":"json"),d=new e.XMLHttpRequest,p=!1,m=!1,v=d,y=d.abort;for(var g in d.abort=function(){p=!0,y.call(this)},d.open(u,t,!1!==r.async,"string"==typeof r.user?r.user:void 0,"string"==typeof r.password?r.password:void 0),f&&null!=s&&!o(r,"content-type")&&d.setRequestHeader("Content-Type","application/json; charset=utf-8"),"function"==typeof r.deserialize||o(r,"accept")||d.setRequestHeader("Accept","application/json, text/*"),r.withCredentials&&(d.withCredentials=r.withCredentials),r.timeout&&(d.timeout=r.timeout),d.responseType=c,r.headers)n.call(r.headers,g)&&d.setRequestHeader(g,r.headers[g]);d.onreadystatechange=function(e){if(!p&&4===e.target.readyState)try{var n,o=e.target.status>=200&&e.target.status<300||304===e.target.status||/^file:\/\//i.test(t),a=e.target.response;if("json"===c){if(!e.target.responseType&&"function"!=typeof r.extract)try{a=JSON.parse(e.target.responseText)}catch(e){a=null}}else c&&"text"!==c||null==a&&(a=e.target.responseText);if("function"==typeof r.extract?(a=r.extract(e.target,r),o=!0):"function"==typeof r.deserialize&&(a=r.deserialize(a)),o){if("function"==typeof r.type)if(Array.isArray(a))for(var u=0;u-1&&u.pop();for(var f=0;f Date: Sun, 17 Sep 2023 23:50:36 +0300 Subject: [PATCH 6/6] fix: Propagate unhandled errors thrown in event handlers --- README.md | 2 +- api/tests/test-mountRedraw.js | 33 ++++++++++++++++++++------------- mithril.js | 7 ++++++- mithril.min.js | 2 +- render/render.js | 7 ++++++- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 5dae62b10..2213499c1 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ ## What is Mithril.js? -A modern client-side JavaScript framework for building Single Page Applications. It's small (9.15 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side JavaScript framework for building Single Page Applications. It's small (9.16 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril.js is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/api/tests/test-mountRedraw.js b/api/tests/test-mountRedraw.js index 2a5f4a431..1fd7cbd91 100644 --- a/api/tests/test-mountRedraw.js +++ b/api/tests/test-mountRedraw.js @@ -643,51 +643,58 @@ o.spec("mount/redraw", function() { o(onupdate.callCount).equals(0) }) - o("redraws after async event handlers throws error", function() { + o("redraws after async event handlers throw error", function() { var onupdate = o.spy() var oninit = o.spy() var e = $document.createEvent("MouseEvents") e.initEvent("click", true, true) - var RemoteFailedThenable = function() { - var errorCallbacks = [] + var RemotelyRejectedThenable = function() { + var rejectionSubscribers = [] return { - then: function(unused, errorCallback) { - errorCallbacks.push(errorCallback) + then: function(onFulfilled, onRejection) { + rejectionSubscribers.push(onRejection) }, fire: function() { - errorCallbacks.forEach(function(callback) { - callback() + rejectionSubscribers.forEach(function(reject) { + reject("example error message") }) }, } } - var remoteFailedThenable = RemoteFailedThenable() - var getRemoteFailedThenable = function() { - return remoteFailedThenable + var remotelyRejectedThenable = RemotelyRejectedThenable() + var getRemotelyRejectedThenable = function() { + return remotelyRejectedThenable } m.mount(root, createComponent({ view: function() { return h("button", { - onclick: getRemoteFailedThenable, + onclick: getRemotelyRejectedThenable, oninit: oninit, onupdate: onupdate, }) }, })) - root.firstChild.dispatchEvent(e) throttleMock.fire() o(onupdate.callCount).equals(1) o(oninit.callCount).equals(1) - remoteFailedThenable.fire() + let errorsThrownCount = 0 + + try { + remotelyRejectedThenable.fire() + } catch (e) { + errorsThrownCount++ + } + throttleMock.fire() o(oninit.callCount).equals(1) o(onupdate.callCount).equals(2) + o(errorsThrownCount).equals(1) }) o("redraws when the render function is run", function() { diff --git a/mithril.js b/mithril.js index 8383f026a..257e51b4d 100644 --- a/mithril.js +++ b/mithril.js @@ -997,7 +997,12 @@ var _11 = function($window) { else if (typeof handler.handleEvent === "function") handler.handleEvent(ev) if (this._ && ev.redraw !== false) { (0, this._)() - if (result != null && typeof result.then === "function") result.then(this._, this._) + if (result != null && typeof result.then === "function") { + result.then(this._, function(error) { + (0, this._)() + throw error + }.bind(this)) + } } if (result === false) { ev.preventDefault() diff --git a/mithril.min.js b/mithril.min.js index b8c7be4d6..516b250fc 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1 +1 @@ -!function(){"use strict";function e(e,t,n,r,o,l){return{tag:e,key:t,attrs:n,children:r,text:o,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0}}e.normalize=function(t){return Array.isArray(t)?e("[",void 0,void 0,e.normalizeChildren(t),void 0,void 0):null==t||"boolean"==typeof t?null:"object"==typeof t?t:e("#",void 0,void 0,String(t),void 0,void 0)},e.normalizeChildren=function(t){var n=[];if(t.length){for(var r=null!=t[0]&&null!=t[0].key,o=1;o0&&(i.className=l.join(" ")),o[e]={tag:n,attrs:i}}function i(e,t){var r=t.attrs,o=n.call(r,"class"),l=o?r.class:r.className;if(t.tag=e.tag,t.attrs={},!function(e){for(var t in e)if(n.call(e,t))return!1;return!0}(e.attrs)){var i={};for(var a in r)n.call(r,a)&&(i[a]=r[a]);r=i}for(var a in e.attrs)n.call(e.attrs,a)&&"className"!==a&&!n.call(r,a)&&(r[a]=e.attrs[a]);for(var a in null==l&&null==e.attrs.className||(r.className=null!=l?null!=e.attrs.className?String(e.attrs.className)+" "+String(l):l:null!=e.attrs.className?e.attrs.className:null),o&&(r.class=null),r)if(n.call(r,a)&&"key"!==a){t.attrs=r;break}return t}function a(n){if(null==n||"string"!=typeof n&&"function"!=typeof n&&"function"!=typeof n.view)throw Error("The selector must be either a string or a component.");var r=t.apply(1,arguments);return"string"==typeof n&&(r.children=e.normalizeChildren(r.children),"["!==n)?i(o[n]||l(n),r):(r.tag=n,r)}a.trust=function(t){return null==t&&(t=""),e("<",void 0,void 0,t,void 0,void 0)},a.fragment=function(){var n=t.apply(0,arguments);return n.tag="[",n.children=e.normalizeChildren(n.children),n};var u=new WeakMap;var s={delayedRemoval:u,domFor:function*({dom:e,domSize0:t},{generation0:n}={}){if(null!=e)do{const{nextSibling:r}=e;u.get(e)===n&&(yield e,t--),e=r}while(t)}},f=s.delayedRemoval,c=s.domFor,d=function(t){var n,r,o=t&&t.document,l={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"};function i(e){return e.attrs&&e.attrs.xmlns||l[e.tag]}function a(e,t){if(e.state!==t)throw new Error("'vnode.state' must not be modified.")}function u(e){var t=e.state;try{return this.apply(t,arguments)}finally{a(e,t)}}function s(){try{return o.activeElement}catch(e){return null}}function d(e,t,n,r,o,l,i){for(var a=n;a'+t.children+"",i=i.firstChild):i.innerHTML=t.children,t.dom=i.firstChild,t.domSize=i.childNodes.length;for(var a,u=o.createDocumentFragment();a=i.firstChild;)u.appendChild(a);k(e,u,r)}function h(e,t,n,r,o,l){if(t!==n&&(null!=t||null!=n))if(null==t||0===t.length)d(e,n,0,n.length,r,o,l);else if(null==n||0===n.length)E(e,t,0,t.length);else{var i=null!=t[0]&&null!=t[0].key,a=null!=n[0]&&null!=n[0].key,u=0,s=0;if(!i)for(;s=s&&S>=u&&(m=t[k],v=n[S],m.key===v.key);)m!==v&&y(e,m,v,r,o,l),null!=v.dom&&(o=v.dom),k--,S--;for(;k>=s&&S>=u&&(f=t[s],c=n[u],f.key===c.key);)s++,u++,f!==c&&y(e,f,c,r,b(t,s,o),l);for(;k>=s&&S>=u&&u!==S&&f.key===v.key&&m.key===c.key;)x(e,m,h=b(t,s,o)),m!==c&&y(e,m,c,r,h,l),++u<=--S&&x(e,f,o),f!==v&&y(e,f,v,r,o,l),null!=v.dom&&(o=v.dom),s++,m=t[--k],v=n[S],f=t[s],c=n[u];for(;k>=s&&S>=u&&m.key===v.key;)m!==v&&y(e,m,v,r,o,l),null!=v.dom&&(o=v.dom),S--,m=t[--k],v=n[S];if(u>S)E(e,t,s,k+1);else if(s>k)d(e,n,u,S+1,r,o,l);else{var j,A,C=o,O=S-u+1,T=new Array(O),N=0,$=0,L=2147483647,R=0;for($=0;$=u;$--){null==j&&(j=g(t,s,k+1));var I=j[(v=n[$]).key];null!=I&&(L=I>>1)+(r>>>1)+(n&r&1);e[t[a]]0&&(w[o]=t[n-1]),t[n]=o)}}n=t.length,r=t[n-1];for(;n-- >0;)t[n]=r,r=w[r];return w.length=0,t}(T)).length-1,$=S;$>=u;$--)c=n[$],-1===T[$-u]?p(e,c,r,l,o):A[N]===$-u?N--:x(e,c,o),null!=c.dom&&(o=n[$].dom);else for($=S;$>=u;$--)c=n[$],-1===T[$-u]&&p(e,c,r,l,o),null!=c.dom&&(o=n[$].dom)}}else{var P=t.lengthP&&E(e,t,u,t.length),n.length>P&&d(e,n,u,n.length,r,o,l)}}}function y(t,n,r,o,l,a){var s=n.tag;if(s===r.tag){if(r.state=n.state,r.events=n.events,function(e,t){do{var n;if(null!=e.attrs&&"function"==typeof e.attrs.onbeforeupdate)if(void 0!==(n=u.call(e.attrs.onbeforeupdate,e,t))&&!n)break;if("string"!=typeof e.tag&&"function"==typeof e.state.onbeforeupdate)if(void 0!==(n=u.call(e.state.onbeforeupdate,e,t))&&!n)break;return!1}while(0);return e.dom=t.dom,e.domSize=t.domSize,e.instance=t.instance,e.attrs=t.attrs,e.children=t.children,e.text=t.text,!0}(r,n))return;if("string"==typeof s)switch(null!=r.attrs&&M(r.attrs,r,o),s){case"#":!function(e,t){e.children.toString()!==t.children.toString()&&(e.dom.nodeValue=t.children);t.dom=e.dom}(n,r);break;case"<":!function(e,t,n,r,o){t.children!==n.children?(j(e,t,void 0),v(e,n,r,o)):(n.dom=t.dom,n.domSize=t.domSize)}(t,n,r,a,l);break;case"[":!function(e,t,n,r,o,l){h(e,t.children,n.children,r,o,l);var i=0,a=n.children;if(n.dom=null,null!=a){for(var u=0;u-1||null!=e.attrs&&e.attrs.is||"href"!==t&&"list"!==t&&"form"!==t&&"width"!==t&&"height"!==t)&&t in e.dom}var $,L=/[A-Z]/g;function R(e){return"-"+e.toLowerCase()}function I(e){return"-"===e[0]&&"-"===e[1]?e:"cssFloat"===e?"float":e.replace(L,R)}function P(e,t,n){if(t===n);else if(null==n)e.style="";else if("object"!=typeof n)e.style=n;else if(null==t||"object"!=typeof t)for(var r in e.style.cssText="",n){null!=(o=n[r])&&e.style.setProperty(I(r),String(o))}else{for(var r in n){var o;null!=(o=n[r])&&(o=String(o))!==String(t[r])&&e.style.setProperty(I(r),o)}for(var r in t)null!=t[r]&&null==n[r]&&e.style.removeProperty(I(r))}}function _(){this._=n}function F(e,t,r){if(null!=e.events){if(e.events._=n,e.events[t]===r)return;null==r||"function"!=typeof r&&"object"!=typeof r?(null!=e.events[t]&&e.dom.removeEventListener(t.slice(2),e.events,!1),e.events[t]=void 0):(null==e.events[t]&&e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}else null==r||"function"!=typeof r&&"object"!=typeof r||(e.events=new _,e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}function D(e,t,n){"function"==typeof e.oninit&&u.call(e.oninit,t),"function"==typeof e.oncreate&&n.push(u.bind(e.oncreate,t))}function M(e,t,n){"function"==typeof e.onupdate&&n.push(u.bind(e.onupdate,t))}return _.prototype=Object.create(null),_.prototype.handleEvent=function(e){var t,n=this["on"+e.type];"function"==typeof n?t=n.call(e.currentTarget,e):"function"==typeof n.handleEvent&&n.handleEvent(e),this._&&!1!==e.redraw&&((0,this._)(),null!=t&&"function"==typeof t.then&&t.then(this._,this._)),!1===t&&(e.preventDefault(),e.stopPropagation())},function(t,o,l){if(!t)throw new TypeError("DOM element being rendered to does not exist.");if(null!=$&&t.contains($))throw new TypeError("Node is currently being rendered to and thus is locked.");var i=n,a=$,u=[],f=s(),c=t.namespaceURI;$=t,n="function"==typeof l?l:void 0,r={};try{null==t.vnodes&&(t.textContent=""),o=e.normalizeChildren(Array.isArray(o)?o:[o]),h(t,t.vnodes,o,u,null,"http://www.w3.org/1999/xhtml"===c?void 0:c),t.vnodes=o,null!=f&&s()!==f&&"function"==typeof f.focus&&f.focus();for(var d=0;d=0&&(o.splice(l,2),l<=i&&(i-=2),t(n,[])),null!=r&&(o.push(n,r),t(n,e(r),u))},redraw:u}}(d,"undefined"!=typeof requestAnimationFrame?requestAnimationFrame:null,"undefined"!=typeof console?console:null),m=function(e){if("[object Object]"!==Object.prototype.toString.call(e))return"";var t=[];for(var n in e)r(n,e[n]);return t.join("&");function r(e,n){if(Array.isArray(n))for(var o=0;o=0&&(p+=e.slice(n,o)),s>=0&&(p+=(n<0?"?":"&")+u.slice(s,c));var h=m(a);return h&&(p+=(n<0&&s<0?"?":"&")+h),r>=0&&(p+=e.slice(r)),f>=0&&(p+=(r<0?"":"&")+u.slice(f)),p},y=function(e,t){function r(e){return new Promise(e)}function o(e,t){for(var r in e.headers)if(n.call(e.headers,r)&&r.toLowerCase()===t)return!0;return!1}return r.prototype=Promise.prototype,r.__proto__=Promise,{request:function(l,i){"string"!=typeof l?(i=l,l=l.url):null==i&&(i={});var a=function(t,r){return new Promise((function(l,i){t=h(t,r.params);var a,u=null!=r.method?r.method.toUpperCase():"GET",s=r.body,f=(null==r.serialize||r.serialize===JSON.serialize)&&!(s instanceof e.FormData||s instanceof e.URLSearchParams),c=r.responseType||("function"==typeof r.extract?"":"json"),d=new e.XMLHttpRequest,p=!1,m=!1,v=d,y=d.abort;for(var g in d.abort=function(){p=!0,y.call(this)},d.open(u,t,!1!==r.async,"string"==typeof r.user?r.user:void 0,"string"==typeof r.password?r.password:void 0),f&&null!=s&&!o(r,"content-type")&&d.setRequestHeader("Content-Type","application/json; charset=utf-8"),"function"==typeof r.deserialize||o(r,"accept")||d.setRequestHeader("Accept","application/json, text/*"),r.withCredentials&&(d.withCredentials=r.withCredentials),r.timeout&&(d.timeout=r.timeout),d.responseType=c,r.headers)n.call(r.headers,g)&&d.setRequestHeader(g,r.headers[g]);d.onreadystatechange=function(e){if(!p&&4===e.target.readyState)try{var n,o=e.target.status>=200&&e.target.status<300||304===e.target.status||/^file:\/\//i.test(t),a=e.target.response;if("json"===c){if(!e.target.responseType&&"function"!=typeof r.extract)try{a=JSON.parse(e.target.responseText)}catch(e){a=null}}else c&&"text"!==c||null==a&&(a=e.target.responseText);if("function"==typeof r.extract?(a=r.extract(e.target,r),o=!0):"function"==typeof r.deserialize&&(a=r.deserialize(a)),o){if("function"==typeof r.type)if(Array.isArray(a))for(var u=0;u-1&&u.pop();for(var f=0;f0&&(i.className=l.join(" ")),o[e]={tag:n,attrs:i}}function i(e,t){var r=t.attrs,o=n.call(r,"class"),l=o?r.class:r.className;if(t.tag=e.tag,t.attrs={},!function(e){for(var t in e)if(n.call(e,t))return!1;return!0}(e.attrs)){var i={};for(var a in r)n.call(r,a)&&(i[a]=r[a]);r=i}for(var a in e.attrs)n.call(e.attrs,a)&&"className"!==a&&!n.call(r,a)&&(r[a]=e.attrs[a]);for(var a in null==l&&null==e.attrs.className||(r.className=null!=l?null!=e.attrs.className?String(e.attrs.className)+" "+String(l):l:null!=e.attrs.className?e.attrs.className:null),o&&(r.class=null),r)if(n.call(r,a)&&"key"!==a){t.attrs=r;break}return t}function a(n){if(null==n||"string"!=typeof n&&"function"!=typeof n&&"function"!=typeof n.view)throw Error("The selector must be either a string or a component.");var r=t.apply(1,arguments);return"string"==typeof n&&(r.children=e.normalizeChildren(r.children),"["!==n)?i(o[n]||l(n),r):(r.tag=n,r)}a.trust=function(t){return null==t&&(t=""),e("<",void 0,void 0,t,void 0,void 0)},a.fragment=function(){var n=t.apply(0,arguments);return n.tag="[",n.children=e.normalizeChildren(n.children),n};var u=new WeakMap;var s={delayedRemoval:u,domFor:function*({dom:e,domSize0:t},{generation0:n}={}){if(null!=e)do{const{nextSibling:r}=e;u.get(e)===n&&(yield e,t--),e=r}while(t)}},f=s.delayedRemoval,c=s.domFor,d=function(t){var n,r,o=t&&t.document,l={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"};function i(e){return e.attrs&&e.attrs.xmlns||l[e.tag]}function a(e,t){if(e.state!==t)throw new Error("'vnode.state' must not be modified.")}function u(e){var t=e.state;try{return this.apply(t,arguments)}finally{a(e,t)}}function s(){try{return o.activeElement}catch(e){return null}}function d(e,t,n,r,o,l,i){for(var a=n;a'+t.children+"",i=i.firstChild):i.innerHTML=t.children,t.dom=i.firstChild,t.domSize=i.childNodes.length;for(var a,u=o.createDocumentFragment();a=i.firstChild;)u.appendChild(a);k(e,u,r)}function h(e,t,n,r,o,l){if(t!==n&&(null!=t||null!=n))if(null==t||0===t.length)d(e,n,0,n.length,r,o,l);else if(null==n||0===n.length)E(e,t,0,t.length);else{var i=null!=t[0]&&null!=t[0].key,a=null!=n[0]&&null!=n[0].key,u=0,s=0;if(!i)for(;s=s&&S>=u&&(m=t[k],v=n[S],m.key===v.key);)m!==v&&y(e,m,v,r,o,l),null!=v.dom&&(o=v.dom),k--,S--;for(;k>=s&&S>=u&&(f=t[s],c=n[u],f.key===c.key);)s++,u++,f!==c&&y(e,f,c,r,b(t,s,o),l);for(;k>=s&&S>=u&&u!==S&&f.key===v.key&&m.key===c.key;)x(e,m,h=b(t,s,o)),m!==c&&y(e,m,c,r,h,l),++u<=--S&&x(e,f,o),f!==v&&y(e,f,v,r,o,l),null!=v.dom&&(o=v.dom),s++,m=t[--k],v=n[S],f=t[s],c=n[u];for(;k>=s&&S>=u&&m.key===v.key;)m!==v&&y(e,m,v,r,o,l),null!=v.dom&&(o=v.dom),S--,m=t[--k],v=n[S];if(u>S)E(e,t,s,k+1);else if(s>k)d(e,n,u,S+1,r,o,l);else{var j,A,C=o,O=S-u+1,T=new Array(O),N=0,$=0,L=2147483647,R=0;for($=0;$=u;$--){null==j&&(j=g(t,s,k+1));var I=j[(v=n[$]).key];null!=I&&(L=I>>1)+(r>>>1)+(n&r&1);e[t[a]]0&&(w[o]=t[n-1]),t[n]=o)}}n=t.length,r=t[n-1];for(;n-- >0;)t[n]=r,r=w[r];return w.length=0,t}(T)).length-1,$=S;$>=u;$--)c=n[$],-1===T[$-u]?p(e,c,r,l,o):A[N]===$-u?N--:x(e,c,o),null!=c.dom&&(o=n[$].dom);else for($=S;$>=u;$--)c=n[$],-1===T[$-u]&&p(e,c,r,l,o),null!=c.dom&&(o=n[$].dom)}}else{var P=t.lengthP&&E(e,t,u,t.length),n.length>P&&d(e,n,u,n.length,r,o,l)}}}function y(t,n,r,o,l,a){var s=n.tag;if(s===r.tag){if(r.state=n.state,r.events=n.events,function(e,t){do{var n;if(null!=e.attrs&&"function"==typeof e.attrs.onbeforeupdate)if(void 0!==(n=u.call(e.attrs.onbeforeupdate,e,t))&&!n)break;if("string"!=typeof e.tag&&"function"==typeof e.state.onbeforeupdate)if(void 0!==(n=u.call(e.state.onbeforeupdate,e,t))&&!n)break;return!1}while(0);return e.dom=t.dom,e.domSize=t.domSize,e.instance=t.instance,e.attrs=t.attrs,e.children=t.children,e.text=t.text,!0}(r,n))return;if("string"==typeof s)switch(null!=r.attrs&&M(r.attrs,r,o),s){case"#":!function(e,t){e.children.toString()!==t.children.toString()&&(e.dom.nodeValue=t.children);t.dom=e.dom}(n,r);break;case"<":!function(e,t,n,r,o){t.children!==n.children?(j(e,t,void 0),v(e,n,r,o)):(n.dom=t.dom,n.domSize=t.domSize)}(t,n,r,a,l);break;case"[":!function(e,t,n,r,o,l){h(e,t.children,n.children,r,o,l);var i=0,a=n.children;if(n.dom=null,null!=a){for(var u=0;u-1||null!=e.attrs&&e.attrs.is||"href"!==t&&"list"!==t&&"form"!==t&&"width"!==t&&"height"!==t)&&t in e.dom}var $,L=/[A-Z]/g;function R(e){return"-"+e.toLowerCase()}function I(e){return"-"===e[0]&&"-"===e[1]?e:"cssFloat"===e?"float":e.replace(L,R)}function P(e,t,n){if(t===n);else if(null==n)e.style="";else if("object"!=typeof n)e.style=n;else if(null==t||"object"!=typeof t)for(var r in e.style.cssText="",n){null!=(o=n[r])&&e.style.setProperty(I(r),String(o))}else{for(var r in n){var o;null!=(o=n[r])&&(o=String(o))!==String(t[r])&&e.style.setProperty(I(r),o)}for(var r in t)null!=t[r]&&null==n[r]&&e.style.removeProperty(I(r))}}function _(){this._=n}function F(e,t,r){if(null!=e.events){if(e.events._=n,e.events[t]===r)return;null==r||"function"!=typeof r&&"object"!=typeof r?(null!=e.events[t]&&e.dom.removeEventListener(t.slice(2),e.events,!1),e.events[t]=void 0):(null==e.events[t]&&e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}else null==r||"function"!=typeof r&&"object"!=typeof r||(e.events=new _,e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}function D(e,t,n){"function"==typeof e.oninit&&u.call(e.oninit,t),"function"==typeof e.oncreate&&n.push(u.bind(e.oncreate,t))}function M(e,t,n){"function"==typeof e.onupdate&&n.push(u.bind(e.onupdate,t))}return _.prototype=Object.create(null),_.prototype.handleEvent=function(e){var t,n=this["on"+e.type];"function"==typeof n?t=n.call(e.currentTarget,e):"function"==typeof n.handleEvent&&n.handleEvent(e),this._&&!1!==e.redraw&&((0,this._)(),null!=t&&"function"==typeof t.then&&t.then(this._,function(e){throw(0,this._)(),e}.bind(this))),!1===t&&(e.preventDefault(),e.stopPropagation())},function(t,o,l){if(!t)throw new TypeError("DOM element being rendered to does not exist.");if(null!=$&&t.contains($))throw new TypeError("Node is currently being rendered to and thus is locked.");var i=n,a=$,u=[],f=s(),c=t.namespaceURI;$=t,n="function"==typeof l?l:void 0,r={};try{null==t.vnodes&&(t.textContent=""),o=e.normalizeChildren(Array.isArray(o)?o:[o]),h(t,t.vnodes,o,u,null,"http://www.w3.org/1999/xhtml"===c?void 0:c),t.vnodes=o,null!=f&&s()!==f&&"function"==typeof f.focus&&f.focus();for(var d=0;d=0&&(o.splice(l,2),l<=i&&(i-=2),t(n,[])),null!=r&&(o.push(n,r),t(n,e(r),u))},redraw:u}}(d,"undefined"!=typeof requestAnimationFrame?requestAnimationFrame:null,"undefined"!=typeof console?console:null),m=function(e){if("[object Object]"!==Object.prototype.toString.call(e))return"";var t=[];for(var n in e)r(n,e[n]);return t.join("&");function r(e,n){if(Array.isArray(n))for(var o=0;o=0&&(p+=e.slice(n,o)),s>=0&&(p+=(n<0?"?":"&")+u.slice(s,c));var h=m(a);return h&&(p+=(n<0&&s<0?"?":"&")+h),r>=0&&(p+=e.slice(r)),f>=0&&(p+=(r<0?"":"&")+u.slice(f)),p},y=function(e,t){function r(e){return new Promise(e)}function o(e,t){for(var r in e.headers)if(n.call(e.headers,r)&&r.toLowerCase()===t)return!0;return!1}return r.prototype=Promise.prototype,r.__proto__=Promise,{request:function(l,i){"string"!=typeof l?(i=l,l=l.url):null==i&&(i={});var a=function(t,r){return new Promise((function(l,i){t=h(t,r.params);var a,u=null!=r.method?r.method.toUpperCase():"GET",s=r.body,f=(null==r.serialize||r.serialize===JSON.serialize)&&!(s instanceof e.FormData||s instanceof e.URLSearchParams),c=r.responseType||("function"==typeof r.extract?"":"json"),d=new e.XMLHttpRequest,p=!1,m=!1,v=d,y=d.abort;for(var g in d.abort=function(){p=!0,y.call(this)},d.open(u,t,!1!==r.async,"string"==typeof r.user?r.user:void 0,"string"==typeof r.password?r.password:void 0),f&&null!=s&&!o(r,"content-type")&&d.setRequestHeader("Content-Type","application/json; charset=utf-8"),"function"==typeof r.deserialize||o(r,"accept")||d.setRequestHeader("Accept","application/json, text/*"),r.withCredentials&&(d.withCredentials=r.withCredentials),r.timeout&&(d.timeout=r.timeout),d.responseType=c,r.headers)n.call(r.headers,g)&&d.setRequestHeader(g,r.headers[g]);d.onreadystatechange=function(e){if(!p&&4===e.target.readyState)try{var n,o=e.target.status>=200&&e.target.status<300||304===e.target.status||/^file:\/\//i.test(t),a=e.target.response;if("json"===c){if(!e.target.responseType&&"function"!=typeof r.extract)try{a=JSON.parse(e.target.responseText)}catch(e){a=null}}else c&&"text"!==c||null==a&&(a=e.target.responseText);if("function"==typeof r.extract?(a=r.extract(e.target,r),o=!0):"function"==typeof r.deserialize&&(a=r.deserialize(a)),o){if("function"==typeof r.type)if(Array.isArray(a))for(var u=0;u-1&&u.pop();for(var f=0;f