From 5afefb30b88a2edd289d023706a59e62f3fed08f Mon Sep 17 00:00:00 2001
From: Leo Horie
Date: Fri, 14 Nov 2014 23:37:36 -0500
Subject: [PATCH 1/6] const style
---
mithril.js | 54 +++++++++++++++++++++++++++---------------------------
1 file changed, 27 insertions(+), 27 deletions(-)
diff --git a/mithril.js b/mithril.js
index 8a2d1166..db22d811 100644
--- a/mithril.js
+++ b/mithril.js
@@ -1,5 +1,5 @@
Mithril = m = new function app(window, undefined) {
- var sObj = "[object Object]", sArr = "[object Array]", sStr = "[object String]", sFn = "function";
+ var OBJECT = "[object Object]", ARRAY = "[object Array]", STRING = "[object String]", FUNCTION = "function";
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)$/;
@@ -33,7 +33,7 @@ Mithril = m = new function app(window, undefined) {
*/
function m() {
var args = [].slice.call(arguments);
- var hasAttrs = args[1] != null && type.call(args[1]) == sObj && !("tag" in args[1]) && !("subtree" in args[1]);
+ var hasAttrs = args[1] != null && type.call(args[1]) == OBJECT && !("tag" in args[1]) && !("subtree" in args[1]);
var attrs = hasAttrs ? args[1] : {};
var classAttrName = "class" in attrs ? "class" : "className";
var cell = {tag: "div", attrs: {}};
@@ -51,7 +51,7 @@ Mithril = m = new function app(window, undefined) {
var children = hasAttrs ? args[2] : args[1];
- if (type.call(children) == sArr) {
+ if (type.call(children) == ARRAY) {
cell.children = children
}
else {
@@ -97,7 +97,7 @@ Mithril = m = new function app(window, undefined) {
if (cached != null) {
if (parentCache && parentCache.nodes) {
var offset = index - parentIndex;
- var end = offset + (dataType == sArr ? data : cached.nodes).length;
+ var end = offset + (dataType == ARRAY ? data : cached.nodes).length;
clear(parentCache.nodes.slice(offset, end), parentCache.slice(offset, end))
}
else if (cached.nodes) clear(cached.nodes, cached)
@@ -107,10 +107,10 @@ Mithril = m = new function app(window, undefined) {
cached.nodes = []
}
- if (dataType == sArr) {
+ if (dataType == ARRAY) {
//recursively flatten array
for (var i = 0; i < data.length; i++) {
- if (type.call(data[i]) == sArr) {
+ 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
}
@@ -193,7 +193,7 @@ Mithril = m = new function app(window, undefined) {
//the second clause (after the pipe) matches text nodes
subArrayCount += (item.match(/<[^\/]|\>\s*[^<]/g) || []).length
}
- else subArrayCount += type.call(item) == sArr ? item.length : 1;
+ else subArrayCount += type.call(item) == ARRAY ? item.length : 1;
cached[cacheCount++] = item
}
if (!intact) {
@@ -212,7 +212,7 @@ Mithril = m = new function app(window, undefined) {
cached.nodes = nodes
}
}
- else if (data != null && dataType == sObj) {
+ else if (data != null && dataType == OBJECT) {
if (!data.attrs) data.attrs = {};
if (!cached.attrs) cached.attrs = {};
@@ -221,9 +221,9 @@ Mithril = m = new function app(window, undefined) {
//if an element is different enough from the one in cache, recreate it
if (data.tag != cached.tag || dataAttrKeys.join() != Object.keys(cached.attrs).join() || data.attrs.id != cached.attrs.id) {
if (cached.nodes.length) clear(cached.nodes);
- if (cached.configContext && typeof cached.configContext.onunload == sFn) cached.configContext.onunload()
+ if (cached.configContext && typeof cached.configContext.onunload == FUNCTION) cached.configContext.onunload()
}
- if (type.call(data.tag) != sStr) return;
+ if (type.call(data.tag) != STRING) return;
var node, isNew = cached.nodes.length === 0;
if (data.attrs.xmlns) namespace = data.attrs.xmlns;
@@ -254,7 +254,7 @@ Mithril = m = new function app(window, undefined) {
if (shouldReattach === true && node != null) parentElement.insertBefore(node, parentElement.childNodes[index] || null)
}
//schedule configs to be called. They are called after `build` finishes running
- if (typeof data.attrs["config"] == sFn) {
+ if (typeof data.attrs["config"] == FUNCTION) {
var context = cached.configContext = cached.configContext || {};
// bind
@@ -266,7 +266,7 @@ Mithril = m = new function app(window, undefined) {
configs.push(callback(data, [node, !isNew, context, cached]))
}
}
- else if (typeof dataType != sFn) {
+ else if (typeof dataType != FUNCTION) {
//handle text nodes
var nodes;
if (cached.nodes.length === 0) {
@@ -321,11 +321,11 @@ Mithril = m = new function app(window, undefined) {
//we don't ignore `key` because it must be unique and having it on the DOM helps debugging
if (attrName === "config") continue;
//hook event handlers to the auto-redrawing system
- else if (typeof dataAttr == sFn && attrName.indexOf("on") == 0) {
+ else if (typeof dataAttr == FUNCTION && attrName.indexOf("on") == 0) {
node[attrName] = autoredraw(dataAttr, node)
}
//handle `style: {...}`
- else if (attrName === "style" && dataAttr != null && type.call(dataAttr) == sObj) {
+ else if (attrName === "style" && dataAttr != null && type.call(dataAttr) == OBJECT) {
for (var rule in dataAttr) {
if (cachedAttr == null || cachedAttr[rule] !== dataAttr[rule]) node.style[rule] = dataAttr[rule]
}
@@ -369,9 +369,9 @@ Mithril = m = new function app(window, undefined) {
if (nodes.length != 0) nodes.length = 0
}
function unload(cached) {
- if (cached.configContext && typeof cached.configContext.onunload == sFn) cached.configContext.onunload();
+ if (cached.configContext && typeof cached.configContext.onunload == FUNCTION) cached.configContext.onunload();
if (cached.children) {
- if (type.call(cached.children) == sArr) {
+ if (type.call(cached.children) == ARRAY) {
for (var i = 0; i < cached.children.length; i++) unload(cached.children[i])
}
else if (cached.children.tag) unload(cached.children)
@@ -463,7 +463,7 @@ Mithril = m = new function app(window, undefined) {
m.prop = function (store) {
//note: using non-strict equality check here because we're checking if store is null OR undefined
- if (((store != null && type.call(store) == sObj) || typeof store == sFn) && typeof store.then == sFn) {
+ if (((store != null && type.call(store) == OBJECT) || typeof store == FUNCTION) && typeof store.then == FUNCTION) {
return propify(store)
}
@@ -476,7 +476,7 @@ Mithril = m = new function app(window, undefined) {
var index = roots.indexOf(root);
if (index < 0) index = roots.length;
var isPrevented = false;
- if (controllers[index] && typeof controllers[index].onunload == sFn) {
+ if (controllers[index] && typeof controllers[index].onunload == FUNCTION) {
var event = {
preventDefault: function() {isPrevented = true}
};
@@ -553,7 +553,7 @@ Mithril = m = new function app(window, undefined) {
m.route = function() {
//m.route()
if (arguments.length === 0) return currentRoute;
- else if (arguments.length === 3 && type.call(arguments[1]) == sStr) {
+ else if (arguments.length === 3 && type.call(arguments[1]) == STRING) {
var root = arguments[0], defaultRoute = arguments[1], router = arguments[2];
redirect = function(source) {
var path = currentRoute = normalizeRoute(source);
@@ -580,9 +580,9 @@ Mithril = m = new function app(window, undefined) {
element.addEventListener("click", routeUnobtrusive)
}
//m.route(route)
- else if (type.call(arguments[0]) == sStr) {
+ else if (type.call(arguments[0]) == STRING) {
currentRoute = arguments[0];
- var querystring = arguments[1] != null && type.call(arguments[1]) == sObj ? buildQueryString(arguments[1]) : null;
+ var querystring = arguments[1] != null && type.call(arguments[1]) == OBJECT ? buildQueryString(arguments[1]) : null;
if (querystring) currentRoute += (currentRoute.indexOf("?") === -1 ? "?" : "&") + querystring;
var shouldReplaceHistoryEntry = (arguments.length == 3 ? arguments[2] : arguments[1]) === true;
@@ -645,7 +645,7 @@ Mithril = m = new function app(window, undefined) {
var str = [];
for(var prop in object) {
var key = prefix ? prefix + "[" + prop + "]" : prop, value = object[prop];
- str.push(value != null && type.call(value) == sObj ? buildQueryString(value, key) : encodeURIComponent(key) + "=" + encodeURIComponent(value))
+ str.push(value != null && type.call(value) == OBJECT ? buildQueryString(value, key) : encodeURIComponent(key) + "=" + encodeURIComponent(value))
}
return str.join("&")
}
@@ -731,7 +731,7 @@ Mithril = m = new function app(window, undefined) {
}
function thennable(then, successCallback, failureCallback, notThennableCallback) {
- if (((promiseValue != null && type.call(promiseValue) == sObj) || typeof promiseValue == sFn) && typeof then == sFn) {
+ if (((promiseValue != null && type.call(promiseValue) == OBJECT) || typeof promiseValue == FUNCTION) && typeof then == FUNCTION) {
try {
// count protects against abuse calls from spec checker
var count = 0;
@@ -775,7 +775,7 @@ Mithril = m = new function app(window, undefined) {
fire()
}, function() {
try {
- if (state == RESOLVING && typeof successCallback == sFn) {
+ if (state == RESOLVING && typeof successCallback == FUNCTION) {
promiseValue = successCallback(promiseValue)
}
else if (state == REJECTING && typeof failureCallback == "function") {
@@ -892,13 +892,13 @@ Mithril = m = new function app(window, undefined) {
if (options.deserialize == JSON.parse) {
xhr.setRequestHeader("Accept", "application/json, text/*");
}
- if (typeof options.config == sFn) {
+ if (typeof options.config == FUNCTION) {
var maybeXhr = options.config(xhr, options);
if (maybeXhr != null) xhr = maybeXhr
}
var data = options.method == "GET" || !options.data ? "" : options.data
- if (data && (type.call(data) != sStr && data.constructor != window.FormData)) {
+ if (data && (type.call(data) != STRING && data.constructor != window.FormData)) {
throw "Request data should be either be a string or FormData. Check the `serialize` option in `m.request`";
}
xhr.send(data);
@@ -943,7 +943,7 @@ Mithril = m = new function app(window, undefined) {
var unwrap = (e.type == "load" ? xhrOptions.unwrapSuccess : xhrOptions.unwrapError) || identity;
var response = unwrap(deserialize(extract(e.target, xhrOptions)));
if (e.type == "load") {
- if (type.call(response) == sArr && xhrOptions.type) {
+ if (type.call(response) == ARRAY && xhrOptions.type) {
for (var i = 0; i < response.length; i++) response[i] = new xhrOptions.type(response[i])
}
else if (xhrOptions.type) response = new xhrOptions.type(response)
From 2ec0e5e0c2a864a45803423435035772caccf0e5 Mon Sep 17 00:00:00 2001
From: Chris Bowdon
Date: Sat, 15 Nov 2014 11:02:44 +0000
Subject: [PATCH 2/6] Added declaration for TypeScript external module support
---
mithril.d.ts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/mithril.d.ts b/mithril.d.ts
index 4fcb5b87..a3f6ae18 100644
--- a/mithril.d.ts
+++ b/mithril.d.ts
@@ -63,3 +63,7 @@ interface MithrilXHROptions {
declare var Mithril: MithrilStatic;
declare var m: MithrilStatic;
+
+declare module 'mithril' {
+ export = MithrilStatic;
+}
From 304c5a289be9b75ad2fba6e8c55b81c0b9ded087 Mon Sep 17 00:00:00 2001
From: Leo Horie
Date: Mon, 17 Nov 2014 21:33:16 -0500
Subject: [PATCH 3/6] build fix and doc fixes
---
Gruntfile.js | 10 ++--------
docs/layout/index.html | 2 +-
docs/practices.md | 2 +-
3 files changed, 4 insertions(+), 10 deletions(-)
diff --git a/Gruntfile.js b/Gruntfile.js
index 558754b4..e83bc59e 100755
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -129,7 +129,7 @@ module.exports = function(grunt) {
zip: {
distribution: {
cwd: currentVersionArchiveFolder + "/",
- src: [currentVersionArchiveFolder + "/mithril.min.js", currentVersionArchiveFolder + "/mithril.min.map", currentVersionArchiveFolder + "/mithril.js"],
+ src: [currentVersionArchiveFolder + "/mithril.min.js", currentVersionArchiveFolder + "/mithril.min.js.map", currentVersionArchiveFolder + "/mithril.js"],
dest: currentVersionArchiveFolder + "/mithril.min.zip"
}
},
@@ -148,16 +148,10 @@ module.exports = function(grunt) {
comparisons: {expand: true, cwd: inputFolder + "/layout/comparisons/", src: "./**", dest: currentVersionArchiveFolder + "/comparisons/"},
unminified: {src: "mithril.js", dest: currentVersionArchiveFolder + "/mithril.js"},
minified: {src: "mithril.min.js", dest: currentVersionArchiveFolder + "/mithril.min.js"},
- map: {src: "mithril.min.map", dest: currentVersionArchiveFolder + "/mithril.min.map"},
+ map: {src: "mithril.min.js.map", dest: currentVersionArchiveFolder + "/mithril.min.js.map"},
typescript: {src: "mithril.d.ts", dest: currentVersionArchiveFolder + "/mithril.d.ts"},
publish: {expand: true, cwd: currentVersionArchiveFolder, src: "./**", dest: outputFolder},
archive: {expand: true, cwd: currentVersionArchiveFolder, src: "./**", dest: outputFolder + "/archive/v" + version},
- cdnjs1: {src: currentVersionArchiveFolder + "/mithril.js", dest: "../cdnjs/ajax/libs/mithril/" + version + "/mithril.js"},
- cdnjs2: {src: currentVersionArchiveFolder + "/mithril.min.js", dest: "../cdnjs/ajax/libs/mithril/" + version + "/mithril.min.js"},
- cdnjs3: {src: currentVersionArchiveFolder + "/mithril.min.map", dest: "../cdnjs/ajax/libs/mithril/" + version + "/mithril.min.map"},
- jsdelivr1: {src: currentVersionArchiveFolder + "/mithril.js", dest: "../jsdelivr/files/mithril/" + version + "/mithril.js"},
- jsdelivr2: {src: currentVersionArchiveFolder + "/mithril.min.js", dest: "../jsdelivr/files/mithril/" + version + "/mithril.min.js"},
- jsdelivr3: {src: currentVersionArchiveFolder + "/mithril.min.map", dest: "../jsdelivr/files/mithril/" + version + "/mithril.min.map"}
},
execute: {
tests: {src: [currentVersionArchiveFolder + "/mithril-tests.js"]}
diff --git a/docs/layout/index.html b/docs/layout/index.html
index 21b13509..b8d44753 100644
--- a/docs/layout/index.html
+++ b/docs/layout/index.html
@@ -251,7 +251,7 @@ m.module(document.getElementById("example"), app);
-
+
diff --git a/docs/practices.md b/docs/practices.md
index fa2a7266..172531b3 100644
--- a/docs/practices.md
+++ b/docs/practices.md
@@ -100,7 +100,7 @@ In the unlikely case that you have another global variable called `m` in your pa
Calling this method while using `m.module` or `m.route` should only be done if you have recurring asynchronous view updates (i.e. something that uses setInterval).
-If you're integrating other non-recurring services (e.g. calling setTimeout), you should use [`m.startComputation` / `m.emdComputation`](mithril.computation.md) instead.
+If you're integrating other non-recurring services (e.g. calling setTimeout), you should use [`m.startComputation` / `m.endComputation`](mithril.computation.md) instead.
This is the most potentially expensive method in Mithril and should not be used at a rate faster than the rate at which the native `requestAnimationFrame` method fires (i.e. the rate at which browsers are comfortable calling recurring rendering-intensive code). Typically, this rate is around 60 calls per second.
From d35c959424583855696bdbf1735f390c9de97d6f Mon Sep 17 00:00:00 2001
From: Leo Horie
Date: Mon, 17 Nov 2014 21:40:39 -0500
Subject: [PATCH 4/6] self-host ghbtn for https support
---
docs/layout/ghbtns.html | 1 +
docs/layout/index.html | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
create mode 100644 docs/layout/ghbtns.html
diff --git a/docs/layout/ghbtns.html b/docs/layout/ghbtns.html
new file mode 100644
index 00000000..c4aa9146
--- /dev/null
+++ b/docs/layout/ghbtns.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/layout/index.html b/docs/layout/index.html
index b8d44753..78091558 100644
--- a/docs/layout/index.html
+++ b/docs/layout/index.html
@@ -30,7 +30,7 @@
Download v$version
-
+
From 75567c68cc4f8e6053ef8d767a8cb04dc09a1b54 Mon Sep 17 00:00:00 2001
From: Leo Horie
Date: Mon, 17 Nov 2014 23:03:13 -0500
Subject: [PATCH 5/6] don't break input cursor in chrome
---
mithril.js | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/mithril.js b/mithril.js
index db22d811..19dd41b9 100644
--- a/mithril.js
+++ b/mithril.js
@@ -343,7 +343,8 @@ Mithril = m = new function app(window, undefined) {
//- list and form are typically used as strings, but are DOM element references in js
//- when using CSS selectors (e.g. `m("[style='']")`), style is used as a string, but it's an object in js
else if (attrName in node && !(attrName == "list" || attrName == "style" || attrName == "form")) {
- node[attrName] = dataAttr
+ //#348 don't set the value if not needed otherwise cursor placement breaks in Chrome
+ if (node[attrName] != dataAttr) node[attrName] = dataAttr
}
else node.setAttribute(attrName, dataAttr)
}
@@ -352,7 +353,8 @@ Mithril = m = new function app(window, undefined) {
if (e.message.indexOf("Invalid argument") < 0) throw e
}
}
- else if (attrName === "value" && tag === "input" && node.value !== dataAttr) {
+ //#348 dataAttr may not be a string, so use loose comparison (double equal) instead of strict (triple equal)
+ else if (attrName === "value" && tag === "input" && node.value != dataAttr) {
node.value = dataAttr
}
}
From 1fce18069d3c081ac49ea80077d1c8b44cecf152 Mon Sep 17 00:00:00 2001
From: Leo Horie
Date: Mon, 17 Nov 2014 23:13:26 -0500
Subject: [PATCH 6/6] improve comment clarity
---
mithril.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mithril.js b/mithril.js
index 19dd41b9..7a5d5a93 100644
--- a/mithril.js
+++ b/mithril.js
@@ -88,7 +88,7 @@ Mithril = m = new function app(window, undefined) {
//`configs` is a list of config functions to run after the topmost `build` call finishes running
//there's logic that relies on the assumption that null and undefined data are equivalent to empty strings
- //- this prevents lifecycle surprises from procedural helpers that mix implicit and explicit return statements
+ //- 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
if (data == null) data = "";
if (data.subtree === "retain") return cached;