From 23930871a19d0c780b1a36783450fdf80d966c2e Mon Sep 17 00:00:00 2001 From: Derrick Gilland Date: Fri, 24 Jul 2015 16:50:23 -0400 Subject: [PATCH 1/9] Add `finally` to promise-like object. Closes #680 --- mithril.js | 8 ++++++++ tests/mithril-tests.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/mithril.js b/mithril.js index d8a8f8b0..080c6052 100644 --- a/mithril.js +++ b/mithril.js @@ -1055,6 +1055,14 @@ var m = (function app(window, undefined) { return propify(promise.then(resolve, reject), initialValue); }; prop["catch"] = prop.then.bind(null, null); + prop["finally"] = function(callback){ + var _callback = function(value){return m.deferred().resolve(callback(value)).promise;}; + return prop.then(function(value) { + return propify(_callback(value).then(function() {return value;}), initialValue); + }, function(reason) { + return propify(_callback(reason).then(function() {throw new Error(reason);}), initialValue); + }); + }; return prop; } //Promiz.mithril.js | Zolmeister | MIT diff --git a/tests/mithril-tests.js b/tests/mithril-tests.js index d0fd3dad..36c50785 100644 --- a/tests/mithril-tests.js +++ b/tests/mithril-tests.js @@ -3915,6 +3915,35 @@ function testMithril(mock) { mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().message === "error occurred" && error().message === "error occurred" }) + test(function() { + // Data returned by then() functions propagate to finally(). + var data = m.prop(""); + var prop = m.request({method: "GET", url: "test"}).then(function() {return "foo"})["finally"](data) + mock.XMLHttpRequest.$instances.pop().onreadystatechange() + return prop() === "foo" && data() === "foo" + }) + test(function() { + // Data returned by finally() functions do *not* propagate to next promise. + var data = m.prop(""); + var prop = m.request({method: "GET", url: "test"}).then(function() {return "foo"})["finally"](function() {return "bar"}).then(data) + mock.XMLHttpRequest.$instances.pop().onreadystatechange() + return prop() === "foo" && data() === "foo" + }) + test(function() { + // Errors thrown in finally() can be caught by next promise. + var error = m.prop("no error") + var prop = m.request({method: "GET", url: "test"}).then(function() {return "foo"})["finally"](function() {throw new Error("error occurred")})["catch"](error) + mock.XMLHttpRequest.$instances.pop().onreadystatechange() + return prop().message === "error occurred" && error().message === "error occurred" + }) + test(function() { + // Promise finally() method occurrs after catch(). + var error = m.prop("no error") + var lastly = function() { error("lastly") }; + var prop = m.request({method: "GET", url: "test", deserialize: function() {throw new Error("error occurred")}})["catch"](error)["finally"](lastly) + mock.XMLHttpRequest.$instances.pop().onreadystatechange() + return prop().message === "error occurred" && error() === "lastly" + }) test(function() { var error = m.prop("no error"), exception var prop = m.request({method: "GET", url: "test", deserialize: function() {throw new TypeError("error occurred")}}).then(null, error) From 5111c75746fcd8800d6112e9c05d5777ced956aa Mon Sep 17 00:00:00 2001 From: impinball Date: Mon, 27 Jul 2015 18:48:08 -0400 Subject: [PATCH 2/9] Bump npm version Fixes #740. It really needs it... :( Also, I fixed some weird indentation going on in that area of the package.json file (mixed spaces/tabs). --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 819228f7..ffd7ac2e 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "mithril", "description": "Mithril.js beta build - use this to help us test the releases before they are released", - "version": "0.1.34-beta.0", - "repository": { - "type": "git", - "url": "git@github.com:lhorie/mithril.js.git" - }, + "version": "0.2.1", + "repository": { + "type": "git", + "url": "git@github.com:lhorie/mithril.js.git" + }, "scripts": { "test": "grunt test" }, From c46567ab81fa6ff5b8750b5c6a18667fb1dc10d8 Mon Sep 17 00:00:00 2001 From: Greg King Date: Wed, 29 Jul 2015 09:40:32 -0400 Subject: [PATCH 3/9] #745 Remove references to DOM nodes when unmounting When a null component is passed into m.mount(), remove references to the root DOM element from: - roots - cellCache - nodeCache And remove the associated entries from: - controllers - components --- mithril.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/mithril.js b/mithril.js index 080c6052..c3f9e657 100644 --- a/mithril.js +++ b/mithril.js @@ -764,6 +764,8 @@ var m = (function app(window, undefined) { controllers[index].onunload(event); } + var isNullComponent = component === null; + if (!isPrevented) { m.redraw.strategy("all"); m.startComputation(); @@ -777,14 +779,24 @@ var m = (function app(window, undefined) { components[index] = component; } endFirstComputation(); + if (isNullComponent) { + removeRootElement(root, index); + } return controllers[index]; } - if (!component) { - roots.splice(index, 1); - controllers.splice(index, 1); - components.splice(index, 1); + if (isNullComponent) { + removeRootElement(root, index); } }; + + function removeRootElement(root, index) { + roots.splice(index, 1); + controllers.splice(index, 1); + components.splice(index, 1); + reset(root); + nodeCache.splice(getCellCacheKey(root), 1); + } + var redrawing = false, forcing = false; m.redraw = function(force) { if (redrawing) return; From 72c039c4dc1496bf667ab046fe1c64292b8dfc69 Mon Sep 17 00:00:00 2001 From: pelonpelon Date: Sat, 1 Aug 2015 14:51:18 -0500 Subject: [PATCH 4/9] allow m.withAttr callback to determine it's own `this` [non-breaking change] Background: In ES6 we now have `Object.setPrototypeOf` which makes prototype delegation an alternative to *sugary*, fake class coding patterns. This can be accomplished in ES5, but ES6 is much more elegant. Here is a basic example. `new` is never used and `this` is very easy to follow. Working example with changes to mithril.js on lines 854, 858, 859 *only*. http://jsbin.com/nopugo/1/edit?js,console,output ```javascript 'use strict' const m = require('mithril') const DataModel = { data: [1,2,3], getData(){ console.log('getting data from server') return this.data }, postData(val){ console.log('sending data to server') this.data.push(val) } } const ViewModel = { filterEvenData: function() { return this.getData().filter((val) => (val % 2 === 0) && (+val !== 0)) }, addNewData: function(val){ console.log('adding new data', val) this.postData(val) } } var Model = Object.setPrototypeOf(ViewModel, DataModel) const App = { controller(){}, view(ctrl){ return m('div', [ m('pre', [ 'EVEN NUMBERS IN DATA\n', this.filterEvenData().map((key,i) =>`${i+1} = ${key}\n`) ]), m('div', 'Enter a number'), m('input[placeholder=number]', { // addNewData is called with **this** === undefined unless we pass `this` to Function.prototype.call in m.withAttr onchange: m.withAttr('value', App.addNewData, App), value: null } ) ]) } } Object.setPrototypeOf(App, Model) m.mount(document.body, App) ``` --- mithril.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mithril.js b/mithril.js index 080c6052..a58e2fc3 100644 --- a/mithril.js +++ b/mithril.js @@ -851,11 +851,12 @@ var m = (function app(window, undefined) { else m.endComputation(); } - m.withAttr = function(prop, withAttrCallback) { + m.withAttr = function(prop, withAttrCallback, callbackThis) { return function(e) { e = e || event; var currentTarget = e.currentTarget || this; - withAttrCallback(prop in currentTarget ? currentTarget[prop] : currentTarget.getAttribute(prop)); + var _this = callbackThis || this; + withAttrCallback.call(_this, prop in currentTarget ? currentTarget[prop] : currentTarget.getAttribute(prop)); }; }; From 352d093d90857c064e485beb33b6904bc0eeec1f Mon Sep 17 00:00:00 2001 From: pelonpelon Date: Sat, 1 Aug 2015 15:01:38 -0500 Subject: [PATCH 5/9] test for correct `this` on m.withAttr callback --- tests/mithril-tests.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/mithril-tests.js b/tests/mithril-tests.js index 36c50785..f1597309 100644 --- a/tests/mithril-tests.js +++ b/tests/mithril-tests.js @@ -1380,6 +1380,13 @@ function testMithril(mock) { handler({currentTarget: {test: "foo"}}) return value === "foo" }) + test(function() { + var value + var _this + var handler = m.withAttr("test", function(data) {value = data}, _this) + handler({currentTarget: {test: "foo"}}) + return value === "foo" && handler.this === _this + }) //m.trust test(function() {return m.trust("test").valueOf() === "test"}) From 49412ea96bc07650c9353f93cf2734c96b2ec120 Mon Sep 17 00:00:00 2001 From: islahul Date: Mon, 3 Aug 2015 09:54:58 +0530 Subject: [PATCH 6/9] style fixes spaces and indentation Signed-off-by: islahul --- mithril.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mithril.js b/mithril.js index 080c6052..cf3c1b9c 100644 --- a/mithril.js +++ b/mithril.js @@ -22,7 +22,7 @@ var m = (function app(window, undefined) { var $document, $location, $requestAnimationFrame, $cancelAnimationFrame; // self invoking function needed because of the way mocks work - function initialize(window){ + function initialize(window) { $document = window.document; $location = window.location; $cancelAnimationFrame = window.cancelAnimationFrame || window.clearTimeout; @@ -31,9 +31,9 @@ var m = (function app(window, undefined) { initialize(window); - m.version = function(){ - return VERSION; - }; + m.version = function() { + return VERSION; + }; /** * @typedef {String} Tag From 9a42242454ca045b643669bea03bf247963416c6 Mon Sep 17 00:00:00 2001 From: Marco Lamberto Date: Tue, 4 Aug 2015 12:16:29 +0200 Subject: [PATCH 7/9] Fixes #721. Firefox insertAdjacentHTML updating text nodes with "beforeend" instead of creating new ones. --- mithril.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mithril.js b/mithril.js index efb3a92b..caae614c 100644 --- a/mithril.js +++ b/mithril.js @@ -636,7 +636,12 @@ var m = (function app(window, undefined) { } else nextSibling.insertAdjacentHTML("beforebegin", data); } - else parentElement.insertAdjacentHTML("beforeend", data); + else { + if (window.Range && window.Range.prototype.createContextualFragment) { + parentElement.appendChild($document.createRange().createContextualFragment(data)); + } + else parentElement.insertAdjacentHTML("beforeend", data); + } var nodes = []; while (parentElement.childNodes[index] !== nextSibling) { nodes.push(parentElement.childNodes[index]); From 713b458aea608502c9f1eb262a1d844517855fcf Mon Sep 17 00:00:00 2001 From: Marco Lamberto Date: Tue, 4 Aug 2015 13:01:07 +0200 Subject: [PATCH 8/9] Better detection for Range support. --- mithril.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/mithril.js b/mithril.js index caae614c..55a9cd29 100644 --- a/mithril.js +++ b/mithril.js @@ -624,6 +624,23 @@ var m = (function app(window, undefined) { else if (cached.children.tag) unload(cached.children); } } + + var insertAdjacentBeforeEnd = (function () { + var rangeStrategy = function (parentElement, data) { + parentElement.appendChild($document.createRange().createContextualFragment(data)); + }; + var insertAdjacentStrategy = function (parentElement, data) { + parentElement.insertAdjacentHTML("beforeend", data); + }; + + try { + $document.createRange().createContextualFragment('x'); + return rangeStrategy; + } catch (e) { + return insertAdjacentStrategy; + } + })(); + function injectHTML(parentElement, index, data) { var nextSibling = parentElement.childNodes[index]; if (nextSibling) { @@ -636,12 +653,8 @@ var m = (function app(window, undefined) { } else nextSibling.insertAdjacentHTML("beforebegin", data); } - else { - if (window.Range && window.Range.prototype.createContextualFragment) { - parentElement.appendChild($document.createRange().createContextualFragment(data)); - } - else parentElement.insertAdjacentHTML("beforeend", data); - } + else insertAdjacentBeforeEnd(parentElement, data); + var nodes = []; while (parentElement.childNodes[index] !== nextSibling) { nodes.push(parentElement.childNodes[index]); From 132fe161760041c284a691add319e69dc017b54c Mon Sep 17 00:00:00 2001 From: Patrick Kristiansen Date: Tue, 4 Aug 2015 16:57:13 +0200 Subject: [PATCH 9/9] Update externs for Google Closure compiler --- mithril.closure-compiler-externs.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mithril.closure-compiler-externs.js b/mithril.closure-compiler-externs.js index ed3575ca..294c3ee1 100644 --- a/mithril.closure-compiler-externs.js +++ b/mithril.closure-compiler-externs.js @@ -1,5 +1,6 @@ var m = { "render": function () {}, + "mount": function () {}, "trust": function () {}, "module": function () {}, "redraw": function () {}, @@ -11,5 +12,6 @@ var m = { "deferred": function () {}, "sync": function () {}, "request": function () {}, - "deps": function () {} + "deps": function () {}, + "component": function() {} }