diff --git a/docs/getting-started.md b/docs/getting-started.md
index 0b2814ce..fdad414d 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -498,7 +498,7 @@ m.mount(document, {controller: todo.controller, view: todo.view});
```
-This example is also available as a [jsFiddle](http://jsfiddle.net/milesmatthias/fbgypzbr/1/).
+This example is also available as a [jsFiddle](http://jsfiddle.net/fbgypzbr/16/).
There is also [Extended example](http://jsfiddle.net/glebcha/q7tvLxsa/) available on jsfiddle.
---
diff --git a/docs/installation.md b/docs/installation.md
index 170a6a02..206caa37 100644
--- a/docs/installation.md
+++ b/docs/installation.md
@@ -60,7 +60,7 @@ Then, to use Mithril, point a script tag to the downloaded file:
### Bower
-[Bower](http://bower.io) is a package manager for [NodeJS](http://nodejs.org/). If you're using NodeJS already or planning on using [Grunt](http://gruntjs.com/) to create a build system, you can use Bower to conveniently keep up-to-date with Mithril versions.
+[Bower](http://bower.io) is a frontend package manager built in [NodeJS](http://nodejs.org/). If you're using NodeJS already or planning on using [Grunt](http://gruntjs.com/) to create a build system, you can use Bower to conveniently keep up-to-date with Mithril versions.
Assuming you have NodeJS installed, you can install Bower by typing this in the command line:
diff --git a/docs/mithril.component.md b/docs/mithril.component.md
index 0766de56..4e26d0b0 100644
--- a/docs/mithril.component.md
+++ b/docs/mithril.component.md
@@ -219,7 +219,7 @@ Components can be placed anywhere a regular element can. If you have components
var App = {
controller: function() {
return {data: [1, 2, 3]}
- }
+ },
view: function(ctrl) {
return m(".app", [
//pressing the button reverses the list
@@ -513,7 +513,7 @@ There are a few other technical caveats when nesting components:
1. Nested component views must return either a virtual element or another component. Returning an array, a string, a number, boolean, falsy value, etc will result in an error.
-2. Nested components cannot change `m.redraw.strategy` from the controller constructor (but they can from event handlers). It's recommended that you use the [`ctx.retain`](mithril.md#persising-dom-elements-across-route-changes) flag instead of changing the redraw strategy in controller constructors.
+2. Nested components cannot change `m.redraw.strategy` from the controller constructor (but they can from event handlers). It's recommended that you use the [`ctx.retain`](mithril.md#persisting-dom-elements-across-route-changes) flag instead of changing the redraw strategy in controller constructors.
3. The root DOM element in a component's view must not be changed during the lifecycle of the component, otherwise undefined behavior will occur. In other words, don't do this:
diff --git a/docs/mithril.deferred.md b/docs/mithril.deferred.md
index 69120a21..9266f0c5 100644
--- a/docs/mithril.deferred.md
+++ b/docs/mithril.deferred.md
@@ -223,7 +223,7 @@ where:
The default value (if this parameter is falsy) is the identity function `function(value) {return value}`
- If this function returns undefined, then it passes the `value` argument to the next step in the thennable queue, if any
+ If this function returns undefined, then it passes the `value` argument to the next step in the thenable queue, if any
- **any errorCallback(any value)** (optional)
@@ -231,7 +231,7 @@ where:
The default value (if this parameter is falsy) is the identity function `function(value) {return value}`
- If this function returns undefined, then it passes the `value` argument to the next step in the thennable queue, if any
+ If this function returns undefined, then it passes the `value` argument to the next step in the thenable queue, if any
- **returns Promise promise**
diff --git a/docs/mithril.redraw.md b/docs/mithril.redraw.md
index 88ef3f45..ee0f0e51 100644
--- a/docs/mithril.redraw.md
+++ b/docs/mithril.redraw.md
@@ -126,7 +126,7 @@ Common reasons why one might need to change redraw strategy are:
Note that the redraw strategy is a global setting that affects the entire template trees of all components on the page. In order to prevent redraws in *some parts* of an application, but not others, see [subtree directives](mithril.render.md#subtree-directives)
-You can also configure individual elements to always be diffed, instead of recreated from scratch (even across route changes), by using the [`ctx.retain` flag](mithril.md#persising-dom-elements-across-route-changes). If you need to persist DOM state across route changes, it's recommended that you use the `ctx.retain` flag instead of `m.redraw.strategy("diff")`.
+You can also configure individual elements to always be diffed, instead of recreated from scratch (even across route changes), by using the [`ctx.retain` flag](mithril.md#persisting-dom-elements-across-route-changes). If you need to persist DOM state across route changes, it's recommended that you use the `ctx.retain` flag instead of `m.redraw.strategy("diff")`.
---
diff --git a/docs/routing.md b/docs/routing.md
index da660ea3..a6970a25 100644
--- a/docs/routing.md
+++ b/docs/routing.md
@@ -62,7 +62,7 @@ In this case, since there's only one route, the app redirects to the default rou
The string `johndoe` is bound to the `:userID` parameter, which can be retrieved programmatically in the controller via `m.route.param("userID")`.
-The `m.route.mode` property defines which URL portion is used to implement the routing mechanism. Its value can be set to either "search", "hash" or "pathname". The default value is "search".
+The `m.route.mode` property defines which URL portion is used to implement the routing mechanism. It should be set before any calls to `m.route`. Its value can be set to either "search", "hash" or "pathname". The default value is "search".
- `search` mode uses the querystring. This allows named anchors (i.e. `Back to top`, ``) to work on the page, but routing changes causes page refreshes in IE8, due to its lack of support for `history.pushState`.
diff --git a/docs/web-services.md b/docs/web-services.md
index ba1bfb54..469bfb4b 100644
--- a/docs/web-services.md
+++ b/docs/web-services.md
@@ -27,7 +27,7 @@ var users = m.request({method: "GET", url: "/user"});
Note that this getter-setter holds an *undefined* value until the AJAX request completes. Attempting to unwrap its value early will likely result in errors.
-The returned getter-setter also implements the [promise](mithril.deferred.md) interface (also known as a *thennable*): this is the mechanism you should always use to queue operations to be performed on the data from the web service.
+The returned getter-setter also implements the [promise](mithril.deferred.md) interface (also known as a *thenable*): this is the mechanism you should always use to queue operations to be performed on the data from the web service.
The simplest use case of this feature is to implement functional value assignment via `m.prop` (i.e. the same thing as above). You can bind a pre-existing getter-setter by passing it in as a parameter to a `.then` method:
@@ -49,9 +49,9 @@ var doSomething = function() { /*...*/ }
m.request({method: "GET", url: "/user"}).then(users).then(doSomething)
```
-While both basic assignment syntax and thennable syntax can be used to the same effect, typically it's recommended that you use the assignment syntax in the first example whenever possible, as it's easier to read.
+While both basic assignment syntax and thenable syntax can be used to the same effect, typically it's recommended that you use the assignment syntax in the first example whenever possible, as it's easier to read.
-The thennable mechanism is intended to be used in three ways:
+The thenable mechanism is intended to be used in three ways:
- In the model layer: to process web service data in transformative ways (e.g. filtering a list based on a parameter that the web service doesn't support)
- In the controller layer: to bind redirection code upon a condition
@@ -98,7 +98,7 @@ var controller = function() {
#### Binding errors
-Mithril thennables take two functions as optional parameters: the first parameter is called if the web service request completes successfully. The second parameter is called if it completes with an error.
+Mithril thenables take two functions as optional parameters: the first parameter is called if the web service request completes successfully. The second parameter is called if it completes with an error.
Error binding is meant to be done in the controller layer. Doing it in the model level is also possible, but generally leads to more code in order to connect all the dots.
diff --git a/mithril.js b/mithril.js
index 688112c9..3e4c0867 100644
--- a/mithril.js
+++ b/mithril.js
@@ -3,7 +3,7 @@ var m = (function app(window, undefined) {
var type = {}.toString;
var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, attrParser = /\[(.+?)(?:=("|'|)(.*?)\2)?\]/;
var voidElements = /^(AREA|BASE|BR|COL|COMMAND|EMBED|HR|IMG|INPUT|KEYGEN|LINK|META|PARAM|SOURCE|TRACK|WBR)$/;
- var noop = function() {}
+ var noop = function() {};
// caching commonly used variables
var $document, $location, $requestAnimationFrame, $cancelAnimationFrame;
@@ -40,37 +40,37 @@ var m = (function app(window, undefined) {
var classAttrName = "class" in attrs ? "class" : "className";
var cell = {tag: "div", attrs: {}};
var match, classes = [];
- if (type.call(args[0]) != STRING) throw new Error("selector in m(selector, attrs, children) should be a string")
+ if (type.call(args[0]) != STRING) throw new Error("selector in m(selector, attrs, children) should be a string");
while (match = parser.exec(args[0])) {
if (match[1] === "" && match[2]) cell.tag = match[2];
else if (match[1] === "#") cell.attrs.id = match[2];
else if (match[1] === ".") classes.push(match[2]);
else if (match[3][0] === "[") {
var pair = attrParser.exec(match[3]);
- cell.attrs[pair[1]] = pair[3] || (pair[2] ? "" :true)
+ cell.attrs[pair[1]] = pair[3] || (pair[2] ? "" :true);
}
}
var children = hasAttrs ? args.slice(2) : args.slice(1);
if (children.length === 1 && type.call(children[0]) === ARRAY) {
- cell.children = children[0]
+ cell.children = children[0];
}
else {
- cell.children = children
+ cell.children = children;
}
-
+
for (var attrName in attrs) {
if (attrs.hasOwnProperty(attrName)) {
if (attrName === classAttrName && attrs[attrName] != null && attrs[attrName] !== "") {
- classes.push(attrs[attrName])
- cell.attrs[attrName] = "" //create key in correct iteration order
+ classes.push(attrs[attrName]);
+ cell.attrs[attrName] = ""; //create key in correct iteration order
}
- else cell.attrs[attrName] = attrs[attrName]
+ else cell.attrs[attrName] = attrs[attrName];
}
}
if (classes.length > 0) cell.attrs[classAttrName] = classes.join(" ");
-
- return cell
+
+ return cell;
}
function build(parentElement, parentTag, parentCache, parentIndex, data, cached, shouldReattach, index, editable, namespace, configs) {
//`build` is a recursive function that manages creation/diffing/removal of DOM elements based on comparison between `data` and `cached`
@@ -99,7 +99,7 @@ var m = (function app(window, undefined) {
//- this prevents lifecycle surprises from procedural helpers that mix implicit and explicit return statements (e.g. function foo() {if (cond) return m("div")}
//- it simplifies diffing code
//data.toString() might throw or return null if data is the return value of Console.log in Firefox (behavior depends on version)
- try {if (data == null || data.toString() == null) data = "";} catch (e) {data = ""}
+ try { if (data == null || data.toString() == null) data = ""; } catch (e) { data = ""; }
if (data.subtree === "retain") return cached;
var cachedType = type.call(cached), dataType = type.call(data);
if (cached == null || cachedType !== dataType) {
@@ -107,13 +107,13 @@ var m = (function app(window, undefined) {
if (parentCache && parentCache.nodes) {
var offset = index - parentIndex;
var end = offset + (dataType === ARRAY ? data : cached.nodes).length;
- clear(parentCache.nodes.slice(offset, end), parentCache.slice(offset, end))
+ clear(parentCache.nodes.slice(offset, end), parentCache.slice(offset, end));
}
- else if (cached.nodes) clear(cached.nodes, cached)
+ else if (cached.nodes) clear(cached.nodes, cached);
}
cached = new data.constructor;
if (cached.tag) cached = {}; //if constructor creates a virtual dom element, use a blank object as the base cached node instead of copying the virtual el (#277)
- cached.nodes = []
+ cached.nodes = [];
}
if (dataType === ARRAY) {
@@ -121,11 +121,11 @@ var m = (function app(window, undefined) {
for (var i = 0, len = data.length; i < len; i++) {
if (type.call(data[i]) === ARRAY) {
data = data.concat.apply([], data);
- i-- //check current index again and flatten until there are no more nested arrays at that index
- len = data.length
+ i--; //check current index again and flatten until there are no more nested arrays at that index
+ len = data.length;
}
}
-
+
var nodes = [], intact = cached.length === data.length, subArrayCount = 0;
//keys algorithm: sort elements without recreating them if keys are present
@@ -138,30 +138,30 @@ var m = (function app(window, undefined) {
for (var i = 0; i < cached.length; i++) {
if (cached[i] && cached[i].attrs && cached[i].attrs.key != null) {
shouldMaintainIdentities = true;
- existing[cached[i].attrs.key] = {action: DELETION, index: i}
+ existing[cached[i].attrs.key] = {action: DELETION, index: i};
}
}
-
- var guid = 0
+
+ var guid = 0;
for (var i = 0, len = data.length; i < len; i++) {
if (data[i] && data[i].attrs && data[i].attrs.key != null) {
for (var j = 0, len = data.length; j < len; j++) {
- if (data[j] && data[j].attrs && data[j].attrs.key == null) data[j].attrs.key = "__mithril__" + guid++
+ if (data[j] && data[j].attrs && data[j].attrs.key == null) data[j].attrs.key = "__mithril__" + guid++;
}
- break
+ break;
}
}
-
+
if (shouldMaintainIdentities) {
- var keysDiffer = false
- if (data.length != cached.length) keysDiffer = true
+ var keysDiffer = false;
+ if (data.length != cached.length) keysDiffer = true;
else for (var i = 0, cachedCell, dataCell; cachedCell = cached[i], dataCell = data[i]; i++) {
if (cachedCell.attrs && dataCell.attrs && cachedCell.attrs.key != dataCell.attrs.key) {
- keysDiffer = true
- break
+ keysDiffer = true;
+ break;
}
}
-
+
if (keysDiffer) {
for (var i = 0, len = data.length; i < len; i++) {
if (data[i] && data[i].attrs) {
@@ -173,35 +173,35 @@ var m = (function app(window, undefined) {
index: i,
from: existing[key].index,
element: cached.nodes[existing[key].index] || $document.createElement("div")
- }
+ };
}
}
}
- var actions = []
- for (var prop in existing) actions.push(existing[prop])
+ var actions = [];
+ for (var prop in existing) actions.push(existing[prop]);
var changes = actions.sort(sortChanges);
- var newCached = new Array(cached.length)
- newCached.nodes = cached.nodes.slice()
+ var newCached = new Array(cached.length);
+ newCached.nodes = cached.nodes.slice();
for (var i = 0, change; change = changes[i]; i++) {
if (change.action === DELETION) {
clear(cached[change.index].nodes, cached[change.index]);
- newCached.splice(change.index, 1)
+ newCached.splice(change.index, 1);
}
if (change.action === INSERTION) {
var dummy = $document.createElement("div");
dummy.key = data[change.index].attrs.key;
parentElement.insertBefore(dummy, parentElement.childNodes[change.index] || null);
- newCached.splice(change.index, 0, {attrs: {key: data[change.index].attrs.key}, nodes: [dummy]})
- newCached.nodes[change.index] = dummy
+ newCached.splice(change.index, 0, {attrs: {key: data[change.index].attrs.key}, nodes: [dummy]});
+ newCached.nodes[change.index] = dummy;
}
if (change.action === MOVE) {
if (parentElement.childNodes[change.index] !== change.element && change.element !== null) {
- parentElement.insertBefore(change.element, parentElement.childNodes[change.index] || null)
+ parentElement.insertBefore(change.element, parentElement.childNodes[change.index] || null);
}
- newCached[change.index] = cached[change.from]
- newCached.nodes[change.index] = change.element
+ newCached[change.index] = cached[change.from];
+ newCached.nodes[change.index] = change.element;
}
}
cached = newCached;
@@ -218,57 +218,57 @@ var m = (function app(window, undefined) {
//fix offset of next element if item was a trusted string w/ more than one html element
//the first clause in the regexp matches elements
//the second clause (after the pipe) matches text nodes
- subArrayCount += (item.match(/<[^\/]|\>\s*[^<]/g) || [0]).length
+ subArrayCount += (item.match(/<[^\/]|\>\s*[^<]/g) || [0]).length;
}
else subArrayCount += type.call(item) === ARRAY ? item.length : 1;
- cached[cacheCount++] = item
+ cached[cacheCount++] = item;
}
if (!intact) {
//diff the array itself
-
+
//update the list of DOM nodes by collecting the nodes from each item
for (var i = 0, len = data.length; i < len; i++) {
- if (cached[i] != null) nodes.push.apply(nodes, cached[i].nodes)
+ if (cached[i] != null) nodes.push.apply(nodes, cached[i].nodes);
}
//remove items from the end of the array if the new array is shorter than the old one
//if errors ever happen here, the issue is most likely a bug in the construction of the `cached` data structure somewhere earlier in the program
for (var i = 0, node; node = cached.nodes[i]; i++) {
- if (node.parentNode != null && nodes.indexOf(node) < 0) clear([node], [cached[i]])
+ if (node.parentNode != null && nodes.indexOf(node) < 0) clear([node], [cached[i]]);
}
if (data.length < cached.length) cached.length = data.length;
- cached.nodes = nodes
+ cached.nodes = nodes;
}
}
else if (data != null && dataType === OBJECT) {
- var views = [], controllers = []
+ var views = [], controllers = [];
while (data.view) {
- var view = data.view.$original || data.view
- var controllerIndex = m.redraw.strategy() == "diff" && cached.views ? cached.views.indexOf(view) : -1
- var controller = controllerIndex > -1 ? cached.controllers[controllerIndex] : new (data.controller || noop)
- var key = data && data.attrs && data.attrs.key
- data = (pendingRequests == 0 || forcing) || (cached && cached.controllers && cached.controllers.indexOf(controller) > -1) ? data.view(controller) : {tag: "placeholder"}
+ var view = data.view.$original || data.view;
+ var controllerIndex = m.redraw.strategy() == "diff" && cached.views ? cached.views.indexOf(view) : -1;
+ var controller = controllerIndex > -1 ? cached.controllers[controllerIndex] : new (data.controller || noop);
+ var key = data && data.attrs && data.attrs.key;
+ data = (pendingRequests == 0 || forcing) || (cached && cached.controllers && cached.controllers.indexOf(controller) > -1) ? data.view(controller) : {tag: "placeholder"};
if (data.subtree === "retain") return cached;
if (key) {
- if (!data.attrs) data.attrs = {}
- data.attrs.key = key
+ if (!data.attrs) data.attrs = {};
+ data.attrs.key = key;
}
- if (controller.onunload) unloaders.push({controller: controller, handler: controller.onunload})
- views.push(view)
- controllers.push(controller)
+ if (controller.onunload) unloaders.push({controller: controller, handler: controller.onunload});
+ views.push(view);
+ controllers.push(controller);
}
- if (!data.tag && controllers.length) throw new Error("Component template must return a virtual element, not an array, string, etc.")
+ if (!data.tag && controllers.length) throw new Error("Component template must return a virtual element, not an array, string, etc.");
if (!data.attrs) data.attrs = {};
if (!cached.attrs) cached.attrs = {};
- var dataAttrKeys = Object.keys(data.attrs)
- var hasKeys = dataAttrKeys.length > ("key" in data.attrs ? 1 : 0)
+ var dataAttrKeys = Object.keys(data.attrs);
+ var hasKeys = dataAttrKeys.length > ("key" in data.attrs ? 1 : 0);
//if an element is different enough from the one in cache, recreate it
if (data.tag != cached.tag || dataAttrKeys.sort().join() != Object.keys(cached.attrs).sort().join() || data.attrs.id != cached.attrs.id || data.attrs.key != cached.attrs.key || (m.redraw.strategy() == "all" && (!cached.configContext || cached.configContext.retain !== true)) || (m.redraw.strategy() == "diff" && cached.configContext && cached.configContext.retain === false)) {
if (cached.nodes.length) clear(cached.nodes);
- if (cached.configContext && typeof cached.configContext.onunload === FUNCTION) cached.configContext.onunload()
+ if (cached.configContext && typeof cached.configContext.onunload === FUNCTION) cached.configContext.onunload();
if (cached.controllers) {
for (var i = 0, controller; controller = cached.controllers[i]; i++) {
- if (typeof controller.onunload === FUNCTION) controller.onunload({preventDefault: noop})
+ if (typeof controller.onunload === FUNCTION) controller.onunload({preventDefault: noop});
}
}
}
@@ -278,7 +278,7 @@ var m = (function app(window, undefined) {
if (data.attrs.xmlns) namespace = data.attrs.xmlns;
else if (data.tag === "svg") namespace = "http://www.w3.org/2000/svg";
else if (data.tag === "math") namespace = "http://www.w3.org/1998/Math/MathML";
-
+
if (isNew) {
if (data.attrs.is) node = namespace === undefined ? $document.createElement(data.tag, data.attrs.is) : $document.createElementNS(namespace, data.tag, data.attrs.is);
else node = namespace === undefined ? $document.createElement(data.tag) : $document.createElementNS(namespace, data.tag);
@@ -292,22 +292,22 @@ var m = (function app(window, undefined) {
nodes: [node]
};
if (controllers.length) {
- cached.views = views
- cached.controllers = controllers
+ cached.views = views;
+ cached.controllers = controllers;
for (var i = 0, controller; controller = controllers[i]; i++) {
- if (controller.onunload && controller.onunload.$old) controller.onunload = controller.onunload.$old
+ if (controller.onunload && controller.onunload.$old) controller.onunload = controller.onunload.$old;
if (pendingRequests && controller.onunload) {
- var onunload = controller.onunload
- controller.onunload = noop
- controller.onunload.$old = onunload
+ var onunload = controller.onunload;
+ controller.onunload = noop;
+ controller.onunload.$old = onunload;
}
}
}
-
+
if (cached.children && !cached.children.nodes) cached.children.nodes = [];
//edge case: setting value on