From 09b25cb803adf5ac51a4a73bea241e6b761edcac Mon Sep 17 00:00:00 2001 From: Leo Horie Date: Wed, 10 Dec 2014 22:34:20 -0500 Subject: [PATCH 1/2] #378 fix strategy none semantics --- docs/mithril.redraw.md | 10 +++++++++- mithril.js | 13 ++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/docs/mithril.redraw.md b/docs/mithril.redraw.md index 16c8f504..344620b4 100644 --- a/docs/mithril.redraw.md +++ b/docs/mithril.redraw.md @@ -122,7 +122,7 @@ Note that the redraw strategy is a global setting that affects the entire templa ### Preventing redraws on events -Sometimes you only care about a particular condition in an event and want to ignore it if this condition is not met. +Sometimes you only care about a particular condition in an event and want the event to not trigger a redraw if this condition is not met. For example, you might only be interested in running a redraw if a user presses the space bar, and you might not want to waste a redraw if the user presses any other key. In that case, it's possible to skip redrawing altogether by calling `m.redraw.strategy("none")` ```javascript @@ -132,6 +132,14 @@ m("input", {onkeydown: function(e) { }}) ``` +There are some important semantic caveats for `m.redraw.strategy("none")` that you should be aware of: Setting the strategy to `"none"` only affects **synchronous** redraws. As soon as the event handler returns, the strategy is set back to "diff". + +If you set strategy to `"none"` but then proceed to trigger a redraw asynchronously, either via `start/endComputation`, `m.redraw` or `m.request`, a redraw *will* occur, using the `"diff"` strategy. + +Additionally, calling `m.redraw` synchronously after calling `m.redraw.strategy("none")` resets the strategy to `"diff"`. + +Lastly, be aware that if a user action triggers more than one event handler (for example, oninput and onkeypress, or an event bubbling up to event handlers in multiple ancestor elements), every event triggers a redraw by default. Setting strategy to none in any one of those handlers will not affect the redrawing strategy of other handlers (and remember that `strategy("none")` has no effect on asynchronous redraws). + --- ### Forcing redraw diff --git a/mithril.js b/mithril.js index ff799287..db6d7d5c 100644 --- a/mithril.js +++ b/mithril.js @@ -409,7 +409,7 @@ var m = (function app(window, undefined) { m.startComputation(); try {return callback.call(object, e)} finally { - m.endComputation() + endFirstComputation() } } } @@ -499,7 +499,7 @@ var m = (function app(window, undefined) { controllers[index] = controller; modules[index] = module } - m.endComputation(); + endFirstComputation(); return controllers[index] } }; @@ -523,7 +523,7 @@ var m = (function app(window, undefined) { function redraw() { var mode = m.redraw.strategy(); for (var i = 0, root; root = roots[i]; i++) { - if (controllers[i] && mode != "none") { + if (controllers[i]) { m.render(root, modules[i].view(controllers[i]), mode === "all") } } @@ -543,6 +543,13 @@ var m = (function app(window, undefined) { pendingRequests = Math.max(pendingRequests - 1, 0); if (pendingRequests === 0) m.redraw() }; + var endFirstComputation = function() { + if (m.redraw.strategy() == "none") { + pendingRequests-- + m.redraw.strategy("diff") + } + else m.endComputation(); + } m.withAttr = function(prop, withAttrCallback) { return function(e) { From 3073b27abd82ab0b50e87c14c5362b8bafe97044 Mon Sep 17 00:00:00 2001 From: Leo Horie Date: Wed, 10 Dec 2014 23:06:15 -0500 Subject: [PATCH 2/2] improve loop --- mithril.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mithril.js b/mithril.js index db6d7d5c..867d4ed7 100644 --- a/mithril.js +++ b/mithril.js @@ -521,10 +521,10 @@ var m = (function app(window, undefined) { }; m.redraw.strategy = m.prop(); function redraw() { - var mode = m.redraw.strategy(); + var forceRedraw = m.redraw.strategy() === "all"; for (var i = 0, root; root = roots[i]; i++) { if (controllers[i]) { - m.render(root, modules[i].view(controllers[i]), mode === "all") + m.render(root, modules[i].view(controllers[i]), forceRedraw) } } //after rendering within a routed context, we need to scroll back to the top, and fetch the document title for history.pushState