diff --git a/.eslintignore b/.eslintignore index 43a0cfc9..a6ff032f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -7,7 +7,3 @@ mithril.closure-compiler-externs.js # This is merely a dependency for the documentation. docs/layout/lib - -# TODO: These are temporary, and need to be eventually enabled. -mithril.js -tests diff --git a/bench/app/node_modules/todomvc-common/base.js b/bench/app/node_modules/todomvc-common/base.js index 3c6723f3..112cafa2 100644 --- a/bench/app/node_modules/todomvc-common/base.js +++ b/bench/app/node_modules/todomvc-common/base.js @@ -1,6 +1,6 @@ /* global _ */ (function () { - 'use strict'; + 'use strict' /* jshint ignore:start */ // Underscore's Template Module @@ -8,19 +8,19 @@ var _ = (function (_) { _.defaults = function (object) { if (!object) { - return object; + return object } for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { - var iterable = arguments[argsIndex]; + var iterable = arguments[argsIndex] if (iterable) { for (var key in iterable) { if (object[key] == null) { - object[key] = iterable[key]; + object[key] = iterable[key] } } } } - return object; + return object } // By default, Underscore uses ERB-style template delimiters, change the @@ -29,221 +29,221 @@ evaluate : /<%([\s\S]+?)%>/g, interpolate : /<%=([\s\S]+?)%>/g, escape : /<%-([\s\S]+?)%>/g - }; + } // When customizing `templateSettings`, if you don't want to define an // interpolation, evaluation or escaping regex, we need one that is // guaranteed not to match. - var noMatch = /(.)^/; + var noMatch = /(.)^/ // Certain characters need to be escaped so that they can be put into a // string literal. var escapes = { "'": "'", - '\\': '\\', - '\r': 'r', - '\n': 'n', - '\t': 't', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; + "\\": "\\", + "\r": "r", + "\n": "n", + "\t": "t", + "\u2028": "u2028", + "\u2029": "u2029" + } - var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g // JavaScript micro-templating, similar to John Resig's implementation. // Underscore templating handles arbitrary delimiters, preserves whitespace, // and correctly escapes quotes within interpolated code. - _.template = function(text, data, settings) { - var render; - settings = _.defaults({}, settings, _.templateSettings); + _.template = function (text, data, settings) { + var render + settings = _.defaults({}, settings, _.templateSettings) // Combine delimiters into one regular expression via alternation. var matcher = new RegExp([ (settings.escape || noMatch).source, (settings.interpolate || noMatch).source, (settings.evaluate || noMatch).source - ].join('|') + '|$', 'g'); + ].join("|") + "|$", "g") // Compile the template source, escaping string literals appropriately. - var index = 0; - var source = "__p+='"; - text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + var index = 0 + var source = "__p+='" + text.replace(matcher, function (match, escape, interpolate, evaluate, offset) { source += text.slice(index, offset) - .replace(escaper, function(match) { return '\\' + escapes[match]; }); + .replace(escaper, function (match) { return "\\" + escapes[match] }) if (escape) { - source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'" } if (interpolate) { - source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'" } if (evaluate) { - source += "';\n" + evaluate + "\n__p+='"; + source += "';\n" + evaluate + "\n__p+='" } - index = offset + match.length; - return match; - }); - source += "';\n"; + index = offset + match.length + return match + }) + source += "';\n" // If a variable is not specified, place data values in local scope. - if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + if (!settings.variable) source = "with(obj||{}){\n" + source + '}\n' source = "var __t,__p='',__j=Array.prototype.join," + "print=function(){__p+=__j.call(arguments,'');};\n" + - source + "return __p;\n"; + source + "return __p;\n" try { - render = new Function(settings.variable || 'obj', '_', source); + render = new Function(settings.variable || "obj", "_", source) } catch (e) { - e.source = source; - throw e; + e.source = source + throw e } - if (data) return render(data, _); - var template = function(data) { - return render.call(this, data, _); - }; + if (data) return render(data, _) + var template = function (data) { + return render.call(this, data, _) + } // Provide the compiled function source as a convenience for precompilation. - template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + template.source = "function(" + (settings.variable || "obj") + "){\n" + source + '}' - return template; - }; + return template + } - return _; - })({}); + return _ + })({}) - if (location.hostname === 'todomvc.com') { - (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); - ga('create', 'UA-31081062-1', 'auto'); - ga('send', 'pageview'); + if (location.hostname === "todomvc.com") { + (function (i, s, o, g, r, a, m){ i["GoogleAnalyticsObject"] = r;i[r] = i[r]|| function (){ + (i[r].q = i[r].q || []).push(arguments) }, i[r].l = 1 * new Date();a = s.createElement(o), + m = s.getElementsByTagName(o)[0];a.async = 1;a.src = g;m.parentNode.insertBefore(a, m) + })(window, document,"script","https://www.google-analytics.com/analytics.js","ga") + ga("create", "UA-31081062-1", "auto") + ga("send", "pageview") } /* jshint ignore:end */ function redirect() { - if (location.hostname === 'tastejs.github.io') { - location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); + if (location.hostname === "tastejs.github.io") { + location.href = location.href.replace("tastejs.github.io/todomvc", "todomvc.com") } } function findRoot() { - var base = location.href.indexOf('examples/'); - return location.href.substr(0, base); + var base = location.href.indexOf("examples/") + return location.href.substr(0, base) } function getFile(file, callback) { if (!location.host) { - return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); + return console.info("Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.") } - var xhr = new XMLHttpRequest(); + var xhr = new XMLHttpRequest() - xhr.open('GET', findRoot() + file, true); - xhr.send(); + xhr.open("GET", findRoot() + file, true) + xhr.send() xhr.onload = function () { if (xhr.status === 200 && callback) { - callback(xhr.responseText); + callback(xhr.responseText) } - }; + } } function Learn(learnJSON, config) { if (!(this instanceof Learn)) { - return new Learn(learnJSON, config); + return new Learn(learnJSON, config) } - var template, framework; + var template, framework - if (typeof learnJSON !== 'object') { + if (typeof learnJSON !== "object") { try { - learnJSON = JSON.parse(learnJSON); + learnJSON = JSON.parse(learnJSON) } catch (e) { - return; + return } } if (config) { - template = config.template; - framework = config.framework; + template = config.template + framework = config.framework } if (!template && learnJSON.templates) { - template = learnJSON.templates.todomvc; + template = learnJSON.templates.todomvc } - if (!framework && document.querySelector('[data-framework]')) { - framework = document.querySelector('[data-framework]').dataset.framework; + if (!framework && document.querySelector("[data-framework]")) { + framework = document.querySelector("[data-framework]").dataset.framework } - this.template = template; + this.template = template if (learnJSON.backend) { - this.frameworkJSON = learnJSON.backend; - this.frameworkJSON.issueLabel = framework; + this.frameworkJSON = learnJSON.backend + this.frameworkJSON.issueLabel = framework this.append({ backend: true - }); + }) } else if (learnJSON[framework]) { - this.frameworkJSON = learnJSON[framework]; - this.frameworkJSON.issueLabel = framework; - this.append(); + this.frameworkJSON = learnJSON[framework] + this.frameworkJSON.issueLabel = framework + this.append() } - this.fetchIssueCount(); + this.fetchIssueCount() } Learn.prototype.append = function (opts) { - var aside = document.createElement('aside'); - aside.innerHTML = _.template(this.template, this.frameworkJSON); - aside.className = 'learn'; + var aside = document.createElement("aside") + aside.innerHTML = _.template(this.template, this.frameworkJSON) + aside.className = 'learn' if (opts && opts.backend) { // Remove demo link - var sourceLinks = aside.querySelector('.source-links'); - var heading = sourceLinks.firstElementChild; - var sourceLink = sourceLinks.lastElementChild; + var sourceLinks = aside.querySelector(".source-links") + var heading = sourceLinks.firstElementChild + var sourceLink = sourceLinks.lastElementChild // Correct link path - var href = sourceLink.getAttribute('href'); - sourceLink.setAttribute('href', href.substr(href.lastIndexOf('http'))); - sourceLinks.innerHTML = heading.outerHTML + sourceLink.outerHTML; + var href = sourceLink.getAttribute("href") + sourceLink.setAttribute("href", href.substr(href.lastIndexOf("http"))) + sourceLinks.innerHTML = heading.outerHTML + sourceLink.outerHTML } else { // Localize demo links - var demoLinks = aside.querySelectorAll('.demo-link'); + var demoLinks = aside.querySelectorAll(".demo-link") Array.prototype.forEach.call(demoLinks, function (demoLink) { - if (demoLink.getAttribute('href').substr(0, 4) !== 'http') { - demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + if (demoLink.getAttribute("href").substr(0, 4) !== "http") { + demoLink.setAttribute("href", findRoot() + demoLink.getAttribute("href")) } - }); + }) } - document.body.className = (document.body.className + ' learn-bar').trim(); - document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); - }; + document.body.className = (document.body.className + " learn-bar").trim() + document.body.insertAdjacentHTML("afterBegin", aside.outerHTML) + } Learn.prototype.fetchIssueCount = function () { - var issueLink = document.getElementById('issue-count-link'); + var issueLink = document.getElementById("issue-count-link") if (issueLink) { - var url = issueLink.href.replace('https://github.com', 'https://api.github.com/repos'); - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); + var url = issueLink.href.replace("https://github.com", "https://api.github.com/repos") + var xhr = new XMLHttpRequest() + xhr.open("GET", url, true) xhr.onload = function (e) { - var parsedResponse = JSON.parse(e.target.responseText); + var parsedResponse = JSON.parse(e.target.responseText) if (parsedResponse instanceof Array) { - var count = parsedResponse.length; + var count = parsedResponse.length if (count !== 0) { - issueLink.innerHTML = 'This app has ' + count + ' open issues'; - document.getElementById('issue-count').style.display = 'inline'; + issueLink.innerHTML = "This app has " + count + ' open issues' + document.getElementById("issue-count").style.display = 'inline' } } - }; - xhr.send(); + } + xhr.send() } - }; + } - redirect(); - getFile('learn.json', Learn); -})(); + redirect() + getFile("learn.json", Learn) +})() diff --git a/mithril.js b/mithril.js index 5ac1ca34..10258b46 100644 --- a/mithril.js +++ b/mithril.js @@ -1,39 +1,65 @@ -var m = (function app(window, undefined) { - "use strict"; - var VERSION = "v0.2.2-rc.1"; +;(function (global, factory) { // eslint-disable-line + "use strict" + /* eslint-disable no-undef */ + var m = factory(global) + if (typeof module === "object" && module != null && module.exports) { + module.exports = m + } else if (typeof define === "function" && define.amd) { + define(function () { return m }) + } else { + global.m = m + } + /* eslint-enable no-undef */ +})(typeof window !== "undefined" ? window : {}, function (global, undefined) { // eslint-disable-line + "use strict" + + m.version = function () { + return "v0.2.2-rc.1" + } + + var hasOwn = {}.hasOwnProperty + var type = {}.toString + function isFunction(object) { - return typeof object === "function"; + return typeof object === "function" } + function isObject(object) { - return type.call(object) === "[object Object]"; + return type.call(object) === "[object Object]" } + function isString(object) { - return type.call(object) === "[object String]"; + return type.call(object) === "[object String]" } + var isArray = Array.isArray || function (object) { - return type.call(object) === "[object Array]"; - }; - 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 () {}; + return type.call(object) === "[object Array]" + } + + function noop() {} + + /* eslint-disable max-len */ + var voidElements = /^(AREA|BASE|BR|COL|COMMAND|EMBED|HR|IMG|INPUT|KEYGEN|LINK|META|PARAM|SOURCE|TRACK|WBR)$/ + /* eslint-enable max-len */ // caching commonly used variables - var $document, $location, $requestAnimationFrame, $cancelAnimationFrame; + var $document, $location, $requestAnimationFrame, $cancelAnimationFrame // self invoking function needed because of the way mocks work - function initialize(window) { - $document = window.document; - $location = window.location; - $cancelAnimationFrame = window.cancelAnimationFrame || window.clearTimeout; - $requestAnimationFrame = window.requestAnimationFrame || window.setTimeout; + function initialize(mock) { + $document = mock.document + $location = mock.location + $cancelAnimationFrame = mock.cancelAnimationFrame || mock.clearTimeout + $requestAnimationFrame = mock.requestAnimationFrame || mock.setTimeout } - initialize(window); + // testing API + m.deps = function (mock) { + initialize(global = mock || window) + return global + } - m.version = function() { - return VERSION; - }; + m.deps(global) /** * @typedef {String} Tag @@ -41,98 +67,148 @@ var m = (function app(window, undefined) { * Which describes a DOM node */ + function parseTagAttrs(cell, tag) { + var classes = [] + var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g + var match + + while ((match = parser.exec(tag))) { + 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 = /\[(.+?)(?:=("|'|)(.*?)\2)?\]/.exec(match[3]) + cell.attrs[pair[1]] = pair[3] || (pair[2] ? "" : true) + } + } + + return classes + } + + function getVirtualChildren(args, hasAttrs) { + var children = hasAttrs ? args.slice(1) : args + + if (children.length === 1 && isArray(children[0])) { + return children[0] + } else { + return children + } + } + + function assignAttrs(target, attrs, classes) { + var classAttr = "class" in attrs ? "class" : "className" + + for (var attrName in attrs) { + if (hasOwn.call(attrs, attrName)) { + if (attrName === classAttr && + attrs[attrName] != null && + attrs[attrName] !== "") { + classes.push(attrs[attrName]) + // create key in correct iteration order + target[attrName] = "" + } else { + target[attrName] = attrs[attrName] + } + } + } + + if (classes.length) target[classAttr] = classes.join(" ") + } + /** * * @param {Tag} The DOM node tag * @param {Object=[]} optional key-value pairs to be mapped to DOM attrs - * @param {...mNode=[]} Zero or more Mithril child nodes. Can be an array, or splat (optional) - * + * @param {...mNode=[]} Zero or more Mithril child nodes. Can be an array, + * or splat (optional) */ function m(tag, pairs) { for (var args = [], i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - if (isObject(tag)) return parameterize(tag, args); - var hasAttrs = pairs != null && isObject(pairs) && !("tag" in pairs || "view" in pairs || "subtree" in pairs); - var attrs = hasAttrs ? pairs : {}; - var classAttrName = "class" in attrs ? "class" : "className"; - var cell = {tag: "div", attrs: {}}; - var match, classes = []; - if (!isString(tag)) throw new Error("selector in m(selector, attrs, children) should be a string"); - while ((match = parser.exec(tag)) != null) { - 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); - } + args[i - 1] = arguments[i] } - var children = hasAttrs ? args.slice(1) : args; - if (children.length === 1 && isArray(children[0])) { - cell.children = children[0]; - } - else { - cell.children = children; + if (isObject(tag)) return parameterize(tag, args) + + if (!isString(tag)) { + throw new Error("selector in m(selector, attrs, children) should " + + "be a string") } - 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 - } - else cell.attrs[attrName] = attrs[attrName]; - } - } - if (classes.length) cell.attrs[classAttrName] = classes.join(" "); + var hasAttrs = pairs != null && isObject(pairs) && + !("tag" in pairs || "view" in pairs || "subtree" in pairs) - return cell; + var attrs = hasAttrs ? pairs : {} + var cell = { + tag: "div", + attrs: {}, + children: getVirtualChildren(args, hasAttrs) + } + + assignAttrs(cell.attrs, attrs, parseTagAttrs(cell, tag)) + return cell } + function forEach(list, f) { - for (var i = 0; i < list.length && !f(list[i], i++);) {} + for (var i = 0; i < list.length && !f(list[i], i++);) { + // function called in condition + } } + function forKeys(list, f) { forEach(list, function (attrs, i) { - return (attrs = attrs && attrs.attrs) && attrs.key != null && f(attrs, i); - }); + return (attrs = attrs && attrs.attrs) && + attrs.key != null && + f(attrs, i) + }) } // This function was causing deopts in Chrome. function dataToString(data) { - //data.toString() might throw or return null if data is the return value of Console.log in Firefox (behavior depends on version) + // data.toString() might throw or return null if data is the return + // value of Console.log in some versions of Firefox (behavior depends on + // version) try { - if (data == null || data.toString() == null) return ""; + if (data != null && data.toString() != null) return data } catch (e) { - return ""; + // silently ignore errors } - return data; + return "" } + // This function was causing deopts in Chrome. function injectTextNode(parentElement, first, index, data) { try { - insertNode(parentElement, first, index); - first.nodeValue = data; - } catch (e) {} //IE erroneously throws error when appending an empty text node after a null + insertNode(parentElement, first, index) + first.nodeValue = data + } catch (e) { + // IE erroneously throws error when appending an empty text node + // after a null + } } function flatten(list) { - //recursively flatten array + // recursively flatten array for (var i = 0; i < list.length; i++) { if (isArray(list[i])) { - list = list.concat.apply([], list); - //check current index again and flatten until there are no more nested arrays at that index - i--; + list = list.concat.apply([], list) + // check current index again and flatten until there are no more + // nested arrays at that index + i-- } } - return list; + return list } function insertNode(parentElement, node, index) { - parentElement.insertBefore(node, parentElement.childNodes[index] || null); + parentElement.insertBefore(node, + parentElement.childNodes[index] || null) } - var DELETION = 1, INSERTION = 2, MOVE = 3; + var DELETION = 1 + var INSERTION = 2 + var MOVE = 3 function handleKeysDiffer(data, existing, cached, parentElement) { forKeys(data, function (key, i) { @@ -140,93 +216,142 @@ var m = (function app(window, undefined) { action: MOVE, index: i, from: existing[key].index, - element: cached.nodes[existing[key].index] || $document.createElement("div") - } : {action: INSERTION, index: i}; - }); - var actions = []; - for (var prop in existing) actions.push(existing[prop]); - var changes = actions.sort(sortChanges), newCached = new Array(cached.length); - newCached.nodes = cached.nodes.slice(); + element: cached.nodes[existing[key].index] || + $document.createElement("div") + } : {action: INSERTION, index: i} + }) + + var actions = [] + for (var prop in existing) if (hasOwn.call(existing, prop)) { + actions.push(existing[prop]) + } + + var changes = actions.sort(sortChanges) + var newCached = new Array(cached.length) + + newCached.nodes = cached.nodes.slice() forEach(changes, function (change) { - var index = change.index; + var index = change.index if (change.action === DELETION) { - clear(cached[index].nodes, cached[index]); - newCached.splice(index, 1); + clear(cached[index].nodes, cached[index]) + newCached.splice(index, 1) } if (change.action === INSERTION) { - var dummy = $document.createElement("div"); - dummy.key = data[index].attrs.key; - insertNode(parentElement, dummy, index); + var dummy = $document.createElement("div") + dummy.key = data[index].attrs.key + insertNode(parentElement, dummy, index) newCached.splice(index, 0, { attrs: {key: data[index].attrs.key}, nodes: [dummy] - }); - newCached.nodes[index] = dummy; + }) + newCached.nodes[index] = dummy } if (change.action === MOVE) { - var changeElement = change.element; - var maybeChanged = parentElement.childNodes[index]; + var changeElement = change.element + var maybeChanged = parentElement.childNodes[index] if (maybeChanged !== changeElement && changeElement !== null) { - parentElement.insertBefore(changeElement, maybeChanged || null); + parentElement.insertBefore(changeElement, + maybeChanged || null) } - newCached[index] = cached[change.from]; - newCached.nodes[index] = changeElement; + newCached[index] = cached[change.from] + newCached.nodes[index] = changeElement } - }); + }) - return newCached; + return newCached } function diffKeys(data, cached, existing, parentElement) { - var keysDiffer = data.length !== cached.length; + var keysDiffer = data.length !== cached.length + if (!keysDiffer) { forKeys(data, function (attrs, i) { - var cachedCell = cached[i]; - return keysDiffer = cachedCell && cachedCell.attrs && cachedCell.attrs.key !== attrs.key; - }); + var cachedCell = cached[i] + return keysDiffer = cachedCell && + cachedCell.attrs && + cachedCell.attrs.key !== attrs.key + }) } - return keysDiffer ? handleKeysDiffer(data, existing, cached, parentElement) : cached; + if (keysDiffer) { + return handleKeysDiffer(data, existing, cached, parentElement) + } else { + return cached + } } function diffArray(data, cached, nodes) { - //diff the array itself + // diff the array itself - //update the list of DOM nodes by collecting the nodes from each item + // update the list of DOM nodes by collecting the nodes from each item forEach(data, function (_, 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 + // 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 forEach(cached.nodes, function (node, 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; + + if (data.length < cached.length) cached.length = data.length + cached.nodes = nodes } function buildArrayKeys(data) { - var guid = 0; + var guid = 0 forKeys(data, function () { forEach(data, function (attrs) { - if ((attrs = attrs && attrs.attrs) && attrs.key == null) attrs.key = "__mithril__" + guid++; + if ((attrs = attrs && attrs.attrs) && attrs.key == null) { + attrs.key = "__mithril__" + guid++ + } }) - return 1; - }); + return 1 + }) + } + + function isDifferentEnough(data, cached, dataAttrKeys) { + if (data.tag !== cached.tag) return true + + if (dataAttrKeys.sort().join() !== + Object.keys(cached.attrs).sort().join()) { + return true + } + + if (data.attrs.id !== cached.attrs.id) { + return true + } + + if (data.attrs.key !== cached.attrs.key) { + return true + } + + if (m.redraw.strategy() === "all") { + return !cached.configContext || cached.configContext.retain !== true + } + + if (m.redraw.strategy() === "diff") { + return cached.configContext && cached.configContext.retain === false + } + + return false } function maybeRecreateObject(data, cached, dataAttrKeys) { - //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 && isFunction(cached.configContext.onunload)) cached.configContext.onunload(); + // if an element is different enough from the one in cache, recreate it + if (isDifferentEnough(data, cached, dataAttrKeys)) { + if (cached.nodes.length) clear(cached.nodes) + + if (cached.configContext && + isFunction(cached.configContext.onunload)) { + cached.configContext.onunload() + } + if (cached.controllers) { forEach(cached.controllers, function (controller) { if (controller.onunload) controller.onunload({preventDefault: noop}); @@ -236,71 +361,129 @@ var m = (function app(window, undefined) { } function getObjectNamespace(data, namespace) { - return data.attrs.xmlns ? data.attrs.xmlns : - data.tag === "svg" ? "http://www.w3.org/2000/svg" : - data.tag === "math" ? "http://www.w3.org/1998/Math/MathML" : - namespace; + if (data.attrs.xmlns) return data.attrs.xmlns + if (data.tag === "svg") return "http://www.w3.org/2000/svg" + if (data.tag === "math") return "http://www.w3.org/1998/Math/MathML" + return namespace + } + + var pendingRequests = 0 + m.startComputation = function () { pendingRequests++ } + m.endComputation = function () { + if (pendingRequests > 1) { + pendingRequests-- + } else { + pendingRequests = 0 + m.redraw() + } } function unloadCachedControllers(cached, views, controllers) { if (controllers.length) { - cached.views = views; - cached.controllers = controllers; + cached.views = views + cached.controllers = controllers forEach(controllers, function (controller) { - 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; + 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 + } + }) } } function scheduleConfigsToBeCalled(configs, data, node, isNew, cached) { - //schedule configs to be called. They are called after `build` - //finishes running + // schedule configs to be called. They are called after `build` finishes + // running if (isFunction(data.attrs.config)) { - var context = cached.configContext = cached.configContext || {}; + var context = cached.configContext = cached.configContext || {} - //bind - configs.push(function() { - return data.attrs.config.call(data, node, !isNew, context, cached); - }); + // bind + configs.push(function () { + return data.attrs.config.call(data, node, !isNew, context, + cached) + }) } } - function buildUpdatedNode(cached, data, editable, hasKeys, namespace, views, configs, controllers) { - var node = cached.nodes[0]; - if (hasKeys) setAttributes(node, data.tag, data.attrs, cached.attrs, namespace); - cached.children = build(node, data.tag, undefined, undefined, data.children, cached.children, false, 0, data.attrs.contenteditable ? node : editable, namespace, configs); - cached.nodes.intact = true; + function buildUpdatedNode( + cached, + data, + editable, + hasKeys, + namespace, + views, + configs, + controllers + ) { + var node = cached.nodes[0] - if (controllers.length) { - cached.views = views; - cached.controllers = controllers; + if (hasKeys) { + setAttributes(node, data.tag, data.attrs, cached.attrs, namespace) } - return node; + cached.children = build( + node, + data.tag, + undefined, + undefined, + data.children, + cached.children, + false, + 0, + data.attrs.contenteditable ? node : editable, + namespace, + configs + ) + + cached.nodes.intact = true + + if (controllers.length) { + cached.views = views + cached.controllers = controllers + } + + return node } function handleNonexistentNodes(data, parentElement, index) { - var nodes; + var nodes if (data.$trusted) { - nodes = injectHTML(parentElement, index, data); - } - else { - nodes = [$document.createTextNode(data)]; - if (!parentElement.nodeName.match(voidElements)) insertNode(parentElement, nodes[0], index); + nodes = injectHTML(parentElement, index, data) + } else { + nodes = [$document.createTextNode(data)] + if (!parentElement.nodeName.match(voidElements)) { + insertNode(parentElement, nodes[0], index) + } } - var cached = typeof data === "string" || typeof data === "number" || typeof data === "boolean" ? new data.constructor(data) : data; - cached.nodes = nodes; - return cached; + var cached + + if (typeof data === "string" || + typeof data === "number" || + typeof data === "boolean") { + cached = new data.constructor(data) + } else { + cached = data + } + + cached.nodes = nodes + return cached } - function reattachNodes(data, cached, parentElement, editable, index, parentTag) { - var nodes = cached.nodes; + function reattachNodes( + data, + cached, + parentElement, + editable, + index, + parentTag + ) { + var nodes = cached.nodes if (!editable || editable !== $document.activeElement) { if (data.$trusted) { clear(nodes, cached) @@ -313,864 +496,1371 @@ var m = (function app(window, undefined) { editable.innerHTML = data } else { // was a trusted string - if (nodes[0].nodeType === 1 || nodes.length > 1 || (nodes[0].nodeValue.trim && !nodes[0].nodeValue.trim())) { + if (nodes[0].nodeType === 1 || nodes.length > 1 || + (nodes[0].nodeValue.trim && + !nodes[0].nodeValue.trim())) { clear(cached.nodes, cached) nodes = [$document.createTextNode(data)] } - injectTextNode(parentElement, nodes[0], index, data); + + injectTextNode(parentElement, nodes[0], index, data) } } - cached = new data.constructor(data); - cached.nodes = nodes; - return cached; + cached = new data.constructor(data) + cached.nodes = nodes + return cached } - function handleText(cached, data, index, parentElement, shouldReattach, editable, parentTag) { - //handle text nodes - return cached.nodes.length === 0 ? handleNonexistentNodes(data, parentElement, index) : - cached.valueOf() !== data.valueOf() || shouldReattach === true ? - reattachNodes(data, cached, parentElement, editable, index, parentTag) : - (cached.nodes.intact = true, cached); + function handleTextNode( + cached, + data, + index, + parentElement, + shouldReattach, + editable, + parentTag + ) { + if (!cached.nodes.length) { + return handleNonexistentNodes(data, parentElement, index) + } else if (cached.valueOf() !== data.valueOf() || shouldReattach) { + return reattachNodes(data, cached, parentElement, editable, index, + parentTag) + } else { + return (cached.nodes.intact = true, cached) + } } function getSubArrayCount(item) { if (item.$trusted) { - //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 - var match = item.match(/<[^\/]|\>\s*[^<]/g); - if (match != null) return match.length; + // 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 + var match = item.match(/<[^\/]|\>\s*[^<]/g) + if (match != null) return match.length + } else if (isArray(item)) { + return item.length } - else if (isArray(item)) { - return item.length; - } - return 1; + return 1 } - function buildArray(data, cached, parentElement, index, parentTag, shouldReattach, editable, namespace, configs) { - data = flatten(data); - var nodes = [], intact = cached.length === data.length, subArrayCount = 0; + function buildArray( + data, + cached, + parentElement, + index, + parentTag, + shouldReattach, + editable, + namespace, + configs + ) { + data = flatten(data) + var nodes = [] + var intact = cached.length === data.length + var subArrayCount = 0 + + // keys algorithm: sort elements without recreating them if keys are + // present + // + // 1) create a map of all existing keys, and mark all for deletion + // 2) add new keys to map and mark them for addition + // 3) if key exists in new list, change action from deletion to a move + // 4) for each key, handle its corresponding action as marked in + // previous steps + + var existing = {} + var shouldMaintainIdentities = false - //keys algorithm: sort elements without recreating them if keys are present - //1) create a map of all existing keys, and mark all for deletion - //2) add new keys to map and mark them for addition - //3) if key exists in new list, change action from deletion to a move - //4) for each key, handle its corresponding action as marked in previous steps - var existing = {}, shouldMaintainIdentities = false; forKeys(cached, function (attrs, i) { - shouldMaintainIdentities = true; - existing[cached[i].attrs.key] = {action: DELETION, index: i}; - }); + shouldMaintainIdentities = true + existing[cached[i].attrs.key] = {action: DELETION, index: i} + }) - buildArrayKeys(data); - if (shouldMaintainIdentities) cached = diffKeys(data, cached, existing, parentElement); - //end key algorithm + buildArrayKeys(data) + if (shouldMaintainIdentities) { + cached = diffKeys(data, cached, existing, parentElement) + } + // end key algorithm - var cacheCount = 0; - //faster explicitly written + var cacheCount = 0 + // faster explicitly written for (var i = 0, len = data.length; i < len; i++) { - //diff each item in the array - var item = build(parentElement, parentTag, cached, index, data[i], cached[cacheCount], shouldReattach, index + subArrayCount || subArrayCount, editable, namespace, configs); + // diff each item in the array + var item = build( + parentElement, + parentTag, + cached, + index, + data[i], + cached[cacheCount], + shouldReattach, + index + subArrayCount || subArrayCount, + editable, + namespace, + configs) if (item !== undefined) { - intact = intact && item.nodes.intact; - subArrayCount += getSubArrayCount(item); - cached[cacheCount++] = item; + intact = intact && item.nodes.intact + subArrayCount += getSubArrayCount(item) + cached[cacheCount++] = item } } - if (!intact) diffArray(data, cached, nodes); + if (!intact) diffArray(data, cached, nodes) return cached } function makeCache(data, cached, index, parentIndex, parentCache) { if (cached != null) { - if (type.call(cached) === type.call(data)) return cached; + if (type.call(cached) === type.call(data)) return cached if (parentCache && parentCache.nodes) { - var offset = index - parentIndex, end = offset + (isArray(data) ? data : cached.nodes).length; - clear(parentCache.nodes.slice(offset, end), parentCache.slice(offset, end)); + var offset = index - parentIndex + var end = offset + (isArray(data) ? data : cached.nodes).length + clear( + parentCache.nodes.slice(offset, end), + parentCache.slice(offset, end)) } else if (cached.nodes) { - clear(cached.nodes, cached); + clear(cached.nodes, cached) } } - cached = new data.constructor(); - //if constructor creates a virtual dom element, use a blank object - //as the base cached node instead of copying the virtual el (#277) - if (cached.tag) cached = {}; - cached.nodes = []; - return cached; + cached = new data.constructor() + // if constructor creates a virtual dom element, use a blank object as + // the base cached node instead of copying the virtual el (#277) + if (cached.tag) cached = {} + cached.nodes = [] + return cached } function constructNode(data, namespace) { - return namespace === undefined ? - data.attrs.is ? $document.createElement(data.tag, data.attrs.is) : $document.createElement(data.tag) : - data.attrs.is ? $document.createElementNS(namespace, data.tag, data.attrs.is) : $document.createElementNS(namespace, data.tag); + if (data.attrs.is) { + if (namespace == null) { + return $document.createElement(data.tag, data.attrs.is) + } else { + return $document.createElementNS(namespace, data.tag, + data.attrs.is) + } + } else if (namespace == null) { + return $document.createElement(data.tag, data.attrs.is) + } else { + return $document.createElementNS(namespace, data.tag, + data.attrs.is) + } } function constructAttrs(data, node, namespace, hasKeys) { - return hasKeys ? setAttributes(node, data.tag, data.attrs, {}, namespace) : data.attrs; + if (hasKeys) { + return setAttributes(node, data.tag, data.attrs, {}, namespace) + } else { + return data.attrs + } } - function constructChildren(data, node, cached, editable, namespace, configs) { - return data.children != null && data.children.length > 0 ? - build(node, data.tag, undefined, undefined, data.children, cached.children, true, 0, data.attrs.contenteditable ? node : editable, namespace, configs) : - data.children; + function constructChildren( + data, + node, + cached, + editable, + namespace, + configs + ) { + if (data.children != null && data.children.length > 0) { + return build( + node, + data.tag, + undefined, + undefined, + data.children, + cached.children, + true, + 0, + data.attrs.contenteditable ? node : editable, + namespace, + configs) + } else { + return data.children + } } - function reconstructCached(data, attrs, children, node, namespace, views, controllers) { - var cached = {tag: data.tag, attrs: attrs, children: children, nodes: [node]}; - unloadCachedControllers(cached, views, controllers); - if (cached.children && !cached.children.nodes) cached.children.nodes = []; - //edge case: setting value on doesn't work before children + // exist, so set it again after children have been created + if (data.tag === "select" && "value" in data.attrs) { + setAttributes(node, data.tag, {value: data.attrs.value}, {}, + namespace) + } + return cached } function getController(views, view, cachedControllers, controller) { - var controllerIndex = m.redraw.strategy() === "diff" && views ? views.indexOf(view) : -1; - return controllerIndex > -1 ? cachedControllers[controllerIndex] : - typeof controller === "function" ? new controller() : {}; + var controllerIndex + + if (m.redraw.strategy() === "diff" && views) { + controllerIndex = views.indexOf(view) + } else { + controllerIndex = -1 + } + + if (controllerIndex > -1) { + return cachedControllers[controllerIndex] + } else if (isFunction(controller)) { + return new controller() + } else { + return {} + } } + var unloaders = [] + function updateLists(views, controllers, view, controller) { - if (controller.onunload != null) unloaders.push({controller: controller, handler: controller.onunload}); - views.push(view); - controllers.push(controller); + if (controller.onunload != null) { + unloaders.push({ + controller: controller, + handler: controller.onunload + }) + } + + views.push(view) + controllers.push(controller) } + var forcing = false function checkView(data, view, cached, cachedControllers, controllers, views) { - var controller = getController(cached.views, view, cachedControllers, data.controller); - var key = data && data.attrs && data.attrs.key; - data = pendingRequests === 0 || forcing || cachedControllers && cachedControllers.indexOf(controller) > -1 ? data.view(controller) : {tag: "placeholder"}; + var controller = getController(cached.views, view, cachedControllers, data.controller) + var key = data && data.attrs && data.attrs.key + data = pendingRequests === 0 || forcing || cachedControllers && cachedControllers.indexOf(controller) > -1 ? data.view(controller) : {tag: "placeholder"} if (data.subtree === "retain") return data; - (data.attrs = data.attrs || {}).key = key; - updateLists(views, controllers, view, controller); - return data; + data.attrs = data.attrs || {} + data.attrs.key = key + updateLists(views, controllers, view, controller) + return data } function markViews(data, cached, views, controllers) { - var cachedControllers = cached && cached.controllers; - while (data.view != null) data = checkView(data, data.view.$original || data.view, cached, cachedControllers, controllers, views); - return data; + var cachedControllers = cached && cached.controllers + + while (data.view != null) { + data = checkView( + data, + data.view.$original || data.view, + cached, + cachedControllers, + controllers, + views) + } + + return data } - function buildObject(data, cached, editable, parentElement, index, shouldReattach, namespace, configs) { - var views = [], controllers = []; - data = markViews(data, cached, views, controllers); - if (data.subtree === "retain") return cached; - if (!data.tag && controllers.length) throw new Error("Component template must return a virtual element, not an array, string, etc."); - data.attrs = data.attrs || {}; - cached.attrs = cached.attrs || {}; - var dataAttrKeys = Object.keys(data.attrs); - var hasKeys = dataAttrKeys.length > ("key" in data.attrs ? 1 : 0); - maybeRecreateObject(data, cached, dataAttrKeys); - if (!isString(data.tag)) return; - var isNew = cached.nodes.length === 0; - namespace = getObjectNamespace(data, namespace); - var node; + function buildObject( // eslint-disable-line max-statements + data, + cached, + editable, + parentElement, + index, + shouldReattach, + namespace, + configs + ) { + var views = [] + var controllers = [] + + data = markViews(data, cached, views, controllers) + + if (data.subtree === "retain") return cached + + if (!data.tag && controllers.length) { + throw new Error("Component template must return a virtual " + + "element, not an array, string, etc.") + } + + data.attrs = data.attrs || {} + cached.attrs = cached.attrs || {} + + var dataAttrKeys = Object.keys(data.attrs) + var hasKeys = dataAttrKeys.length > ("key" in data.attrs ? 1 : 0) + + maybeRecreateObject(data, cached, dataAttrKeys) + + if (!isString(data.tag)) return + + var isNew = cached.nodes.length === 0 + + namespace = getObjectNamespace(data, namespace) + + var node if (isNew) { - node = constructNode(data, namespace); - //set attributes first, then create children + node = constructNode(data, namespace) + // set attributes first, then create children var attrs = constructAttrs(data, node, namespace, hasKeys) - var children = constructChildren(data, node, cached, editable, namespace, configs); - cached = reconstructCached(data, attrs, children, node, namespace, views, controllers); + + var children = constructChildren(data, node, cached, editable, + namespace, configs) + + cached = reconstructCached( + data, + attrs, + children, + node, + namespace, + views, + controllers) + } else { + node = buildUpdatedNode( + cached, + data, + editable, + hasKeys, + namespace, + views, + configs, + controllers) } - else { - node = buildUpdatedNode(cached, data, editable, hasKeys, namespace, views, configs, controllers); + + if (isNew || shouldReattach === true && node != null) { + insertNode(parentElement, node, index) } - if (isNew || shouldReattach === true && node != null) insertNode(parentElement, node, index); - //schedule configs to be called. They are called after `build` - //finishes running - scheduleConfigsToBeCalled(configs, data, node, isNew, cached); + + // The configs are called after `build` finishes running + scheduleConfigsToBeCalled(configs, data, node, isNew, cached) + return cached } - 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` - //the diff algorithm can be summarized as this: - //1 - compare `data` and `cached` - //2 - if they are different, copy `data` to `cached` and update the DOM - // based on what the difference is - //3 - recursively apply this algorithm for every array and for the - // children of every virtual element + 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` the + * diff algorithm can be summarized as this: + * + * 1 - compare `data` and `cached` + * 2 - if they are different, copy `data` to `cached` and update the DOM + * based on what the difference is + * 3 - recursively apply this algorithm for every array and for the + * children of every virtual element + * + * The `cached` data structure is essentially the same as the previous + * redraw's `data` data structure, with a few additions: + * - `cached` always has a property called `nodes`, which is a list of + * DOM elements that correspond to the data represented by the + * respective virtual element + * - in order to support attaching `nodes` as a property of `cached`, + * `cached` is *always* a non-primitive object, i.e. if the data was + * a string, then cached is a String instance. If data was `null` or + * `undefined`, cached is `new String("")` + * - `cached also has a `configContext` property, which is the state + * storage object exposed by config(element, isInitialized, context) + * - when `cached` is an Object, it represents a virtual element; when + * it's an Array, it represents a list of elements; when it's a + * String, Number or Boolean, it represents a text node + * + * `parentElement` is a DOM element used for W3C DOM API calls + * `parentTag` is only used for handling a corner case for textarea + * values + * `parentCache` is used to remove nodes in some multi-node cases + * `parentIndex` and `index` are used to figure out the offset of nodes. + * They're artifacts from before arrays started being flattened and are + * likely refactorable + * `data` and `cached` are, respectively, the new and old nodes being + * diffed + * `shouldReattach` is a flag indicating whether a parent node was + * recreated (if so, and if this node is reused, then this node must + * reattach itself to the new parent) + * `editable` is a flag that indicates whether an ancestor is + * contenteditable + * `namespace` indicates the closest HTML namespace as it cascades down + * from an ancestor + * `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 (e.g. + * function foo() {if (cond) return m("div")} + * - it simplifies diffing code + */ + data = dataToString(data) + if (data.subtree === "retain") return cached + cached = makeCache(data, cached, index, parentIndex, parentCache) - //the `cached` data structure is essentially the same as the previous - //redraw's `data` data structure, with a few additions: - //- `cached` always has a property called `nodes`, which is a list of - // DOM elements that correspond to the data represented by the - // respective virtual element - //- in order to support attaching `nodes` as a property of `cached`, - // `cached` is *always* a non-primitive object, i.e. if the data was - // a string, then cached is a String instance. If data was `null` or - // `undefined`, cached is `new String("")` - //- `cached also has a `configContext` property, which is the state - // storage object exposed by config(element, isInitialized, context) - //- when `cached` is an Object, it represents a virtual element; when - // it's an Array, it represents a list of elements; when it's a - // String, Number or Boolean, it represents a text node - - //`parentElement` is a DOM element used for W3C DOM API calls - //`parentTag` is only used for handling a corner case for textarea - //values - //`parentCache` is used to remove nodes in some multi-node cases - //`parentIndex` and `index` are used to figure out the offset of nodes. - //They're artifacts from before arrays started being flattened and are - //likely refactorable - //`data` and `cached` are, respectively, the new and old nodes being - //diffed - //`shouldReattach` is a flag indicating whether a parent node was - //recreated (if so, and if this node is reused, then this node must - //reattach itself to the new parent) - //`editable` is a flag that indicates whether an ancestor is - //contenteditable - //`namespace` indicates the closest HTML namespace as it cascades down - //from an ancestor - //`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 (e.g. - // function foo() {if (cond) return m("div")} - //- it simplifies diffing code - data = dataToString(data); - if (data.subtree === "retain") return cached; - cached = makeCache(data, cached, index, parentIndex, parentCache); - return isArray(data) ? buildArray(data, cached, parentElement, index, parentTag, shouldReattach, editable, namespace, configs) : - data != null && isObject(data) ? buildObject(data, cached, editable, parentElement, index, shouldReattach, namespace, configs) : - !isFunction(data) ? handleText(cached, data, index, parentElement, shouldReattach, editable, parentTag) : - cached; + if (isArray(data)) { + return buildArray( + data, + cached, + parentElement, + index, + parentTag, + shouldReattach, + editable, + namespace, + configs) + } else if (data != null && isObject(data)) { + return buildObject( + data, + cached, + editable, + parentElement, + index, + shouldReattach, + namespace, + configs) + } else if (!isFunction(data)) { + return handleTextNode( + cached, + data, + index, + parentElement, + shouldReattach, + editable, + parentTag) + } else { + return cached + } } - function sortChanges(a, b) { return a.action - b.action || a.index - b.index; } - function setAttributes(node, tag, dataAttrs, cachedAttrs, namespace) { - for (var attrName in dataAttrs) { - var dataAttr = dataAttrs[attrName]; - var cachedAttr = cachedAttrs[attrName]; - if (!(attrName in cachedAttrs) || (cachedAttr !== dataAttr)) { - cachedAttrs[attrName] = dataAttr; - try { - //`config` isn't a real attribute, so ignore it - if (attrName === "config" || attrName === "key") continue; - //hook event handlers to the auto-redrawing system - else if (isFunction(dataAttr) && attrName.slice(0, 2) === "on") { - node[attrName] = autoredraw(dataAttr, node); - } - //handle `style: {...}` - else if (attrName === "style" && dataAttr != null && isObject(dataAttr)) { - for (var rule in dataAttr) { - if (cachedAttr == null || cachedAttr[rule] !== dataAttr[rule]) node.style[rule] = dataAttr[rule]; - } - for (var rule in cachedAttr) { - if (!(rule in dataAttr)) node.style[rule] = ""; - } - } - //handle SVG - else if (namespace != null) { - if (attrName === "href") node.setAttributeNS("http://www.w3.org/1999/xlink", "href", dataAttr); - else node.setAttribute(attrName === "className" ? "class" : attrName, dataAttr); - } - //handle cases that are properties (but ignore cases where we should use setAttribute instead) - //- 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" && attrName !== "type" && attrName !== "width" && attrName !== "height") { - //#348 don't set the value if not needed otherwise cursor placement breaks in Chrome - try { - if (tag !== "input" || node[attrName] !== dataAttr) node[attrName] = dataAttr; - } catch (e) { - node.setAttribute(attrName, dataAttr); - } - } - else node.setAttribute(attrName, dataAttr); - } - catch (e) { - //swallow IE's invalid argument errors to mimic HTML's fallback-to-doing-nothing-on-invalid-attributes behavior - if (e.message.indexOf("Invalid argument") < 0) throw e; - } - } - //#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; + + function sortChanges(a, b) { + return a.action - b.action || a.index - b.index + } + + function copyStyleAttrs(node, dataAttr, cachedAttr) { + for (var rule in dataAttr) if (hasOwn.call(dataAttr, rule)) { + if (cachedAttr == null || cachedAttr[rule] !== dataAttr[rule]) { + node.style[rule] = dataAttr[rule] } } - return cachedAttrs; + + for (rule in cachedAttr) if (hasOwn.call(cachedAttr, rule)) { + if (!hasOwn.call(dataAttr, rule)) node.style[rule] = "" + } } + + function shouldUseSetAttribute(attrName) { + return attrName !== "list" && + attrName !== "style" && + attrName !== "form" && + attrName !== "type" && + attrName !== "width" && + attrName !== "height" + } + + function setSingleAttr( + node, + attrName, + dataAttr, + cachedAttr, + tag, + namespace + ) { + if (attrName === "config" || attrName === "key") { + // `config` isn't a real attribute, so ignore it + return true + } else if (isFunction(dataAttr) && attrName.slice(0, 2) === "on") { + // hook event handlers to the auto-redrawing system + node[attrName] = autoredraw(dataAttr, node) + } else if (attrName === "style" && dataAttr != null && + isObject(dataAttr)) { + // handle `style: {...}` + copyStyleAttrs(node, dataAttr, cachedAttr) + } else if (namespace != null) { + // handle SVG + if (attrName === "href") { + node.setAttributeNS("http://www.w3.org/1999/xlink", + "href", dataAttr) + } else { + node.setAttribute( + attrName === "className" ? "class" : attrName, + dataAttr) + } + } else if (attrName in node && shouldUseSetAttribute(attrName)) { + // handle cases that are properties (but ignore cases where we + // should use setAttribute instead) + // + // - 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 + // + // #348 don't set the value if not needed - otherwise, cursor + // placement breaks in Chrome + try { + if (tag !== "input" || node[attrName] !== dataAttr) { + node[attrName] = dataAttr + } + } catch (e) { + node.setAttribute(attrName, dataAttr) + } + } + else node.setAttribute(attrName, dataAttr) + } + + function trySetAttr( + node, + attrName, + dataAttr, + cachedAttr, + cachedAttrs, + tag, + namespace + ) { + if (!(attrName in cachedAttrs) || (cachedAttr !== dataAttr)) { + cachedAttrs[attrName] = dataAttr + try { + return setSingleAttr( + node, + attrName, + dataAttr, + cachedAttr, + tag, + namespace) + } catch (e) { + // swallow IE's invalid argument errors to mimic HTML's + // fallback-to-doing-nothing-on-invalid-attributes behavior + 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 + node.value = dataAttr + } + } + + function setAttributes(node, tag, dataAttrs, cachedAttrs, namespace) { + for (var attrName in dataAttrs) if (hasOwn.call(dataAttrs, attrName)) { + if (trySetAttr( + node, + attrName, + dataAttrs[attrName], + cachedAttrs[attrName], + cachedAttrs, + tag, + namespace)) { + continue + } + } + return cachedAttrs + } + function clear(nodes, cached) { for (var i = nodes.length - 1; i > -1; i--) { if (nodes[i] && nodes[i].parentNode) { - try { nodes[i].parentNode.removeChild(nodes[i]); } - catch (e) {} //ignore if this fails due to order of events (see http://stackoverflow.com/questions/21926083/failed-to-execute-removechild-on-node) - cached = [].concat(cached); - if (cached[i]) unload(cached[i]); + try { + nodes[i].parentNode.removeChild(nodes[i]) + } catch (e) { + /* eslint-disable max-len */ + // ignore if this fails due to order of events (see + // http://stackoverflow.com/questions/21926083/failed-to-execute-removechild-on-node) + /* eslint-enable max-len */ + } + cached = [].concat(cached) + if (cached[i]) unload(cached[i]) } } - //release memory if nodes is an array. This check should fail if nodes is a NodeList (see loop above) - if (nodes.length) nodes.length = 0; + // release memory if nodes is an array. This check should fail if nodes + // is a NodeList (see loop above) + if (nodes.length) { + nodes.length = 0 + } } + function unload(cached) { if (cached.configContext && isFunction(cached.configContext.onunload)) { - cached.configContext.onunload(); - cached.configContext.onunload = null; + cached.configContext.onunload() + cached.configContext.onunload = null } if (cached.controllers) { forEach(cached.controllers, function (controller) { - if (isFunction(controller.onunload)) controller.onunload({preventDefault: noop}); - }); + if (isFunction(controller.onunload)) { + controller.onunload({preventDefault: noop}) + } + }) } if (cached.children) { - if (isArray(cached.children)) forEach(cached.children, unload); - else if (cached.children.tag) unload(cached.children); + if (isArray(cached.children)) forEach(cached.children, unload) + else if (cached.children.tag) unload(cached.children) } } + function appendTextFragment(parentElement, data) { - try { - parentElement.appendChild($document.createRange().createContextualFragment(data)); - } catch (e) { - parentElement.insertAdjacentHTML("beforeend", data); - } + try { + parentElement.appendChild( + $document.createRange().createContextualFragment(data)) + } catch (e) { + parentElement.insertAdjacentHTML("beforeend", data) + } } + function injectHTML(parentElement, index, data) { - var nextSibling = parentElement.childNodes[index]; + var nextSibling = parentElement.childNodes[index] if (nextSibling) { - var isElement = nextSibling.nodeType !== 1; - var placeholder = $document.createElement("span"); + var isElement = nextSibling.nodeType !== 1 + var placeholder = $document.createElement("span") if (isElement) { - parentElement.insertBefore(placeholder, nextSibling || null); - placeholder.insertAdjacentHTML("beforebegin", data); - parentElement.removeChild(placeholder); + parentElement.insertBefore(placeholder, nextSibling || null) + placeholder.insertAdjacentHTML("beforebegin", data) + parentElement.removeChild(placeholder) + } else { + nextSibling.insertAdjacentHTML("beforebegin", data) } - else nextSibling.insertAdjacentHTML("beforebegin", data); + } else { + appendTextFragment(parentElement, data) } - else { - appendTextFragment(parentElement, data); - } - var nodes = []; + + var nodes = [] + while (parentElement.childNodes[index] !== nextSibling) { - nodes.push(parentElement.childNodes[index]); - index++; + nodes.push(parentElement.childNodes[index]) + index++ } - return nodes; + + return nodes } + function autoredraw(callback, object) { - return function(e) { - e = e || event; - m.redraw.strategy("diff"); - m.startComputation(); - try { return callback.call(object, e); } - finally { - endFirstComputation(); + return function (e) { + e = e || event + m.redraw.strategy("diff") + m.startComputation() + try { + return callback.call(object, e) + } finally { + endFirstComputation() } - }; + } } - var html; + var html var documentNode = { - appendChild: function(node) { - if (html === undefined) html = $document.createElement("html"); - if ($document.documentElement && $document.documentElement !== node) { - $document.replaceChild(node, $document.documentElement); + appendChild: function (node) { + if (html === undefined) html = $document.createElement("html") + if ($document.documentElement && + $document.documentElement !== node) { + $document.replaceChild(node, $document.documentElement) + } else { + $document.appendChild(node) } - else $document.appendChild(node); - this.childNodes = $document.childNodes; + + this.childNodes = $document.childNodes }, - insertBefore: function(node) { - this.appendChild(node); + + insertBefore: function (node) { + this.appendChild(node) }, + childNodes: [] - }; - var nodeCache = [], cellCache = {}; - m.render = function(root, cell, forceRecreation) { - var configs = []; - if (!root) throw new Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined."); - var id = getCellCacheKey(root); - var isDocumentRoot = root === $document; - var node = isDocumentRoot || root === $document.documentElement ? documentNode : root; - if (isDocumentRoot && cell.tag !== "html") cell = {tag: "html", attrs: {}, children: cell}; - if (cellCache[id] === undefined) clear(node.childNodes); - if (forceRecreation === true) reset(root); - cellCache[id] = build(node, null, undefined, undefined, cell, cellCache[id], false, 0, null, undefined, configs); - forEach(configs, function (config) { config(); }); - }; - function getCellCacheKey(element) { - var index = nodeCache.indexOf(element); - return index < 0 ? nodeCache.push(element) - 1 : index; } - m.trust = function(value) { - value = new String(value); - value.$trusted = true; - return value; - }; + var nodeCache = [] + var cellCache = {} + + m.render = function (root, cell, forceRecreation) { + if (!root) { + throw new Error("Ensure the DOM element being passed to " + + "m.route/m.mount/m.render is not undefined.") + } + var configs = [] + var id = getCellCacheKey(root) + var isDocumentRoot = root === $document + var node + + if (isDocumentRoot || root === $document.documentElement) { + node = documentNode + } else { + node = root + } + + if (isDocumentRoot && cell.tag !== "html") { + cell = {tag: "html", attrs: {}, children: cell} + } + + if (cellCache[id] === undefined) clear(node.childNodes) + if (forceRecreation === true) reset(root) + + cellCache[id] = build( + node, + null, + undefined, + undefined, + cell, + cellCache[id], + false, + 0, + null, + undefined, + configs) + + forEach(configs, function (config) { config() }) + } + + function getCellCacheKey(element) { + var index = nodeCache.indexOf(element) + return index < 0 ? nodeCache.push(element) - 1 : index + } + + m.trust = function (value) { + value = new String(value) // eslint-disable-line no-new-wrappers + value.$trusted = true + return value + } function gettersetter(store) { - var prop = function() { - if (arguments.length) store = arguments[0]; - return store; - }; + function prop() { + if (arguments.length) store = arguments[0] + return store + } - prop.toJSON = function() { - return store; - }; + prop.toJSON = function () { + return store + } - return prop; + return prop } m.prop = function (store) { - //note: using non-strict equality check here because we're checking if store is null OR undefined - if ((store != null && isObject(store) || isFunction(store)) && isFunction(store.then)) { - return propify(store); + if ((store != null && isObject(store) || isFunction(store)) && + isFunction(store.then)) { + return propify(store) } - return gettersetter(store); - }; - - var roots = [], components = [], controllers = [], lastRedrawId = null, lastRedrawCallTime = 0, computePreRedrawHook = null, computePostRedrawHook = null, topComponent, unloaders = []; - var FRAME_BUDGET = 16; //60 frames per second = 1 call per 16 ms - function parameterize(component, args) { - var controller = function() { - return (component.controller || noop).apply(this, args) || this; - }; - if (component.controller) controller.prototype = component.controller.prototype; - var view = function(ctrl) { - var currentArgs = arguments.length > 1 ? args.concat([].slice.call(arguments, 1)) : args; - return component.view.apply(component, currentArgs ? [ctrl].concat(currentArgs) : [ctrl]); - }; - view.$original = component.view; - var output = {controller: controller, view: view}; - if (args[0] && args[0].key != null) output.attrs = {key: args[0].key}; - return output; + return gettersetter(store) } - m.component = function(component) { - for (var args = [], i = 1; i < arguments.length; i++) args.push(arguments[i]); - return parameterize(component, args); - }; - m.mount = m.module = function(root, component) { - if (!root) throw new Error("Please ensure the DOM element exists before rendering a template into it."); - var index = roots.indexOf(root); - if (index < 0) index = roots.length; - var isPrevented = false; - var event = {preventDefault: function() { - isPrevented = true; - computePreRedrawHook = computePostRedrawHook = null; - }}; + var roots = [] + var components = [] + var controllers = [] + var lastRedrawId = null + var lastRedrawCallTime = 0 + var computePreRedrawHook = null + var computePostRedrawHook = null + var topComponent + var FRAME_BUDGET = 16 // 60 frames per second = 1 call per 16 ms + + function parameterize(component, args) { + function controller() { + /* eslint-disable no-invalid-this */ + return (component.controller || noop).apply(this, args) || this + /* eslint-enable no-invalid-this */ + } + + if (component.controller) { + controller.prototype = component.controller.prototype + } + + function view(ctrl) { + var currentArgs = [ctrl].concat(args) + for (var i = 1; i < arguments.length; i++) { + currentArgs.push(arguments[i]) + } + + return component.view.apply(component, currentArgs) + } + + view.$original = component.view + var output = {controller: controller, view: view} + if (args[0] && args[0].key != null) output.attrs = {key: args[0].key} + return output + } + + m.component = function (component) { + for (var args = [], i = 1; i < arguments.length; i++) { + args.push(arguments[i]) + } + + return parameterize(component, args) + } + + function checkPrevented(component, root, index, isPrevented) { + if (!isPrevented) { + m.redraw.strategy("all") + m.startComputation() + roots[index] = root + var currentComponent + + if (component) { + currentComponent = topComponent = component + } else { + currentComponent = topComponent = component = {controller: noop} + } + + var controller = new (component.controller || noop)() + + // controllers may call m.mount recursively (via m.route redirects, + // for example) + // this conditional ensures only the last recursive m.mount call is + // applied + if (currentComponent === topComponent) { + controllers[index] = controller + components[index] = component + } + endFirstComputation() + if (component === null) { + removeRootElement(root, index) + } + return controllers[index] + } else if (component == null) { + removeRootElement(root, index) + } + } + + m.mount = m.module = function (root, component) { + if (!root) { + throw new Error("Please ensure the DOM element exists before " + + "rendering a template into it.") + } + + var index = roots.indexOf(root) + if (index < 0) index = roots.length + + var isPrevented = false + var event = { + preventDefault: function () { + isPrevented = true + computePreRedrawHook = computePostRedrawHook = null + } + } forEach(unloaders, function (unloader) { - unloader.handler.call(unloader.controller, event); - unloader.controller.onunload = null; - }); + unloader.handler.call(unloader.controller, event) + unloader.controller.onunload = null + }) if (isPrevented) { forEach(unloaders, function (unloader) { - unloader.controller.onunload = unloader.handler; - }); + unloader.controller.onunload = unloader.handler + }) + } else { + unloaders = [] } - else unloaders = []; if (controllers[index] && isFunction(controllers[index].onunload)) { - controllers[index].onunload(event); + controllers[index].onunload(event) } - var isNullComponent = component === null; - - if (!isPrevented) { - m.redraw.strategy("all"); - m.startComputation(); - roots[index] = root; - var currentComponent = component ? (topComponent = component) : (topComponent = component = {controller: noop}); - var controller = new (component.controller || noop)(); - //controllers may call m.mount recursively (via m.route redirects, for example) - //this conditional ensures only the last recursive m.mount call is applied - if (currentComponent === topComponent) { - controllers[index] = controller; - components[index] = component; - } - endFirstComputation(); - if (isNullComponent) { - removeRootElement(root, index); - } - return controllers[index]; - } - if (isNullComponent) { - removeRootElement(root, index); - } - }; + return checkPrevented(component, root, index, isPrevented) + } function removeRootElement(root, index) { - roots.splice(index, 1); - controllers.splice(index, 1); - components.splice(index, 1); - reset(root); - nodeCache.splice(getCellCacheKey(root), 1); + 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; - redrawing = true; - if (force) forcing = true; + var redrawing = false + m.redraw = function (force) { + if (redrawing) return + redrawing = true + if (force) forcing = true + try { - //lastRedrawId is a positive number if a second redraw is requested before the next animation frame - //lastRedrawID is null if it's the first redraw and not an event handler + // lastRedrawId is a positive number if a second redraw is requested + // before the next animation frame + // lastRedrawID is null if it's the first redraw and not an event + // handler if (lastRedrawId && !force) { - //when setTimeout: only reschedule redraw if time between now and previous redraw is bigger than a frame, otherwise keep currently scheduled timeout - //when rAF: always reschedule redraw - if ($requestAnimationFrame === window.requestAnimationFrame || new Date - lastRedrawCallTime > FRAME_BUDGET) { - if (lastRedrawId > 0) $cancelAnimationFrame(lastRedrawId); - lastRedrawId = $requestAnimationFrame(redraw, FRAME_BUDGET); + // when setTimeout: only reschedule redraw if time between now + // and previous redraw is bigger than a frame, otherwise keep + // currently scheduled timeout + // when rAF: always reschedule redraw + if ($requestAnimationFrame === global.requestAnimationFrame || + new Date() - lastRedrawCallTime > FRAME_BUDGET) { + if (lastRedrawId > 0) $cancelAnimationFrame(lastRedrawId) + lastRedrawId = $requestAnimationFrame(redraw, FRAME_BUDGET) } + } else { + redraw() + lastRedrawId = $requestAnimationFrame(function () { + lastRedrawId = null + }, FRAME_BUDGET) } - else { - redraw(); - lastRedrawId = $requestAnimationFrame(function() { lastRedrawId = null; }, FRAME_BUDGET); - } + } finally { + redrawing = forcing = false } - finally { - redrawing = forcing = false; - } - }; - m.redraw.strategy = m.prop(); + } + + m.redraw.strategy = m.prop() function redraw() { if (computePreRedrawHook) { - computePreRedrawHook(); - computePreRedrawHook = null; + computePreRedrawHook() + computePreRedrawHook = null } forEach(roots, function (root, i) { - var component = components[i]; + var component = components[i] if (controllers[i]) { - var args = [controllers[i]]; - m.render(root, component.view ? component.view(controllers[i], args) : ""); + var args = [controllers[i]] + m.render(root, + component.view ? component.view(controllers[i], args) : "") } - }); - //after rendering within a routed context, we need to scroll back to the top, and fetch the document title for history.pushState + }) + // after rendering within a routed context, we need to scroll back to + // the top, and fetch the document title for history.pushState if (computePostRedrawHook) { - computePostRedrawHook(); - computePostRedrawHook = null; - } - lastRedrawId = null; - lastRedrawCallTime = new Date; - m.redraw.strategy("diff"); - } - - var pendingRequests = 0; - m.startComputation = function() { pendingRequests++; }; - m.endComputation = function() { - if (pendingRequests > 1) pendingRequests--; - else { - pendingRequests = 0; - m.redraw(); + computePostRedrawHook() + computePostRedrawHook = null } + lastRedrawId = null + lastRedrawCallTime = new Date() + m.redraw.strategy("diff") } function endFirstComputation() { if (m.redraw.strategy() === "none") { - pendingRequests--; - m.redraw.strategy("diff"); + pendingRequests-- + m.redraw.strategy("diff") + } else { + m.endComputation() } - else m.endComputation(); } - m.withAttr = function(prop, withAttrCallback, callbackThis) { - return function(e) { - e = e || event; - var currentTarget = e.currentTarget || this; - var _this = callbackThis || this; - withAttrCallback.call(_this, prop in currentTarget ? currentTarget[prop] : currentTarget.getAttribute(prop)); - }; - }; + m.withAttr = function (prop, withAttrCallback, callbackThis) { + return function (e) { + e = e || event + /* eslint-disable no-invalid-this */ + var currentTarget = e.currentTarget || this + var _this = callbackThis || this + /* eslint-enable no-invalid-this */ + var target = prop in currentTarget ? + currentTarget[prop] : + currentTarget.getAttribute(prop) + withAttrCallback.call(_this, target) + } + } - //routing - var modes = {pathname: "", hash: "#", search: "?"}; - var redirect = noop, routeParams, currentRoute, isDefaultRoute = false; - m.route = function(root, arg1, arg2, vdom) { - //m.route() - if (arguments.length === 0) return currentRoute; - //m.route(el, defaultRoute, routes) - else if (arguments.length === 3 && isString(arg1)) { - redirect = function(source) { - var path = currentRoute = normalizeRoute(source); + // routing + var modes = {pathname: "", hash: "#", search: "?"} + var redirect = noop + var isDefaultRoute = false + var routeParams, currentRoute + + m.route = function (root, arg1, arg2, vdom) { // eslint-disable-line + // m.route() + if (arguments.length === 0) return currentRoute + // m.route(el, defaultRoute, routes) + if (arguments.length === 3 && isString(arg1)) { + redirect = function (source) { + var path = currentRoute = normalizeRoute(source) if (!routeByValue(root, arg2, path)) { - if (isDefaultRoute) throw new Error("Ensure the default route matches one of the routes defined in m.route"); - isDefaultRoute = true; - m.route(arg1, true); - isDefaultRoute = false; + if (isDefaultRoute) { + throw new Error("Ensure the default route matches " + + "one of the routes defined in m.route") + } + + isDefaultRoute = true + m.route(arg1, true) + isDefaultRoute = false } - }; - var listener = m.route.mode === "hash" ? "onhashchange" : "onpopstate"; - window[listener] = function() { - var path = $location[m.route.mode]; - if (m.route.mode === "pathname") path += $location.search; - if (currentRoute !== normalizeRoute(path)) redirect(path); - }; + } - computePreRedrawHook = setScroll; - window[listener](); + var listener = m.route.mode === "hash" ? + "onhashchange" : + "onpopstate" + + global[listener] = function () { + var path = $location[m.route.mode] + if (m.route.mode === "pathname") path += $location.search + if (currentRoute !== normalizeRoute(path)) redirect(path) + } + + computePreRedrawHook = setScroll + global[listener]() + + return } - //config: m.route - else if (root.addEventListener || root.attachEvent) { - root.href = (m.route.mode !== 'pathname' ? $location.pathname : '') + modes[m.route.mode] + vdom.attrs.href; + + // config: m.route + if (root.addEventListener || root.attachEvent) { + var base = m.route.mode !== "pathname" ? $location.pathname : "" + root.href = base + modes[m.route.mode] + vdom.attrs.href if (root.addEventListener) { - root.removeEventListener("click", routeUnobtrusive); - root.addEventListener("click", routeUnobtrusive); + root.removeEventListener("click", routeUnobtrusive) + root.addEventListener("click", routeUnobtrusive) + } else { + root.detachEvent("onclick", routeUnobtrusive) + root.attachEvent("onclick", routeUnobtrusive) } - else { - root.detachEvent("onclick", routeUnobtrusive); - root.attachEvent("onclick", routeUnobtrusive); - } - } - //m.route(route, params, shouldReplaceHistoryEntry) - else if (isString(root)) { - var oldRoute = currentRoute; - currentRoute = root; - var args = arg1 || {}; - var queryIndex = currentRoute.indexOf("?"); - var params = queryIndex > -1 ? parseQueryString(currentRoute.slice(queryIndex + 1)) : {}; - for (var i in args) params[i] = args[i]; - var querystring = buildQueryString(params); - var currentPath = queryIndex > -1 ? currentRoute.slice(0, queryIndex) : currentRoute; - if (querystring) currentRoute = currentPath + (currentPath.indexOf("?") === -1 ? "?" : "&") + querystring; - var shouldReplaceHistoryEntry = (arguments.length === 3 ? arg2 : arg1) === true || oldRoute === root; + return + } + // m.route(route, params, shouldReplaceHistoryEntry) + if (isString(root)) { + var oldRoute = currentRoute + currentRoute = root - if (window.history.pushState) { - computePreRedrawHook = setScroll; - computePostRedrawHook = function() { - window.history[shouldReplaceHistoryEntry ? "replaceState" : "pushState"](null, $document.title, modes[m.route.mode] + currentRoute); - }; - redirect(modes[m.route.mode] + currentRoute); + var args = arg1 || {} + var queryIndex = currentRoute.indexOf("?") + var params + + if (queryIndex > -1) { + params = parseQueryString(currentRoute.slice(queryIndex + 1)) + } else { + params = {} } - else { - $location[m.route.mode] = currentRoute; - redirect(modes[m.route.mode] + currentRoute); + + for (var i in args) if (hasOwn.call(args, i)) { + params[i] = args[i] + } + + var querystring = buildQueryString(params) + var currentPath + + if (queryIndex > -1) { + currentPath = currentRoute.slice(0, queryIndex) + } else { + currentPath = currentRoute + } + + if (querystring) { + currentRoute = currentPath + + (currentPath.indexOf("?") === -1 ? "?" : "&") + + querystring + } + + var replaceHistory = + (arguments.length === 3 ? arg2 : arg1) === true || + oldRoute === root + + if (global.history.pushState) { + var method = replaceHistory ? "replaceState" : "pushState" + computePreRedrawHook = setScroll + computePostRedrawHook = function () { + global.history[method](null, $document.title, + modes[m.route.mode] + currentRoute) + } + redirect(modes[m.route.mode] + currentRoute) + } else { + $location[m.route.mode] = currentRoute + redirect(modes[m.route.mode] + currentRoute) } } - }; - m.route.param = function(key) { - if (!routeParams) throw new Error("You must call m.route(element, defaultRoute, routes) before calling m.route.param()"); - if( !key ){ - return routeParams; - } - return routeParams[key]; - }; - m.route.mode = "search"; - function normalizeRoute(route) { - return route.slice(modes[m.route.mode].length); } - function routeByValue(root, router, path) { - routeParams = {}; - var queryStart = path.indexOf("?"); + m.route.param = function (key) { + if (!routeParams) { + throw new Error("You must call m.route(element, defaultRoute, " + + "routes) before calling m.route.param()") + } + + if (!key) { + return routeParams + } + + return routeParams[key] + } + + m.route.mode = "search" + + function normalizeRoute(route) { + return route.slice(modes[m.route.mode].length) + } + + function routeByValue(root, router, path) { + routeParams = {} + + var queryStart = path.indexOf("?") if (queryStart !== -1) { - routeParams = parseQueryString(path.substr(queryStart + 1, path.length)); - path = path.substr(0, queryStart); + routeParams = parseQueryString( + path.substr(queryStart + 1, path.length)) + path = path.substr(0, queryStart) } // Get all routes and check if there's // an exact match for the current path - var keys = Object.keys(router); - var index = keys.indexOf(path); - if(index !== -1){ - m.mount(root, router[keys [index]]); - return true; + var keys = Object.keys(router) + var index = keys.indexOf(path) + + if (index !== -1){ + m.mount(root, router[keys [index]]) + return true } - for (var route in router) { + for (var route in router) if (hasOwn.call(router, route)) { if (route === path) { - m.mount(root, router[route]); - return true; + m.mount(root, router[route]) + return true } - var matcher = new RegExp("^" + route.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$"); + var matcher = new RegExp("^" + route + .replace(/:[^\/]+?\.{3}/g, "(.*?)") + .replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$") if (matcher.test(path)) { - path.replace(matcher, function() { - var keys = route.match(/:[^\/]+/g) || []; - var values = [].slice.call(arguments, 1, -2); + /* eslint-disable no-loop-func */ + path.replace(matcher, function () { + var keys = route.match(/:[^\/]+/g) || [] + var values = [].slice.call(arguments, 1, -2) forEach(keys, function (key, i) { - routeParams[key.replace(/:|\./g, "")] = decodeURIComponent(values[i]); + routeParams[key.replace(/:|\./g, "")] = + decodeURIComponent(values[i]) }) - m.mount(root, router[route]); - }); - return true; + m.mount(root, router[route]) + }) + /* eslint-enable no-loop-func */ + return true } } } + function routeUnobtrusive(e) { - e = e || event; - if (e.ctrlKey || e.metaKey || e.shiftKey || e.which === 2) return; + e = e || event + if (e.ctrlKey || e.metaKey || e.shiftKey || e.which === 2) return - if (e.preventDefault) e.preventDefault(); - else e.returnValue = false; + if (e.preventDefault) { + e.preventDefault() + } else { + e.returnValue = false + } + + var currentTarget = e.currentTarget || e.srcElement + var args + + if (m.route.mode === "pathname" && currentTarget.search) { + args = parseQueryString(currentTarget.search.slice(1)) + } else { + args = {} + } + + while (currentTarget && !/a/i.test(currentTarget.nodeName)) { + currentTarget = currentTarget.parentNode + } - var currentTarget = e.currentTarget || e.srcElement; - var args = m.route.mode === "pathname" && currentTarget.search ? parseQueryString(currentTarget.search.slice(1)) : {}; - while (currentTarget && currentTarget.nodeName.toUpperCase() !== "A") currentTarget = currentTarget.parentNode; // clear pendingRequests because we want an immediate route change - pendingRequests = 0; - m.route(currentTarget[m.route.mode].slice(modes[m.route.mode].length), args); + pendingRequests = 0 + m.route(currentTarget[m.route.mode] + .slice(modes[m.route.mode].length), args) } + function setScroll() { - if (m.route.mode !== "hash" && $location.hash) $location.hash = $location.hash; - else window.scrollTo(0, 0); + if (m.route.mode !== "hash" && $location.hash) { + $location.hash = $location.hash + } else { + global.scrollTo(0, 0) + } } + function buildQueryString(object, prefix) { - var duplicates = {}; - var str = []; - for (var prop in object) { - var key = prefix ? prefix + "[" + prop + "]" : prop; - var value = object[prop]; + var duplicates = {} + var str = [] + + for (var prop in object) if (hasOwn.call(object, prop)) { + var key = prefix ? prefix + "[" + prop + "]" : prop + var value = object[prop] if (value === null) { - str.push(encodeURIComponent(key)); + str.push(encodeURIComponent(key)) } else if (isObject(value)) { - str.push(buildQueryString(value, key)); + str.push(buildQueryString(value, key)) } else if (isArray(value)) { - var keys = []; - duplicates[key] = duplicates[key] || {}; + var keys = [] + duplicates[key] = duplicates[key] || {} + /* eslint-disable no-loop-func */ forEach(value, function (item) { + /* eslint-enable no-loop-func */ if (!duplicates[key][item]) { - duplicates[key][item] = true; - keys.push(encodeURIComponent(key) + "=" + encodeURIComponent(item)); + duplicates[key][item] = true + keys.push(encodeURIComponent(key) + "=" + + encodeURIComponent(item)) } - }); - str.push(keys.join("&")); + }) + str.push(keys.join("&")) } else if (value !== undefined) { - str.push(encodeURIComponent(key) + "=" + encodeURIComponent(value)); + str.push(encodeURIComponent(key) + "=" + + encodeURIComponent(value)) } } - return str.join("&"); + return str.join("&") } + function parseQueryString(str) { - if (str === "" || str == null) return {}; - if (str.charAt(0) === "?") str = str.slice(1); + if (str === "" || str == null) return {} + if (str.charAt(0) === "?") str = str.slice(1) + + var pairs = str.split("&") + var params = {} - var pairs = str.split("&"), params = {}; forEach(pairs, function (string) { - var pair = string.split("="); - var key = decodeURIComponent(pair[0]); - var value = pair.length === 2 ? decodeURIComponent(pair[1]) : null; + var pair = string.split("=") + var key = decodeURIComponent(pair[0]) + var value = pair.length === 2 ? decodeURIComponent(pair[1]) : null if (params[key] != null) { - if (!isArray(params[key])) params[key] = [params[key]]; - params[key].push(value); + if (!isArray(params[key])) params[key] = [params[key]] + params[key].push(value) } - else params[key] = value; - }); + else params[key] = value + }) - return params; + return params } - m.route.buildQueryString = buildQueryString; - m.route.parseQueryString = parseQueryString; + + m.route.buildQueryString = buildQueryString + m.route.parseQueryString = parseQueryString function reset(root) { - var cacheKey = getCellCacheKey(root); - clear(root.childNodes, cellCache[cacheKey]); - cellCache[cacheKey] = undefined; + var cacheKey = getCellCacheKey(root) + clear(root.childNodes, cellCache[cacheKey]) + cellCache[cacheKey] = undefined } m.deferred = function () { - var deferred = new Deferred(); - deferred.promise = propify(deferred.promise); - return deferred; - }; - function propify(promise, initialValue) { - var prop = m.prop(initialValue); - promise.then(prop); - prop.then = function(resolve, reject) { - return propify(promise.then(resolve, reject), initialValue); - }; - prop["catch"] = prop.then.bind(null, null); - return prop; + var deferred = new Deferred() + deferred.promise = propify(deferred.promise) + return deferred } - //Promiz.mithril.js | Zolmeister | MIT - //a modified version of Promiz.js, which does not conform to Promises/A+ for two reasons: - //1) `then` callbacks are called synchronously (because setTimeout is too slow, and the setImmediate polyfill is too big - //2) throwing subclasses of Error cause the error to be bubbled up instead of triggering rejection (because the spec does not account for the important use case of default browser error handling, i.e. message w/ line number) - function Deferred(successCallback, failureCallback) { - var RESOLVING = 1, REJECTING = 2, RESOLVED = 3, REJECTED = 4; - var self = this, state = 0, promiseValue = 0, next = []; - self.promise = {}; - - self.resolve = function(value) { - if (!state) { - promiseValue = value; - state = RESOLVING; - - fire(); - } - return this; - }; - - self.reject = function(value) { - if (!state) { - promiseValue = value; - state = REJECTING; - - fire(); - } - return this; - }; - - self.promise.then = function(successCallback, failureCallback) { - var deferred = new Deferred(successCallback, failureCallback) - if (state === RESOLVED) { - deferred.resolve(promiseValue); - } - else if (state === REJECTED) { - deferred.reject(promiseValue); - } - else { - next.push(deferred); - } - return deferred.promise - }; - - function finish(type) { - state = type || REJECTED; - next.map(function(deferred) { - state === RESOLVED ? deferred.resolve(promiseValue) : deferred.reject(promiseValue); - }); + function propify(promise, initialValue) { + var prop = m.prop(initialValue) + promise.then(prop) + prop.then = function (resolve, reject) { + return propify(promise.then(resolve, reject), initialValue) } - function thennable(then, successCallback, failureCallback, notThennableCallback) { - if (((promiseValue != null && isObject(promiseValue)) || isFunction(promiseValue)) && isFunction(then)) { + prop.catch = prop.then.bind(null, null) + return prop + } + // Promiz.mithril.js | Zolmeister | MIT + // a modified version of Promiz.js, which does not conform to Promises/A+ + // for two reasons: + // + // 1) `then` callbacks are called synchronously (because setTimeout is too + // slow, and the setImmediate polyfill is too big + // + // 2) throwing subclasses of Error cause the error to be bubbled up instead + // of triggering rejection (because the spec does not account for the + // important use case of default browser error handling, i.e. message w/ + // line number) + + var RESOLVING = 1 + var REJECTING = 2 + var RESOLVED = 3 + var REJECTED = 4 + + function Deferred(onSuccess, onFailure) { + var self = this + var state = 0 + var promiseValue = 0 + var next = [] + + self.promise = {} + + self.resolve = function (value) { + if (!state) { + promiseValue = value + state = RESOLVING + + fire() + } + + return self + } + + self.reject = function (value) { + if (!state) { + promiseValue = value + state = REJECTING + + fire() + } + + return self + } + + self.promise.then = function (onSuccess, onFailure) { + var deferred = new Deferred(onSuccess, onFailure) + + if (state === RESOLVED) { + deferred.resolve(promiseValue) + } else if (state === REJECTED) { + deferred.reject(promiseValue) + } else { + next.push(deferred) + } + + return deferred.promise + } + + function finish(type) { + state = type || REJECTED + next.map(function (deferred) { + if (state === RESOLVED) { + deferred.resolve(promiseValue) + } else { + deferred.reject(promiseValue) + } + }) + } + + function thennable(then, success, failure, notThennable) { + if (((promiseValue != null && isObject(promiseValue)) || + isFunction(promiseValue)) && isFunction(then)) { try { // count protects against abuse calls from spec checker - var count = 0; - then.call(promiseValue, function(value) { - if (count++) return; - promiseValue = value; - successCallback(); + var count = 0 + then.call(promiseValue, function (value) { + if (count++) return + promiseValue = value + success() }, function (value) { - if (count++) return; - promiseValue = value; - failureCallback(); - }); - } - catch (e) { - m.deferred.onerror(e); - promiseValue = e; - failureCallback(); + if (count++) return + promiseValue = value + failure() + }) + } catch (e) { + m.deferred.onerror(e) + promiseValue = e + failure() } } else { - notThennableCallback(); + notThennable() } } function fire() { // check if it's a thenable - var then; + var then try { - then = promiseValue && promiseValue.then; - } - catch (e) { - m.deferred.onerror(e); - promiseValue = e; - state = REJECTING; - return fire(); + then = promiseValue && promiseValue.then + } catch (e) { + m.deferred.onerror(e) + promiseValue = e + state = REJECTING + return fire() } if (state === REJECTING) { @@ -1185,223 +1875,259 @@ var m = (function app(window, undefined) { fire() }, function () { try { - if (state === RESOLVING && isFunction(successCallback)) { - promiseValue = successCallback(promiseValue); + if (state === RESOLVING && isFunction(onSuccess)) { + promiseValue = onSuccess(promiseValue) + } else if (state === REJECTING && isFunction(onFailure)) { + promiseValue = onFailure(promiseValue) + state = RESOLVING } - else if (state === REJECTING && isFunction(failureCallback)) { - promiseValue = failureCallback(promiseValue); - state = RESOLVING; - } - } - catch (e) { - m.deferred.onerror(e); - promiseValue = e; - return finish(); + } catch (e) { + m.deferred.onerror(e) + promiseValue = e + return finish() } if (promiseValue === self) { - promiseValue = TypeError(); - finish(); + promiseValue = TypeError() + finish() } else { thennable(then, function () { - finish(RESOLVED); + finish(RESOLVED) }, finish, function () { - finish(state === RESOLVING && RESOLVED); - }); + finish(state === RESOLVING && RESOLVED) + }) } - }); + }) } } - m.deferred.onerror = function(e) { - if (type.call(e) === "[object Error]" && !e.constructor.toString().match(/ Error/)) { - pendingRequests = 0; - throw e; - } - }; - m.sync = function(args) { - var method = "resolve"; + m.deferred.onerror = function (e) { + if (type.call(e) === "[object Error]" && + !e.constructor.toString().match(/ Error/)) { + pendingRequests = 0 + throw e + } + } + + m.sync = function (args) { + var deferred = m.deferred() + var outstanding = args.length + var results = new Array(outstanding) + var method = "resolve" function synchronizer(pos, resolved) { - return function(value) { - results[pos] = value; - if (!resolved) method = "reject"; + return function (value) { + results[pos] = value + if (!resolved) method = "reject" if (--outstanding === 0) { - deferred.promise(results); - deferred[method](results); + deferred.promise(results) + deferred[method](results) } - return value; - }; + return value + } } - var deferred = m.deferred(); - var outstanding = args.length; - var results = new Array(outstanding); if (args.length > 0) { forEach(args, function (arg, i) { - arg.then(synchronizer(i, true), synchronizer(i, false)); - }); + arg.then(synchronizer(i, true), synchronizer(i, false)) + }) + } else { + deferred.resolve([]) } - else deferred.resolve([]); - return deferred.promise; - }; - function identity(value) { return value; } + return deferred.promise + } + + function identity(value) { return value } + + function handleJsonp(options) { + var callbackKey = "mithril_callback_" + + new Date().getTime() + "_" + + (Math.round(Math.random() * 1e16)).toString(36) + + var script = $document.createElement("script") + + global[callbackKey] = function (resp) { + script.parentNode.removeChild(script) + options.onload({ + type: "load", + target: { + responseText: resp + } + }) + global[callbackKey] = undefined + } + + script.onerror = function () { + script.parentNode.removeChild(script) + + options.onerror({ + type: "error", + target: { + status: 500, + responseText: JSON.stringify({ + error: "Error making jsonp request" + }) + } + }) + global[callbackKey] = undefined + + return false + } + + script.onload = function () { + return false + } + + script.src = options.url + + (options.url.indexOf("?") > 0 ? "&" : "?") + + (options.callbackKey ? options.callbackKey : "callback") + + "=" + callbackKey + + "&" + buildQueryString(options.data || {}) + + $document.body.appendChild(script) + } + + function createXhr(options) { + var xhr = new global.XMLHttpRequest() + xhr.open(options.method, options.url, true, options.user, + options.password) + + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status >= 200 && xhr.status < 300) { + options.onload({type: "load", target: xhr}) + } else { + options.onerror({type: "error", target: xhr}) + } + } + } + + if (options.serialize === JSON.stringify && + options.data && + options.method !== "GET") { + xhr.setRequestHeader("Content-Type", + "application/json; charset=utf-8") + } + + if (options.deserialize === JSON.parse) { + xhr.setRequestHeader("Accept", "application/json, text/*") + } + + if (isFunction(options.config)) { + var maybeXhr = options.config(xhr, options) + if (maybeXhr != null) xhr = maybeXhr + } + + var data = options.method === "GET" || !options.data ? "" : options.data + + if (data && !isString(data) && data.constructor !== global.FormData) { + throw new Error("Request data should be either be a string or " + + "FormData. Check the `serialize` option in `m.request`") + } + + xhr.send(data) + return xhr + } function ajax(options) { if (options.dataType && options.dataType.toLowerCase() === "jsonp") { - var callbackKey = "mithril_callback_" + new Date().getTime() + "_" + (Math.round(Math.random() * 1e16)).toString(36) - var script = $document.createElement("script"); - - window[callbackKey] = function(resp) { - script.parentNode.removeChild(script); - options.onload({ - type: "load", - target: { - responseText: resp - } - }); - window[callbackKey] = undefined; - }; - - script.onerror = function() { - script.parentNode.removeChild(script); - - options.onerror({ - type: "error", - target: { - status: 500, - responseText: JSON.stringify({ - error: "Error making jsonp request" - }) - } - }); - window[callbackKey] = undefined; - - return false; - } - - script.onload = function() { - return false; - }; - - script.src = options.url - + (options.url.indexOf("?") > 0 ? "&" : "?") - + (options.callbackKey ? options.callbackKey : "callback") - + "=" + callbackKey - + "&" + buildQueryString(options.data || {}); - $document.body.appendChild(script); - } - else { - var xhr = new window.XMLHttpRequest(); - xhr.open(options.method, options.url, true, options.user, options.password); - xhr.onreadystatechange = function() { - if (xhr.readyState === 4) { - if (xhr.status >= 200 && xhr.status < 300) options.onload({type: "load", target: xhr}); - else options.onerror({type: "error", target: xhr}); - } - }; - if (options.serialize === JSON.stringify && options.data && options.method !== "GET") { - xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8"); - } - if (options.deserialize === JSON.parse) { - xhr.setRequestHeader("Accept", "application/json, text/*"); - } - if (isFunction(options.config)) { - var maybeXhr = options.config(xhr, options); - if (maybeXhr != null) xhr = maybeXhr; - } - - var data = options.method === "GET" || !options.data ? "" : options.data; - if (data && (!isString(data) && data.constructor !== window.FormData)) { - throw new Error("Request data should be either be a string or FormData. Check the `serialize` option in `m.request`"); - } - xhr.send(data); - return xhr; + return handleJsonp(options) + } else { + return createXhr(options) } } - function bindData(xhrOptions, data, serialize) { - if (xhrOptions.method === "GET" && xhrOptions.dataType !== "jsonp") { - var prefix = xhrOptions.url.indexOf("?") < 0 ? "?" : "&"; - var querystring = buildQueryString(data); - xhrOptions.url = xhrOptions.url + (querystring ? prefix + querystring : ""); + function bindData(options, data, serialize) { + if (options.method === "GET" && options.dataType !== "jsonp") { + var prefix = options.url.indexOf("?") < 0 ? "?" : "&" + var querystring = buildQueryString(data) + options.url += (querystring ? prefix + querystring : "") + } else { + options.data = serialize(data) } - else xhrOptions.data = serialize(data); - return xhrOptions; } function parameterizeUrl(url, data) { - var tokens = url.match(/:[a-z]\w+/gi); + var tokens = url.match(/:[a-z]\w+/gi) + if (tokens && data) { forEach(tokens, function (token) { - var key = token.slice(1); - url = url.replace(token, data[key]); - delete data[key]; - }); + var key = token.slice(1) + url = url.replace(token, data[key]) + delete data[key] + }) } - return url; + + return url } - m.request = function(xhrOptions) { - if (xhrOptions.background !== true) m.startComputation(); - var deferred = new Deferred(); - var isJSONP = xhrOptions.dataType && xhrOptions.dataType.toLowerCase() === "jsonp" - var serialize = xhrOptions.serialize = isJSONP ? identity : xhrOptions.serialize || JSON.stringify; - var deserialize = xhrOptions.deserialize = isJSONP ? identity : xhrOptions.deserialize || JSON.parse; - var extract = isJSONP ? function(jsonp) { return jsonp.responseText } : xhrOptions.extract || function(xhr) { - if (xhr.responseText.length === 0 && deserialize === JSON.parse) { - return null - } else { - return xhr.responseText - } - }; - xhrOptions.method = (xhrOptions.method || "GET").toUpperCase(); - xhrOptions.url = parameterizeUrl(xhrOptions.url, xhrOptions.data); - xhrOptions = bindData(xhrOptions, xhrOptions.data, serialize); - xhrOptions.onload = xhrOptions.onerror = function(e) { - try { - e = e || event; - var unwrap = (e.type === "load" ? xhrOptions.unwrapSuccess : xhrOptions.unwrapError) || identity; - var response = unwrap(deserialize(extract(e.target, xhrOptions)), e.target); - if (e.type === "load") { - if (isArray(response) && xhrOptions.type) { - forEach(response, function (res, i) { - response[i] = new xhrOptions.type(res); - }); - } else if (xhrOptions.type) { - response = new xhrOptions.type(response); - } - deferred.resolve(response) - } else { - deferred.reject(response) - } + m.request = function (options) { + if (options.background !== true) m.startComputation() + var deferred = new Deferred() + var isJSONP = options.dataType && + options.dataType.toLowerCase() === "jsonp" - deferred[e.type === "load" ? "resolve" : "reject"](response); - } - catch (e) { - deferred.reject(e); - } - finally { - if (xhrOptions.background !== true) m.endComputation() + var serialize, deserialize, extract + + if (isJSONP) { + serialize = options.serialize = + deserialize = options.deserialize = identity + + extract = function (jsonp) { return jsonp.responseText } + } else { + serialize = options.serialize = options.serialize || JSON.stringify + + deserialize = options.deserialize = + options.deserialize || JSON.parse + extract = options.extract || function (xhr) { + if (xhr.responseText.length || deserialize !== JSON.parse) { + return xhr.responseText + } else { + return null + } } } - ajax(xhrOptions); - deferred.promise = propify(deferred.promise, xhrOptions.initialValue); - return deferred.promise; - }; + options.method = (options.method || "GET").toUpperCase() + options.url = parameterizeUrl(options.url, options.data) + bindData(options, options.data, serialize) + options.onload = options.onerror = function (ev) { + try { + ev = ev || event + var response = deserialize(extract(ev.target, options)) + if (ev.type === "load") { + if (options.unwrapSuccess) { + response = options.unwrapSuccess(response, ev.target) + } - //testing API - m.deps = function(mock) { - initialize(window = mock || window); - return window; - }; - //for internal testing only, do not use `m.deps.factory` - m.deps.factory = app; + if (isArray(response) && options.type) { + forEach(response, function (res, i) { + response[i] = new options.type(res) + }) + } else if (options.type) { + response = new options.type(response) + } - return m; -})(typeof window !== "undefined" ? window : {}); + deferred.resolve(response) + } else { + if (options.unwrapError) { + response = options.unwrapError(response, ev.target) + } -if (typeof module === "object" && module != null && module.exports) module.exports = m; -else if (typeof define === "function" && define.amd) define(function() { return m }); + deferred.reject(response) + } + } catch (e) { + deferred.reject(e) + } finally { + if (options.background !== true) m.endComputation() + } + } + + ajax(options) + deferred.promise = propify(deferred.promise, options.initialValue) + return deferred.promise + } + + return m +}) diff --git a/test-deps/mock.js b/test-deps/mock.js index 9d6f2131..a54a222b 100644 --- a/test-deps/mock.js +++ b/test-deps/mock.js @@ -45,6 +45,9 @@ window.mock = (function () { "use strict" var window = {} + + window.window = window + var document = window.document = { // FIXME: add document.createRange().createContextualFragment() @@ -136,7 +139,7 @@ window.mock = (function () { name = name.toLowerCase() var out = [] - function traverse(node){ + function traverse(node) { if (node.childNodes && node.childNodes.length > 0) { node.childNodes.forEach(function (curr) { if (curr.nodeName.toLowerCase() === name) { @@ -156,7 +159,7 @@ window.mock = (function () { window.scrollTo = function () {} - ;(function (window) { + ;(function () { // This is an actual conforming implementation of the // requestAnimationFrame spec, with the nonstandard extension of // rAF.$resolve for running the callbacks. It works in Node and the @@ -212,7 +215,7 @@ window.mock = (function () { } window.requestAnimationFrame = requestAnimationFrame - })(window) + })() window.XMLHttpRequest = (function () { function Request() { diff --git a/test/isolation-test.html b/test/isolation-test.html new file mode 100644 index 00000000..d566c810 --- /dev/null +++ b/test/isolation-test.html @@ -0,0 +1,8 @@ + + + + + + +

Open the console to see the test report

+ diff --git a/test/isolation-test.js b/test/isolation-test.js new file mode 100644 index 00000000..80f89f66 --- /dev/null +++ b/test/isolation-test.js @@ -0,0 +1,159 @@ +/* global m, test, mock */ +(function () { + "use strict" + + m.deps(mock.window) + + test(function () { // eslint-disable-line max-statements + var root = mock.document.createElement("div") + var retain = false + var flag = true + var loaded1 = null + var loaded2 = null + var loaded1a = null + var loaded2a = null + + var Comp1 = { + controller: function () { + loaded1 = true + this.onunload = function () { + loaded1 = false + } + }, + view: function () { + if (retain) { + return {subtree: "retain"} + } else { + return m("a", { + config: function (el, init, ctx) { + if (!init) { + loaded1a = true + ctx.onunload = function () { + loaded1a = false + } + } + } + }) + } + } + } + + var Comp2 = { + controller: function () { + loaded2 = true + this.onunload = function () { + loaded2 = false + } + }, + view: function () { + if (retain) { + return {subtree: "retain"} + } else { + return m("b", { + config: function (el, init, ctx) { + if (!init) { + loaded2a = true + ctx.onunload = function () { + loaded2a = false + } + } + } + }) + } + } + } + + var Root = { + view: function () { + return flag ? Comp1 : Comp2 + } + } + + m.mount(root, Root) + + mock.requestAnimationFrame.$resolve() + + // loaded 1 + var result1 = loaded1 === true && + loaded2 === null && + loaded1a === true && + loaded2a === null + + retain = true + m.redraw(true) + mock.requestAnimationFrame.$resolve() + + // retained + var result2 = loaded1 === true && + loaded2 === null && + loaded1a === true && + loaded2a === null + + flag = false + m.redraw(true) + mock.requestAnimationFrame.$resolve() + + // loaded 2 while retained: both controllers are alive at the same time + // because dom element is retained + var result3 = loaded1 === true && + loaded2 === true && + loaded1a === true && + loaded2a === null + + retain = false + m.redraw(true) + mock.requestAnimationFrame.$resolve() + + // unretained, i.e. 2 is now dynamic + var result4 = loaded1 === false && + loaded2 === true && + loaded1a === false && + loaded2a === true + + flag = true + m.redraw(true) + mock.requestAnimationFrame.$resolve() + + // loaded 1 while dynamic + var result5 = loaded1 === true && + loaded2 === false && + loaded1a === true && + loaded2a === false + + return result1 && result2 && result3 && result4 && result5 + }) + + /* + test(function() { + var root = mock.document.createElement("div") + var redraws = 0, data + var Root = { + view: function() { + return Comp + } + } + + var Comp = { + controller: function() { + this.foo = m.request({method: "GET", url: "/foo"}) + }, + view: function(ctrl) { + redraws++ + data = ctrl.foo() + return m("div") + } + } + + m.mount(root, Root) + + mock.requestAnimationFrame.$resolve() + mock.XMLHttpRequest.$instances.pop().onreadystatechange() + + return redraws == 1 && data.url == "/foo" + }) + */ + + test.print(function (value) { + console.log(value) // eslint-disable-line no-console + }) +})() diff --git a/test/mithril.deferred.js b/test/mithril.deferred.js index a2efb1af..c9fe9a38 100644 --- a/test/mithril.deferred.js +++ b/test/mithril.deferred.js @@ -295,7 +295,7 @@ describe("m.deferred()", function () { prmA.promise.then(function (A) { return prmB.promise - }).then(function(B) { + }).then(function (B) { expect(B).to.equal("B") }) }) @@ -303,7 +303,7 @@ describe("m.deferred()", function () { var d = m.deferred() d.resolve(5) d.resolve(6) - d.promise.then(function(v) { + d.promise.then(function (v) { expect(v).to.equal(5) }) }) diff --git a/test/mithril.trust.js b/test/mithril.trust.js index c64adb4c..015cd318 100644 --- a/test/mithril.trust.js +++ b/test/mithril.trust.js @@ -56,13 +56,13 @@ describe("m.trust()", function () { it("works with trusted content in div", function () { var root = document.createElement("div") - m.render(root, m('div', [ - m('p', '©'), - m('p', m.trust('©')), - m.trust('©'), + m.render(root, m("div", [ + m("p", "©"), + m("p", m.trust("©")), + m.trust("©"), ])) expect(root.innerHTML).to.equal("

&copy;

©

©
") }) - + }) }) diff --git a/tests/index.html b/tests/index.html index f1e4baee..9d7f08f4 100644 --- a/tests/index.html +++ b/tests/index.html @@ -5,4 +5,4 @@ -

Open the console to see the test report

\ No newline at end of file +

Open the console to see the test report

diff --git a/tests/input-cursor.html b/tests/input-cursor.html deleted file mode 100644 index 8611e06e..00000000 --- a/tests/input-cursor.html +++ /dev/null @@ -1,48 +0,0 @@ -

Typing in the fields below should not move the cursor to the end of the input. Especially in Chrome

-

All inputs should update with the same value

-

Typing in an input should not prevent it from being updated by other inputs

-
- - diff --git a/tests/isolation-test.html b/tests/isolation-test.html deleted file mode 100644 index 210d2693..00000000 --- a/tests/isolation-test.html +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - -

Open the console to see the test report

- \ No newline at end of file diff --git a/tests/mithril-tests.js b/tests/mithril-tests.js index ec24f976..a5042faa 100644 --- a/tests/mithril-tests.js +++ b/tests/mithril-tests.js @@ -1,57 +1,127 @@ -function testMithril(mock) { - m.deps(mock) +/* global m, test, mock */ +(function () { // eslint-disable-line max-statements + "use strict" - //m - test(function() {return m.version().constructor === String}) - test(function() {return m("div").tag === "div"}) - test(function() {return m(".foo").tag === "div"}) - test(function() {return m(".foo").attrs.className === "foo"}) - test(function() {return m("[title=bar]").tag === "div"}) - test(function() {return m("[title=bar]").attrs.title === "bar"}) - test(function() {return m("[title=\'bar\']").attrs.title === "bar"}) - test(function() {return m("[title=\"bar\"]").attrs.title === "bar"}) - test(function() {return m("div", "test").children[0] === "test"}) - test(function() {return m("div", "test", "test2").children[1] === "test2"}) - test(function() {return m("div", ["test"]).children[0] === "test"}) - test(function() {return m("div", {title: "bar"}, "test").attrs.title === "bar"}) - test(function() {return m("div", {title: "bar"}, "test").children[0] === "test"}) - test(function() {return m("div", {title: "bar"}, ["test"]).children[0] === "test"}) - test(function() {return m("div", {title: "bar"}, m("div")).children[0].tag === "div"}) - test(function() {return m("div", {title: "bar"}, [m("div")]).children[0].tag === "div"}) - test(function() {return m("div", {title: "bar"}, "test0", "test1", "test2", "test3").children[3] === "test3"}) // splat - test(function() {return m("div", {title: "bar"}, m("div"), m("i"), m("span")).children[2].tag === "span"}) - test(function() {return m("div", ["a", "b"]).children.length === 2}) - test(function() {return m("div", [m("div")]).children[0].tag === "div"}) - test(function() {return m("div", m("div")).children[0].tag === "div"}) //yes, this is expected behavior: see method signature - test(function() {return m("div", [undefined]).tag === "div"}) - test(function() {return m("div", [{foo: "bar"}])}) //as long as it doesn't throw errors, it's fine - test(function() {return m("svg", [m("g")])}) - test(function() {return m("svg", [m("a[href='http://google.com']")])}) - test(function() {return m(".foo", {"class": "bar"}).attrs["class"] === "foo bar"}) - test(function() {return m(".foo", {className: "bar"}).attrs.className === "foo bar"}) - test(function() {return m(".foo", {className: ""}).attrs.className === "foo"}) - test(function() {return m("div", {className: ""}).attrs.className === ""}) //https://github.com/lhorie/mithril.js/issues/382 and 512 - test(function() {return m("div", {"class": ""}).attrs.className === undefined}) - test(function() {return m("div", {className: ""}).attrs["class"] === undefined}) - test(function() {return m("div", {"class": ""}).attrs["class"] === ""}) - test(function() {return m("div", [1, 2, 3], 4).children.length === 2}) - test(function() {return m("div", [1, 2, 3], 4).children[0].length === 3}) - test(function() {return m("div", [1, 2, 3], 4).children[1] === 4}) - test(function() {return m("div", [1, 2, 3]).children.length === 3}) - test(function() {return m("div", [1, 2, 3], [4, 5, 6, 7]).children.length === 2}) - test(function() {return m("div", [1, 2, 3], [4, 5, 6, 7]).children[0].length === 3}) - test(function() {return m("div", [1, 2, 3], [4, 5, 6, 7]).children[1].length === 4}) - test(function() {return m("div", [1], [2], [3]).children.length === 3}) - test(function() { - //class changes shouldn't trigger dom recreation - var v1 = m(".foo", {"class": "", onclick: function() {}}) - var v2 = m(".foo", {"class": "bar", onclick: function() {}}) + m.deps(mock.window) + + // m + test(function () { return typeof m.version() === "string" }) + test(function () { return m("div").tag === "div" }) + test(function () { return m(".foo").tag === "div" }) + test(function () { return m(".foo").attrs.className === "foo" }) + test(function () { return m("[title=bar]").tag === "div" }) + test(function () { return m("[title=bar]").attrs.title === "bar" }) + test(function () { return m("[title=\'bar\']").attrs.title === "bar" }) + test(function () { return m("[title=\"bar\"]").attrs.title === "bar" }) + test(function () { return m("div", "test").children[0] === "test" }) + + test(function () { + return m("div", "test", "test2").children[1] === "test2" + }) + + test(function () { return m("div", ["test"]).children[0] === "test" }) + + test(function () { + return m("div", {title: "bar"}, "test").attrs.title === "bar" + }) + + test(function () { + return m("div", {title: "bar"}, "test").children[0] === "test" + }) + + test(function () { + return m("div", {title: "bar"}, ["test"]).children[0] === "test" + }) + + test(function () { + return m("div", {title: "bar"}, m("div")).children[0].tag === "div" + }) + + test(function () { + return m("div", {title: "bar"}, [m("div")]).children[0].tag === "div" + }) + + // splat + test(function () { + var node = m("div", {title: "bar"}, "test0", "test1", "test2", "test3") + return node.children[3] === "test3" + }) + + test(function () { + var node = m("div", {title: "bar"}, m("div"), m("i"), m("span")) + return node.children[2].tag === "span" + }) + + test(function () { return m("div", ["a", "b"]).children.length === 2 }) + test(function () { return m("div", [m("div")]).children[0].tag === "div" }) + + // yes, this is expected behavior: see method signature + test(function () { return m("div", m("div")).children[0].tag === "div" }) + + test(function () { return m("div", [undefined]).tag === "div" }) + + // as long as it doesn't throw errors, it's fine + test(function () { return m("div", [{foo: "bar"}]) }) + + test(function () { return m("svg", [m("g")]) }) + test(function () { return m("svg", [m("a[href='http://google.com']")]) }) + + test(function () { + return m(".foo", {class: "bar"}).attrs.class === "foo bar" + }) + + test(function () { + return m(".foo", {className: "bar"}).attrs.className === "foo bar" + }) + + test(function () { + return m(".foo", {className: ""}).attrs.className === "foo" + }) + + // https://github.com/lhorie/mithril.js/issues/382 and 512 + test(function () { + return m("div", {className: ""}).attrs.className === "" + }) + + test(function () { + return m("div", {class: ""}).attrs.className === undefined + }) + + test(function () { + return m("div", {className: ""}).attrs.class === undefined + }) + + test(function () { return m("div", {class: ""}).attrs.class === "" }) + test(function () { return m("div", [1, 2, 3], 4).children.length === 2 }) + test(function () { return m("div", [1, 2, 3], 4).children[0].length === 3 }) + test(function () { return m("div", [1, 2, 3], 4).children[1] === 4 }) + test(function () { return m("div", [1, 2, 3]).children.length === 3 }) + + test(function () { + return m("div", [1, 2, 3], [4, 5, 6, 7]).children.length === 2 + }) + + test(function () { + return m("div", [1, 2, 3], [4, 5, 6, 7]).children[0].length === 3 + }) + + test(function () { + return m("div", [1, 2, 3], [4, 5, 6, 7]).children[1].length === 4 + }) + + test(function () { return m("div", [1], [2], [3]).children.length === 3 }) + + test(function () { + // class changes shouldn't trigger dom recreation + var v1 = m(".foo", {class: "", onclick: function () {}}) + var v2 = m(".foo", {class: "bar", onclick: function () {}}) return Object.keys(v1.attrs).join() === Object.keys(v2.attrs).join() }) - test(function() { - //m should proxy object first arg to m.component + + test(function () { + // m should proxy object first arg to m.component var component = { - controller: function(args) { + controller: function (args) { this.args = args }, view: function () { @@ -65,16 +135,16 @@ function testMithril(mock) { return c1.args === args && c1.args === c2.args }) - //m.mount - test(function() { + // m.mount + test(function () { var root = mock.document.createElement("div") var whatever = 1 var app = { - view: function() { + view: function () { return [ - whatever % 2 ? m('span', '% 2') : undefined, - m('div', 'bugs'), - m('a') + whatever % 2 ? m("span", "% 2") : undefined, + m("div", "bugs"), + m("a") ] } } @@ -91,39 +161,44 @@ function testMithril(mock) { return root.childNodes.length }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() var root1 = mock.document.createElement("div") var mod1 = m.mount(root1, { - controller: function() {this.value = "test1"}, - view: function(ctrl) {return ctrl.value} + controller: function () { this.value = "test1" }, + view: function (ctrl) { return ctrl.value } }) var root2 = mock.document.createElement("div") var mod2 = m.mount(root2, { - controller: function() {this.value = "test2"}, - view: function(ctrl) {return ctrl.value} + controller: function () { this.value = "test2" }, + view: function (ctrl) { return ctrl.value } }) mock.requestAnimationFrame.$resolve() - return (root1.childNodes[0].nodeValue === "test1" && root2.childNodes[0].nodeValue === "test2") - && (mod1.value && mod1.value === "test1") && (mod2.value && mod2.value === "test2") + return (root1.childNodes[0].nodeValue === "test1" && + root2.childNodes[0].nodeValue === "test2") && + (mod1.value && mod1.value === "test1") && + (mod2.value && mod2.value === "test2") }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var unloaded = false + m.mount(root, { - controller: function() { + controller: function () { this.value = "test1" - this.onunload = function() { + this.onunload = function () { unloaded = true } }, - view: function(ctrl) {return ctrl.value} + view: function (ctrl) { return ctrl.value } }) mock.requestAnimationFrame.$resolve() @@ -134,15 +209,16 @@ function testMithril(mock) { return unloaded }) - test(function() { - //component should pass args to both controller and view + + test(function () { + // component should pass args to both controller and view mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var slot1, slot2 var component = { - controller: function(options) {slot1 = options.a}, - view: function(ctrl, options) {slot2 = options.a} + controller: function (options) { slot1 = options.a }, + view: function (ctrl, options) { slot2 = options.a } } m.mount(root, m.component(component, {a: 1})) @@ -150,14 +226,15 @@ function testMithril(mock) { return slot1 === 1 && slot2 === 1 }) - test(function() { - //component should work without controller + + test(function () { + // component should work without controller mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var slot2 var component = { - view: function(ctrl, options) {slot2 = options.a} + view: function (ctrl, options) { slot2 = options.a } } m.mount(root, m.component(component, {a: 1})) @@ -165,26 +242,31 @@ function testMithril(mock) { return slot2 === 1 }) - test(function() { - //component controller should only run once + + test(function () { + // component controller should only run once mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") - var count1 = 0, count2 = 0 - var component = { - view: function() { - return sub - } - } + var count1 = 0 + var count2 = 0 + var sub = { - controller: function() { + controller: function () { count1++ }, - view: function() { + view: function () { count2++ return m("div", "test") } } + + var component = { + view: function () { + return sub + } + } + m.mount(root, component) mock.requestAnimationFrame.$resolve() @@ -195,35 +277,43 @@ function testMithril(mock) { return count1 === 1 && count2 === 2 }) - test(function() { - //sub component controller should only run once + + test(function () { + // sub component controller should only run once mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") - var count1 = 0, count2 = 0, count3 = 0, count4 = 0 - var component = { - view: function() { - return sub - } - } - var sub = { - controller: function() { - count1++ - }, - view: function() { - count2++ - return subsub - } - } + var count1 = 0 + var count2 = 0 + var count3 = 0 + var count4 = 0 + var subsub = { - controller: function() { + controller: function () { count3++ }, - view: function() { + view: function () { count4++ return m("div", "test") } } + + var sub = { + controller: function () { + count1++ + }, + view: function () { + count2++ + return subsub + } + } + + var component = { + view: function () { + return sub + } + } + m.mount(root, component) mock.requestAnimationFrame.$resolve() @@ -234,26 +324,30 @@ function testMithril(mock) { return count1 === 1 && count2 === 2 && count3 === 1 && count4 === 2 }) - test(function() { - //keys in components should work + + test(function () { + // keys in components should work mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] + + var sub = { + controller: function () {}, + view: function () { + return m("div") + } + } + var component = { - controller: function() {}, - view: function() { - return list.map(function(i) { + controller: function () {}, + view: function () { + return list.map(function (i) { return m.component(sub, {key: i}) }) } } - var sub = { - controller: function() {}, - view: function() { - return m("div") - } - } + m.mount(root, component) var firstBefore = root.childNodes[0] @@ -269,23 +363,23 @@ function testMithril(mock) { return firstBefore === firstAfter }) - test(function() { + test(function () { //string keys in components should work mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] var component = { - controller: function() {}, - view: function() { - return list.map(function(i) { + controller: function () {}, + view: function () { + return list.map(function (i) { return m.component(sub, {key: "key" + i}) }) } } var sub = { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return m("div") } } @@ -304,107 +398,35 @@ function testMithril(mock) { return firstBefore === firstAfter }) - test(function() { + test(function () { //keys in subcomponents should work mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] - var component = { - controller: function() {}, - view: function() { - return list.map(function(i) { - return m.component(sub, {key: i}) - }) - } - } - var sub = { - view: function() { - return subsub - } - } + var subsub = { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return m("div") } } - m.mount(root, component) - var firstBefore = root.childNodes[0] - - mock.requestAnimationFrame.$resolve() - - list.reverse() - m.redraw(true) - - mock.requestAnimationFrame.$resolve() - - var firstAfter = root.childNodes[2] - - return firstBefore === firstAfter - }) - test(function() { - //keys in components should work even if component internally messes them up - mock.requestAnimationFrame.$resolve() - - var root = mock.document.createElement("div") - var list = [1, 2, 3] - var component = { - controller: function() {}, - view: function() { - return list.map(function(i) { - return m.component(sub, {key: i}) - }) - } - } var sub = { - controller: function() {}, - view: function() { - return m("div", {key: 1}) - } - } - m.mount(root, component) - - var firstBefore = root.childNodes[0] - - mock.requestAnimationFrame.$resolve() - - list.reverse() - m.redraw(true) - - mock.requestAnimationFrame.$resolve() - - var firstAfter = root.childNodes[2] - - return firstBefore === firstAfter - }) - test(function() { - //keys in subcomponents should work even if component internally messes them up - mock.requestAnimationFrame.$resolve() - - var root = mock.document.createElement("div") - var list = [1, 2, 3] - var component = { - controller: function() {}, - view: function() { - return list.map(function(i) { - return m.component(sub, {key: i}) - }) - } - } - var sub = { - controller: function() {}, - view: function() { + view: function () { return subsub } } - var subsub = { - controller: function() {}, - view: function() { - return m("div", {key: 1}) + + var component = { + controller: function () {}, + view: function () { + return list.map(function (i) { + return m.component(sub, {key: i}) + }) } } + m.mount(root, component) var firstBefore = root.childNodes[0] @@ -420,26 +442,118 @@ function testMithril(mock) { return firstBefore === firstAfter }) - test(function() { - //component identity should stay intact if components are descendants of keyed elements + + test(function () { + // keys in components should work even if component internally messes + // them up mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] + + var sub = { + controller: function () {}, + view: function () { + return m("div", {key: 1}) + } + } + var component = { - controller: function() {}, - view: function() { - return list.map(function(i) { + controller: function () {}, + view: function () { + return list.map(function (i) { + return m.component(sub, {key: i}) + }) + } + } + + m.mount(root, component) + + var firstBefore = root.childNodes[0] + + mock.requestAnimationFrame.$resolve() + + list.reverse() + m.redraw(true) + + mock.requestAnimationFrame.$resolve() + + var firstAfter = root.childNodes[2] + + return firstBefore === firstAfter + }) + + test(function () { + // keys in subcomponents should work even if component internally messes + // them up + mock.requestAnimationFrame.$resolve() + + var root = mock.document.createElement("div") + var list = [1, 2, 3] + + var subsub = { + controller: function () {}, + view: function () { + return m("div", {key: 1}) + } + } + + var sub = { + controller: function () {}, + view: function () { + return subsub + } + } + + var component = { + controller: function () {}, + view: function () { + return list.map(function (i) { + return m.component(sub, {key: i}) + }) + } + } + + m.mount(root, component) + + var firstBefore = root.childNodes[0] + + mock.requestAnimationFrame.$resolve() + + list.reverse() + m.redraw(true) + + mock.requestAnimationFrame.$resolve() + + var firstAfter = root.childNodes[2] + + return firstBefore === firstAfter + }) + + test(function () { + // component identity should stay intact if components are descendants + // of keyed elements + mock.requestAnimationFrame.$resolve() + + var root = mock.document.createElement("div") + var list = [1, 2, 3] + + var sub = { + controller: function () {}, + view: function () { + return m("div") + } + } + + var component = { + controller: function () {}, + view: function () { + return list.map(function (i) { return m("div", {key: i}, sub) }) } } - var sub = { - controller: function() {}, - view: function() { - return m("div") - } - } + m.mount(root, component) var firstBefore = root.childNodes[0].childNodes[0] @@ -455,32 +569,38 @@ function testMithril(mock) { return firstBefore === firstAfter }) - test(function() { - //subcomponent identity should stay intact if components are descendants of keyed elements + + test(function () { + // subcomponent identity should stay intact if components are + // descendants of keyed elements mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] + + var subsub = { + controller: function () {}, + view: function () { + return m("div") + } + } + + var sub = { + controller: function () {}, + view: function () { + return subsub + } + } + var component = { - controller: function() {}, - view: function() { - return list.map(function(i) { + controller: function () {}, + view: function () { + return list.map(function (i) { return m("div", {key: i}, sub) }) } } - var sub = { - controller: function() {}, - view: function() { - return subsub - } - } - var subsub = { - controller: function() {}, - view: function() { - return m("div") - } - } + m.mount(root, component) var firstBefore = root.childNodes[0].childNodes[0] @@ -496,31 +616,35 @@ function testMithril(mock) { return firstBefore === firstAfter }) - test(function() { - //component should call onunload when removed from template + + test(function () { + // component should call onunload when removed from template mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] var unloaded + + var sub = { + controller: function (opts) { + this.onunload = function () { + unloaded = opts.key + } + }, + view: function () { + return m("div") + } + } + var component = { - controller: function() {}, - view: function() { - return list.map(function(i) { + controller: function () {}, + view: function () { + return list.map(function (i) { return m.component(sub, {key: i}) }) } } - var sub = { - controller: function(opts) { - this.onunload = function() { - unloaded = opts.key - } - }, - view: function() { - return m("div") - } - } + m.mount(root, component) mock.requestAnimationFrame.$resolve() @@ -532,41 +656,46 @@ function testMithril(mock) { return unloaded === 3 }) - test(function() { - //subcomponent should call onunload when removed from template + + test(function () { + // subcomponent should call onunload when removed from template mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] var unloaded1, unloaded2 + + var subsub = { + controller: function (opts) { + this.onunload = function () { + unloaded2 = opts.key + } + }, + view: function () { + return m("div") + } + } + + var sub = { + controller: function (opts) { + this.onunload = function () { + unloaded1 = opts.key + } + }, + view: function (ctrl, opts) { + return m.component(subsub, {key: opts.key}) + } + } + var component = { - controller: function() {}, - view: function() { - return list.map(function(i) { + controller: function () {}, + view: function () { + return list.map(function (i) { return m.component(sub, {key: i}) }) } } - var sub = { - controller: function(opts) { - this.onunload = function() { - unloaded1 = opts.key - } - }, - view: function(ctrl, opts) { - return m.component(subsub, {key: opts.key}) - } - } - var subsub = { - controller: function(opts) { - this.onunload = function() { - unloaded2 = opts.key - } - }, - view: function() { - return m("div") - } - } + m.mount(root, component) mock.requestAnimationFrame.$resolve() @@ -578,91 +707,112 @@ function testMithril(mock) { return unloaded1 === 3 && unloaded2 === 3 }) - test(function() { - //calling m.redraw synchronously from controller constructor should not trigger extra redraws + + test(function () { + // calling m.redraw synchronously from controller constructor should not + // trigger extra redraws mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var count = 0 - var component = { - controller: function() {}, - view: function() { - return sub - } - } + var sub = { - controller: function() { + controller: function () { m.redraw() }, - view: function() { + view: function () { count++ return m("div") } } + + var component = { + controller: function () {}, + view: function () { + return sub + } + } + m.mount(root, component) mock.requestAnimationFrame.$resolve() return count === 1 }) - test(function() { - //calling m.redraw synchronously from controller constructor should not trigger extra redraws + + test(function () { + // calling m.redraw synchronously from controller constructor should not + // trigger extra redraws mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var count = 0 - var component = { - controller: function() {}, - view: function() { - return sub - } - } - var sub = { - controller: function() {}, - view: function() { - return subsub - } - } + var subsub = { - controller: function() { + controller: function () { m.redraw() }, - view: function() { + view: function () { count++ return m("div") } } + + var sub = { + controller: function () {}, + view: function () { + return subsub + } + } + + var component = { + controller: function () {}, + view: function () { + return sub + } + } + m.mount(root, component) mock.requestAnimationFrame.$resolve() return count === 1 }) - test(function() { - //calling preventDefault from component's onunload should prevent route change + + test(function () { + // calling preventDefault from component's onunload should prevent route + // change mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var loaded = false var testEnabled = true - var component = { - controller: function() {}, - view: function() { - return sub - } - } + var sub = { - controller: function() { - this.onunload = function(e) {if (testEnabled) e.preventDefault()} + controller: function () { + this.onunload = function (e) { + if (testEnabled) e.preventDefault() + } }, - view: function() { + view: function () { return m("div") } } + + var component = { + controller: function () {}, + view: function () { + return sub + } + } + m.route(root, "/a", { "/a": component, - "/b": {controller: function() {loaded = true}, view: function() {}} + "/b": { + controller: function () { loaded = true }, + view: function () {} + } }) mock.requestAnimationFrame.$resolve() @@ -674,115 +824,147 @@ function testMithril(mock) { return loaded === false }) - test(function() { - //calling preventDefault from subcomponent's onunload should prevent route change + + test(function () { + // calling preventDefault from subcomponent's onunload should prevent + // route change mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var loaded = false var testEnabled = true - var component = { - controller: function() {}, - view: function() { - return sub + + var subsub = { + controller: function () { + this.onunload = function (e) { + if (testEnabled) e.preventDefault() + } + }, + view: function () { + return m("div") } } + var sub = { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return subsub } } + + var component = { + controller: function () {}, + view: function () { + return sub + } + } + + m.route(root, "/a", { + "/a": component, + "/b": { + controller: function () { loaded = true }, + view: function () {} + } + }) + + mock.requestAnimationFrame.$resolve() + + m.route("/b") + + mock.requestAnimationFrame.$resolve() + testEnabled = false + + return loaded === false + }) + + test(function () { + // calling preventDefault from non-curried component's onunload should + // prevent route change + mock.requestAnimationFrame.$resolve() + mock.location.search = "?" + + var root = mock.document.createElement("div") + var loaded = false + var testEnabled = true + + var sub = { + controller: function () { + this.onunload = function (e) { + if (testEnabled) e.preventDefault() + } + }, + view: function () { + return m("div") + } + } + + var component = { + controller: function () {}, + view: function () { + return sub + } + } + + m.route(root, "/a", { + "/a": component, + "/b": { + controller: function () { loaded = true }, + view: function () {} + } + }) + + mock.requestAnimationFrame.$resolve() + + m.route("/b") + + mock.requestAnimationFrame.$resolve() + testEnabled = false + + return loaded === false + }) + + test(function () { + // calling preventDefault from non-curried subcomponent's onunload + // should prevent route change + mock.requestAnimationFrame.$resolve() + mock.location.search = "?" + + var root = mock.document.createElement("div") + var loaded = false + var testEnabled = true + var subsub = { - controller: function() { - this.onunload = function(e) {if (testEnabled) e.preventDefault()} + controller: function () { + this.onunload = function (e) { + if (testEnabled) e.preventDefault() + } }, - view: function() { + view: function () { return m("div") } } - m.route(root, "/a", { - "/a": component, - "/b": {controller: function() {loaded = true}, view: function() {}} - }) - mock.requestAnimationFrame.$resolve() - - m.route("/b") - - mock.requestAnimationFrame.$resolve() - testEnabled = false - - return loaded === false - }) - test(function() { - //calling preventDefault from non-curried component's onunload should prevent route change - mock.requestAnimationFrame.$resolve() - mock.location.search = "?" - - var root = mock.document.createElement("div") - var loaded = false - var testEnabled = true - var component = { - controller: function() {}, - view: function() { - return sub - } - } var sub = { - controller: function() { - this.onunload = function(e) {if (testEnabled) e.preventDefault()} - }, - view: function() { - return m("div") - } - } - m.route(root, "/a", { - "/a": component, - "/b": {controller: function() {loaded = true}, view: function() {}} - }) - - mock.requestAnimationFrame.$resolve() - - m.route("/b") - - mock.requestAnimationFrame.$resolve() - testEnabled = false - - return loaded === false - }) - test(function() { - //calling preventDefault from non-curried subcomponent's onunload should prevent route change - mock.requestAnimationFrame.$resolve() - mock.location.search = "?" - - var root = mock.document.createElement("div") - var loaded = false - var testEnabled = true - var component = { - controller: function() {}, - view: function() { - return sub - } - } - var sub = { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return subsub } } - var subsub = { - controller: function() { - this.onunload = function(e) {if (testEnabled) e.preventDefault()} - }, - view: function() { - return m("div") + + var component = { + controller: function () {}, + view: function () { + return sub } } + m.route(root, "/a", { "/a": component, - "/b": {controller: function() {loaded = true}, view: function() {}} + "/b": { + controller: function () { loaded = true }, + view: function () {} + } }) mock.requestAnimationFrame.$resolve() @@ -794,44 +976,50 @@ function testMithril(mock) { return loaded === false }) - test(function() { + + test(function () { // nested components under keyed components should render mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var count = 0 - var App = { - controller: function() {}, - view: function() { - return m('.outer', [ - m('.inner', m.component(CommentList, { list: [1, 2, 3] })) - ]) + + var Reply = { + controller: function () {}, + view: function () { + count++ + return m(".reply") } } + var CommentList = { - controller: function() {}, - view: function(ctrl, props) { - return m('.list', props.list.map(function(i) { - return m('.comment', [ + controller: function () {}, + view: function (ctrl, props) { + return m(".list", props.list.map(function (i) { + return m(".comment", [ m.component(Reply, {key: i}) ]) })) } } - var Reply = { - controller: function() {}, - view: function() { - count++ - return m(".reply") + + var App = { + controller: function () {}, + view: function () { + return m(".outer", [ + m(".inner", m.component(CommentList, {list: [1, 2, 3]})) + ]) } } + m.mount(root, App) mock.requestAnimationFrame.$resolve() return count === 3 }) - test(function() { + + test(function () { // a route change should initialize a component's controller mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -840,25 +1028,25 @@ function testMithril(mock) { var countA = 0 var countB = 0 var subA = { - controller: function(){ countA += 1 }, - view: function() { return m("div") } + controller: function (){ countA += 1 }, + view: function () { return m("div") } } var subB = { - controller: function() { countB += 1 }, - view: function() { return m("div") } + controller: function () { countB += 1 }, + view: function () { return m("div") } } m.route(root, "/a", { "/a": { view: function () { - return m('.page-a', [ - m('h1'), m.component(subA, { x: 11 }) + return m(".page-a", [ + m("h1"), m.component(subA, {x: 11}) ]) } }, "/b": { - view: function() { - return m('.page-b', [ - m('h2'), m.component(subB, { y: 22 }) + view: function () { + return m(".page-b", [ + m("h2"), m.component(subB, {y: 22}) ]) } } @@ -876,28 +1064,33 @@ function testMithril(mock) { return countA === 2 && countB === 1 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") - var component = {}, unloaded = false - component.controller = function() { - this.onunload = function() {unloaded = true} + var component = {} + var unloaded = false + component.controller = function () { + this.onunload = function () { unloaded = true } } - component.view = function() {} + component.view = function () {} m.mount(root, component) - m.mount(root, {controller: function() {}, view: function() {}}) + m.mount(root, {controller: function () {}, view: function () {}}) return unloaded === true }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var initCount = 0 var component = {} - component.view = function() { - return m("div", {config: function(el, init) { - if (!init) initCount++ - }}) + component.view = function () { + return m("div", { + config: function (el, init) { + if (!init) initCount++ + } + }) } m.mount(root, component) @@ -909,7 +1102,8 @@ function testMithril(mock) { return initCount === 1 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") var dom = mock.document.createElement("div") @@ -917,9 +1111,13 @@ function testMithril(mock) { var show = true var component = { - view: function() { + view: function () { return [ - m(".foo", {key: 1, config: test, onclick: function() {show = !show}}), + m(".foo", { + key: 1, + config: test, + onclick: function () { show = !show } + }), show ? m(".bar", {key: 2}) : null ] } @@ -947,28 +1145,29 @@ function testMithril(mock) { return root.childNodes.length === 3 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") var show = true var testcomponent = { - controller: function() {}, - view: function() { - return m('div', 'component'); + controller: function () {}, + view: function () { + return m("div", "component") } } var app = { - view: function() { + view: function () { return show ? [ - m('h1', '1'), + m("h1", "1"), testcomponent ] : [ - m('h1', '2') - ]; + m("h1", "2") + ] } - }; + } - m.mount(root, app); + m.mount(root, app) mock.requestAnimationFrame.$resolve() @@ -984,14 +1183,15 @@ function testMithril(mock) { return root.childNodes.length === 2 }) - test(function() { + + test(function () { // Components should not require a view mock.requestAnimationFrame.$resolve() mock.location.search = "?" var Component = { view: function () { - return m('.comp') + return m(".comp") } } @@ -999,8 +1199,8 @@ function testMithril(mock) { m.route.mode = "search" m.route(root, "/foo", { "/foo": { - view: function() { - return [ Component ] + view: function () { + return [Component] } } }) @@ -1009,34 +1209,41 @@ function testMithril(mock) { return root.childNodes[0].nodeName === "DIV" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/551 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/551 var root = mock.document.createElement("div") - var a = false, found = false, unloaded = false, redraws = 0 - var Root = { - view: function() { - return Comp - } - } + var a = false + var found = false + var unloaded = false + var redraws = 0 + var Comp = { - view: function() { + view: function () { redraws++ return m("div", {config: Comp.config}, [ - m("div", {onclick: function() { - a = !a - m.redraw(true) - found = root.childNodes[0].childNodes[1] - }}, "asd"), + m("div", { + onclick: function () { + a = !a + m.redraw(true) + found = root.childNodes[0].childNodes[1] + } + }, "asd"), a ? m("#a", "aaa") : null, "test" ]) }, - config: function(el, init, ctx) { - if (!init) ctx.onunload = function() { - unloaded = true - } + config: function (el, init, ctx) { + if (!init) ctx.onunload = function () { unloaded = true } } } + + var Root = { + view: function () { + return Comp + } + } + m.mount(root, Root) var target = root.childNodes[0].childNodes[0] @@ -1046,35 +1253,42 @@ function testMithril(mock) { return !unloaded && found.id === "a" && redraws === 3 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/551 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/551 var root = mock.document.createElement("div") - var a = false, found = false, unloaded = false, redraws = 0 - var Root = { - view: function() { - return Comp - } - } + var a = false + var found = false + var unloaded = false + var redraws = 0 + var Comp = { - view: function() { + view: function () { redraws++ return m("div", {config: Comp.config}, [ - m("div", {onclick: function() { - a = !a - m.redraw(true) - found = root.childNodes[0].childNodes[1] - m.redraw.strategy("none") - }}, "asd"), + m("div", { + onclick: function () { + a = !a + m.redraw(true) + found = root.childNodes[0].childNodes[1] + m.redraw.strategy("none") + } + }, "asd"), a ? m("#a", "aaa") : null, "test" ]) }, - config: function(el, init, ctx) { - if (!init) ctx.onunload = function() { - unloaded = true - } + config: function (el, init, ctx) { + if (!init) ctx.onunload = function () { unloaded = true } } } + + var Root = { + view: function () { + return Comp + } + } + m.mount(root, Root) var target = root.childNodes[0].childNodes[0] @@ -1084,13 +1298,14 @@ function testMithril(mock) { return !unloaded && found.id === "a" && redraws === 2 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") var redraws = 0 var Root = { - view: function() { + view: function () { redraws++ - return m("div", {onclick: function() {m.redraw(true)}}) + return m("div", {onclick: function () { m.redraw(true) }}) } } @@ -1103,38 +1318,43 @@ function testMithril(mock) { return redraws === 3 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/555 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/555 var root = mock.document.createElement("div") + var MyComponent = { - controller: function(args) { - this.name = args.name; + controller: function (args) { + this.name = args.name }, - view: function(ctrl) { - return m('div', ctrl.name); + view: function (ctrl) { + return m("div", ctrl.name) } } + var FooPage = { - view: function() { - return m('div', [ - m('a[href=/]', {config: m.route}, 'foo'), - m('a[href=/bar]', {config: m.route}, 'bar'), - m.component(MyComponent, {name: 'Jane'}) - ]); + view: function () { + return m("div", [ + m("a[href=/]", {config: m.route}, "foo"), + m("a[href=/bar]", {config: m.route}, "bar"), + m.component(MyComponent, {name: "Jane"}) + ]) } - }; + } + var BarPage = { - view: function() { - return m('div', [ - m('a[href=/]', {config: m.route}, 'foo'), - m('a[href=/bar]', {config: m.route}, 'bar'), - m.component(MyComponent, {name: 'Bob'}) - ]); + view: function () { + return m("div", [ + m("a[href=/]", {config: m.route}, "foo"), + m("a[href=/bar]", {config: m.route}, "bar"), + m.component(MyComponent, {name: "Bob"}) + ]) } - }; - m.route(root, '/', { - '/': FooPage, - '/bar': BarPage + } + + m.route(root, "/", { + "/": FooPage, + "/bar": BarPage }) mock.requestAnimationFrame.$resolve() @@ -1143,28 +1363,32 @@ function testMithril(mock) { mock.requestAnimationFrame.$resolve() - return root.childNodes[0].childNodes[2].childNodes[0].nodeValue === "Bob" + var parent = root.childNodes[0].childNodes[2].childNodes[0] + return parent.nodeValue === "Bob" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") - var redraws = 0, data - var Root = { - view: function() { - return Comp - } - } + var redraws = 0 + var data var Comp = { - controller: function() { + controller: function () { this.foo = m.request({method: "GET", url: "/foo"}) }, - view: function(ctrl) { + view: function (ctrl) { redraws++ data = ctrl.foo() return m("div") } } + var Root = { + view: function () { + return Comp + } + } + m.mount(root, Root) mock.requestAnimationFrame.$resolve() @@ -1176,39 +1400,41 @@ function testMithril(mock) { return redraws === 1 && data.url === "/foo" }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") - var redraws1 = 0, redraws2 = 0 - var Root = { - view: function() { - return m("div", [ - Comp1, - Comp2 - ]) - } - } + var redraws1 = 0 + var redraws2 = 0 + var Comp1 = { - controller: function() { + controller: function () { this.foo = m.request({method: "GET", url: "/foo"}) }, - view: function() { + view: function () { redraws1++ return m("div") } } + var Comp2 = { - controller: function() { + controller: function () { this.bar = m.request({method: "GET", url: "/bar"}) }, - view: function() { + view: function () { redraws2++ return m("div") } } + var Root = { + view: function () { + return m("div", [Comp1, Comp2]) + } + } + m.mount(root, Root) mock.requestAnimationFrame.$resolve() @@ -1223,38 +1449,43 @@ function testMithril(mock) { return redraws1 === 1 && redraws2 === 1 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") - var redraws1 = 0, redraws2 = 0 - var Root1 = { - view: function() { - return Comp1 - } - } - var Root2 = { - view: function() { - return Comp2 - } - } + var redraws1 = 0 + var redraws2 = 0 + var Comp1 = { - controller: function() { + controller: function () { this.foo = m.request({method: "GET", url: "/foo"}) }, - view: function() { + view: function () { redraws1++ return m("div") } } + + var Root1 = { + view: function () { + return Comp1 + } + } + var Comp2 = { - controller: function() { + controller: function () { this.bar = m.request({method: "GET", url: "/bar"}) }, - view: function() { + view: function () { redraws2++ return m("div") } } + var Root2 = { + view: function () { + return Comp2 + } + } m.route(root, "/", { "/": Root1, @@ -1266,7 +1497,6 @@ function testMithril(mock) { m.route("/root2") - mock.requestAnimationFrame.$resolve() mock.XMLHttpRequest.$instances.pop().onreadystatechange() @@ -1276,30 +1506,34 @@ function testMithril(mock) { return redraws1 === 1 && redraws2 === 1 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") var cond = true - var controller1 = null, controller2 = null - var Root = { - view: function() { - return cond ? Comp1 : Comp2 - } - } + var controller1 = null + var controller2 = null var Comp1 = { - view: function(ctrl) { + view: function (ctrl) { controller1 = ctrl return m("div") } } + var Comp2 = { - view: function(ctrl) { + view: function (ctrl) { controller2 = ctrl return m("div") } } + var Root = { + view: function () { + return cond ? Comp1 : Comp2 + } + } + m.mount(root, Root) mock.requestAnimationFrame.$resolve() @@ -1311,27 +1545,32 @@ function testMithril(mock) { return controller1 !== controller2 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") var cond = true var unloaded = false - var Root = { - view: function() { - return cond ? Comp1 : Comp2 + + var Comp1 = { + view: function () { + return m("div", { + config: function (el, init, ctx) { + ctx.onunload = function () { unloaded = true } + } + }) } } - var Comp1 = { - view: function() { - return m("div", {config: function(el, init, ctx) { - ctx.onunload = function() {unloaded = true} - }}) + var Comp2 = { + view: function () { + return m("div") } } - var Comp2 = { - view: function() { - return m("div") + + var Root = { + view: function () { + return cond ? Comp1 : Comp2 } } @@ -1346,27 +1585,30 @@ function testMithril(mock) { return unloaded }) - test(function() { + + test(function () { var root = mock.document.createElement("div") var cond = true var initialized = null - var Root = { - view: function() { - return cond ? Comp1 : Comp2 - } - } var Comp1 = { - view: function() { + view: function () { return m("div") } } + var Comp2 = { - view: function() { - return m("div", {config: function(el, init) { - initialized = init - }}) + view: function () { + return m("div", { + config: function (el, init) { initialized = init } + }) + } + } + + var Root = { + view: function () { + return cond ? Comp1 : Comp2 } } @@ -1381,75 +1623,91 @@ function testMithril(mock) { return initialized === false }) - test(function() { + + test(function () { var root = mock.document.createElement("div") var el - var FooPage = { - view: function(ctrl) { - return m('div', [ - m('button', {onclick: function() { - ctrl.bar = true; - m.redraw(true); - el = root.childNodes[0].childNodes[1] - }}, 'click me'), - ctrl.bar ? m.component(BarComponent) : '' - ]); - } - }; + var BarComponent = { - view: function() { - return m('#bar', 'test'); + view: function () { + return m("#bar", "test") } - }; - m.mount(root, FooPage); + } + + var FooPage = { + view: function (ctrl) { + return m("div", [ + m("button", { + onclick: function () { + ctrl.bar = true + m.redraw(true) + el = root.childNodes[0].childNodes[1] + } + }, "click me"), + ctrl.bar ? m.component(BarComponent) : "" + ]) + } + } + + m.mount(root, FooPage) root.childNodes[0].childNodes[0].onclick({}) return el.id === "bar" }) - //m.withAttr - test(function() { - //the handler is called with the correct value & context when callbackThis not given - var _this = {}; - var value, context; - var handler = m.withAttr("test", function(data) { - value = data; - context = this; - }); - handler.call(_this, {currentTarget: {test: "foo"}}); - return value === "foo" && context === _this; - }) - test(function() { - //the handler is called with the correct value & context when callbackThis is given - var _this = {}; - var value, context; - var handler = m.withAttr("test", function(data) { - value = data; - context = this; - }, _this); - handler({currentTarget: {test: "foo"}}); - return value === "foo" && context === _this; + // m.withAttr + test(function () { + // the handler is called with the correct value & context when + // callbackThis not given + var _this = {} + var value, context + var handler = m.withAttr("test", function (data) { + value = data + /* eslint-disable consistent-this, no-invalid-this */ + context = this + /* eslint-enable consistent-this, no-invalid-this */ + }) + + handler.call(_this, {currentTarget: {test: "foo"}}) + return value === "foo" && context === _this }) - //m.trust - test(function() {return m.trust("test").valueOf() === "test"}) + test(function () { + // the handler is called with the correct value & context when + // callbackThis is given + var _this = {} + var value, context + var handler = m.withAttr("test", function (data) { + value = data + /* eslint-disable consistent-this, no-invalid-this */ + context = this + /* eslint-enable consistent-this, no-invalid-this */ + }, _this) + handler({currentTarget: {test: "foo"}}) + return value === "foo" && context === _this + }) - //m.render - test(function() { + // m.trust + test(function () { return m.trust("test").valueOf() === "test" }) + + // m.render + test(function () { var root = mock.document.createElement("div") m.render(root, "test") return root.childNodes[0].nodeValue === "test" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") - m.render(root, m("div", {"class": "a"})) + m.render(root, m("div", {class: "a"})) var elementBefore = root.childNodes[0] - m.render(root, m("div", {"class": "b"})) + m.render(root, m("div", {class: "b"})) var elementAfter = root.childNodes[0] return elementBefore === elementAfter }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m(".a")) var elementBefore = root.childNodes[0] @@ -1457,7 +1715,8 @@ function testMithril(mock) { var elementAfter = root.childNodes[0] return elementBefore === elementAfter }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("div", {id: "a"})) var elementBefore = root.childNodes[0] @@ -1465,7 +1724,8 @@ function testMithril(mock) { var elementAfter = root.childNodes[0] return elementBefore !== elementAfter }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("#a")) var elementBefore = root.childNodes[0] @@ -1473,7 +1733,8 @@ function testMithril(mock) { var elementAfter = root.childNodes[0] return elementBefore !== elementAfter }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("#a")) var elementBefore = root.childNodes[0] @@ -1481,202 +1742,287 @@ function testMithril(mock) { var elementAfter = root.childNodes[0] return elementBefore !== elementAfter }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("div", [undefined])) return root.childNodes[0].childNodes[0].nodeValue === "" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("svg", [m("g")])) var g = root.childNodes[0].childNodes[0] - return g.nodeName === "G" && g.namespaceURI === "http://www.w3.org/2000/svg" + return g.nodeName === "G" && + g.namespaceURI === "http://www.w3.org/2000/svg" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("svg", [m("a[href='http://google.com']")])) return root.childNodes[0].childNodes[0].nodeName === "A" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("div.classname", [m("a", {href: "/first"})])) m.render(root, m("div", [m("a", {href: "/second"})])) return root.childNodes[0].childNodes.length === 1 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li")])) m.render(root, m("ul", [m("li"), undefined])) return root.childNodes[0].childNodes[1].nodeValue === "" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li"), m("li")])) m.render(root, m("ul", [m("li"), undefined])) return root.childNodes[0].childNodes[1].nodeValue === "" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li")])) m.render(root, m("ul", [undefined])) return root.childNodes[0].childNodes[0].nodeValue === "" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li")])) m.render(root, m("ul", [{}])) return root.childNodes[0].childNodes.length === 0 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li")])) m.render(root, m("ul", [{tag: "b", attrs: {}}])) return root.childNodes[0].childNodes[0].nodeName === "B" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li")])) + /* eslint-disable no-new-wrappers */ m.render(root, m("ul", [{tag: new String("b"), attrs: {}}])) + /* eslint-enable no-new-wrappers */ return root.childNodes[0].childNodes[0].nodeName === "B" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li", [m("a")])])) m.render(root, m("ul", [{subtree: "retain"}])) return root.childNodes[0].childNodes[0].childNodes[0].nodeName === "A" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/43 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/43 var root = mock.document.createElement("div") m.render(root, m("a", {config: m.route}, "test")) m.render(root, m("a", {config: m.route}, "test")) return root.childNodes[0].childNodes[0].nodeValue === "test" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/44 (1) + + test(function () { + // https://github.com/lhorie/mithril.js/issues/44 (1) var root = mock.document.createElement("div") m.render(root, m("#foo", [null, m("#bar")])) m.render(root, m("#foo", ["test", m("#bar")])) return root.childNodes[0].childNodes[0].nodeValue === "test" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/44 (2) + + test(function () { + // https://github.com/lhorie/mithril.js/issues/44 (2) var root = mock.document.createElement("div") m.render(root, m("#foo", [null, m("#bar")])) m.render(root, m("#foo", [m("div"), m("#bar")])) return root.childNodes[0].childNodes[0].nodeName === "DIV" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/44 (3) + + test(function () { + // https://github.com/lhorie/mithril.js/issues/44 (3) var root = mock.document.createElement("div") m.render(root, m("#foo", ["test", m("#bar")])) m.render(root, m("#foo", [m("div"), m("#bar")])) return root.childNodes[0].childNodes[0].nodeName === "DIV" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/44 (4) + + test(function () { + // https://github.com/lhorie/mithril.js/issues/44 (4) var root = mock.document.createElement("div") m.render(root, m("#foo", [m("div"), m("#bar")])) m.render(root, m("#foo", ["test", m("#bar")])) return root.childNodes[0].childNodes[0].nodeValue === "test" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/44 (5) + + test(function () { + // https://github.com/lhorie/mithril.js/issues/44 (5) var root = mock.document.createElement("div") m.render(root, m("#foo", [m("#bar")])) m.render(root, m("#foo", [m("#bar"), [m("#baz")]])) return root.childNodes[0].childNodes[1].id === "baz" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/48 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/48 var root = mock.document m.render(root, m("html", [m("#foo")])) var result = root.childNodes[0].childNodes[0].id === "foo" root.childNodes = [mock.document.createElement("html")] return result }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/49 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/49 var root = mock.document.createElement("div") m.render(root, m("a", "test")) m.render(root, m("a.foo", "test")) return root.childNodes[0].childNodes[0].nodeValue === "test" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/49 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/49 var root = mock.document.createElement("div") m.render(root, m("a.foo", "test")) m.render(root, m("a", "test")) return root.childNodes[0].childNodes[0].nodeValue === "test" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/49 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/49 var root = mock.document.createElement("div") m.render(root, m("a.foo", "test")) m.render(root, m("a", "test1")) return root.childNodes[0].childNodes[0].nodeValue === "test1" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/49 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/49 var root = mock.document.createElement("div") m.render(root, m("a", "test")) m.render(root, m("a", "test1")) return root.childNodes[0].childNodes[0].nodeValue === "test1" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/50 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/50 var root = mock.document.createElement("div") m.render(root, m("#foo", [[m("div", "a"), m("div", "b")], m("#bar")])) return root.childNodes[0].childNodes[1].childNodes[0].nodeValue === "b" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/50 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/50 var root = mock.document.createElement("div") - m.render(root, m("#foo", [[m("div", "a"), m("div", "b")], m("#bar")])) - m.render(root, m("#foo", [[m("div", "a"), m("div", "b"), m("div", "c")], m("#bar")])) + + m.render(root, m("#foo", [ + [m("div", "a"), m("div", "b")], + m("#bar") + ])) + + m.render(root, m("#foo", [ + [m("div", "a"), m("div", "b"), m("div", "c")], + m("#bar") + ])) + return root.childNodes[0].childNodes[2].childNodes[0].nodeValue === "c" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/50 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/50 var root = mock.document.createElement("div") - m.render(root, m("#foo", [[m("div", "a"), m("div", "b")], [m("div", "c"), m("div", "d")], m("#bar")])) - return root.childNodes[0].childNodes[3].childNodes[0].nodeValue === "d" && root.childNodes[0].childNodes[4].id === "bar" + + m.render(root, m("#foo", [ + [m("div", "a"), m("div", "b")], + [m("div", "c"), m("div", "d")], + m("#bar") + ])) + + var parent = root.childNodes[0] + return parent.childNodes[3].childNodes[0].nodeValue === "d" && + parent.childNodes[4].id === "bar" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/50 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/50 var root = mock.document.createElement("div") m.render(root, m("#foo", [[m("div", "a"), m("div", "b")], "test"])) - return root.childNodes[0].childNodes[1].childNodes[0].nodeValue === "b" && root.childNodes[0].childNodes[2].nodeValue === "test" + var parent = root.childNodes[0] + return parent.childNodes[1].childNodes[0].nodeValue === "b" && + parent.childNodes[2].nodeValue === "test" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/50 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/50 var root = mock.document.createElement("div") m.render(root, m("#foo", [["a", "b"], "test"])) - return root.childNodes[0].childNodes[1].nodeValue === "b" && root.childNodes[0].childNodes[2].nodeValue === "test" + var parent = root.childNodes[0] + return parent.childNodes[1].nodeValue === "b" && + parent.childNodes[2].nodeValue === "test" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/51 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/51 var root = mock.document.createElement("div") - m.render(root, m("main", [m("button"), m("article", [m("section"), m("nav")])])) - m.render(root, m("main", [m("button"), m("article", [m("span"), m("nav")])])) - return root.childNodes[0].childNodes[1].childNodes[0].nodeName === "SPAN" + + m.render(root, m("main", [ + m("button"), + m("article", [m("section"), m("nav")]) + ])) + + m.render(root, m("main", [ + m("button"), + m("article", [m("span"), m("nav")]) + ])) + + var node = root.childNodes[0].childNodes[1].childNodes[0] + return node.nodeName === "SPAN" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/51 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/51 var root = mock.document.createElement("div") - m.render(root, m("main", [m("button"), m("article", [m("section"), m("nav")])])) - m.render(root, m("main", [m("button"), m("article", ["test", m("nav")])])) - return root.childNodes[0].childNodes[1].childNodes[0].nodeValue === "test" + + m.render(root, m("main", [ + m("button"), + m("article", [m("section"), m("nav")]) + ])) + + m.render(root, m("main", [ + m("button"), + m("article", ["test", m("nav")]) + ])) + + var node = root.childNodes[0].childNodes[1].childNodes[0] + return node.nodeValue === "test" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/51 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/51 var root = mock.document.createElement("div") - m.render(root, m("main", [m("button"), m("article", [m("section"), m("nav")])])) - m.render(root, m("main", [m("button"), m("article", [m.trust("test"), m("nav")])])) - return root.childNodes[0].childNodes[1].childNodes[0].nodeValue === "test" + + m.render(root, m("main", [ + m("button"), + m("article", [m("section"), m("nav")]) + ])) + + m.render(root, m("main", [ + m("button"), + m("article", [m.trust("test"), m("nav")]) + ])) + + var node = root.childNodes[0].childNodes[1].childNodes[0] + return node.nodeValue === "test" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/55 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/55 var root = mock.document.createElement("div") m.render(root, m("#a")) var elementBefore = root.childNodes[0] @@ -1684,20 +2030,23 @@ function testMithril(mock) { var elementAfter = root.childNodes[0] return elementBefore !== elementAfter }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/56 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/56 var root = mock.document.createElement("div") m.render(root, [null, "foo"]) m.render(root, ["bar"]) return root.childNodes.length === 1 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/56 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/56 var root = mock.document.createElement("div") m.render(root, m("div", "foo")) return root.childNodes.length === 1 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("div", [m("button"), m("ul")])) var valueBefore = root.childNodes[0].childNodes[0].nodeName @@ -1705,7 +2054,8 @@ function testMithril(mock) { var valueAfter = root.childNodes[0].childNodes[0].nodeValue return valueBefore === "BUTTON" && valueAfter === "" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("div", [m("ul"), undefined])) var valueBefore1 = root.childNodes[0].childNodes[0].nodeName @@ -1713,10 +2063,12 @@ function testMithril(mock) { m.render(root, m("div", [undefined, m("ul")])) var valueAfter1 = root.childNodes[0].childNodes[0].nodeValue var valueAfter2 = root.childNodes[0].childNodes[1].nodeName - return valueBefore1 === "UL" && valueAfter1 === "" && valueBefore2 === "" && valueAfter2 === "UL" + return valueBefore1 === "UL" && valueAfter1 === "" && + valueBefore2 === "" && valueAfter2 === "UL" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/79 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/79 var root = mock.document.createElement("div") m.render(root, m("div", {style: {background: "red"}})) var valueBefore = root.childNodes[0].style.background @@ -1724,12 +2076,14 @@ function testMithril(mock) { var valueAfter = root.childNodes[0].style.background return valueBefore === "red" && valueAfter === "" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("div[style='background:red']")) return root.childNodes[0].style === "background:red" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("div", {style: {background: "red"}})) var valueBefore = root.childNodes[0].style.background @@ -1737,219 +2091,398 @@ function testMithril(mock) { var valueAfter = root.childNodes[0].style.background return valueBefore === "red" && valueAfter === undefined }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/87 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/87 var root = mock.document.createElement("div") m.render(root, m("div", [[m("a"), m("a")], m("button")])) m.render(root, m("div", [[m("a")], m("button")])) - return root.childNodes[0].childNodes.length === 2 && root.childNodes[0].childNodes[1].nodeName === "BUTTON" + return root.childNodes[0].childNodes.length === 2 && + root.childNodes[0].childNodes[1].nodeName === "BUTTON" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/87 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/87 var root = mock.document.createElement("div") m.render(root, m("div", [m("a"), m("b"), m("button")])) m.render(root, m("div", [m("a"), m("button")])) - return root.childNodes[0].childNodes.length === 2 && root.childNodes[0].childNodes[1].nodeName === "BUTTON" + return root.childNodes[0].childNodes.length === 2 && + root.childNodes[0].childNodes[1].nodeName === "BUTTON" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/99 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/99 var root = mock.document.createElement("div") m.render(root, m("div", [m("img"), m("h1")])) m.render(root, m("div", [m("a")])) - return root.childNodes[0].childNodes.length === 1 && root.childNodes[0].childNodes[0].nodeName === "A" + return root.childNodes[0].childNodes.length === 1 && + root.childNodes[0].childNodes[0].nodeName === "A" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/120 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", ["a", "b", "c", "d"])) m.render(root, m("div", [["d", "e"]])) var children = root.childNodes[0].childNodes - return children.length === 2 && children[0].nodeValue === "d" && children[1].nodeValue === "e" + return children.length === 2 && + children[0].nodeValue === "d" && + children[1].nodeValue === "e" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/120 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", [["a", "b", "c", "d"]])) m.render(root, m("div", ["d", "e"])) var children = root.childNodes[0].childNodes - return children.length === 2 && children[0].nodeValue === "d" && children[1].nodeValue === "e" + return children.length === 2 && + children[0].nodeValue === "d" && + children[1].nodeValue === "e" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/120 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", ["x", [["a"], "b", "c", "d"]])) m.render(root, m("div", ["d", ["e"]])) var children = root.childNodes[0].childNodes - return children.length === 2 && children[0].nodeValue === "d" && children[1].nodeValue === "e" + return children.length === 2 && + children[0].nodeValue === "d" && + children[1].nodeValue === "e" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/120 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", ["b"])) m.render(root, m("div", [["e"]])) var children = root.childNodes[0].childNodes return children.length === 1 && children[0].nodeValue === "e" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/120 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", ["a", ["b"]])) m.render(root, m("div", ["d", [["e"]]])) var children = root.childNodes[0].childNodes - return children.length === 2 && children[0].nodeValue === "d" && children[1].nodeValue === "e" + return children.length === 2 && + children[0].nodeValue === "d" && + children[1].nodeValue === "e" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/120 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", ["a", [["b"]]])) m.render(root, m("div", ["d", ["e"]])) var children = root.childNodes[0].childNodes - return children.length === 2 && children[0].nodeValue === "d" && children[1].nodeValue === "e" + return children.length === 2 && + children[0].nodeValue === "d" && + children[1].nodeValue === "e" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/120 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", ["a", [["b"], "c"]])) m.render(root, m("div", ["d", [[["e"]], "x"]])) var children = root.childNodes[0].childNodes - return children.length === 3 && children[0].nodeValue === "d" && children[1].nodeValue === "e" + return children.length === 3 && + children[0].nodeValue === "d" && + children[1].nodeValue === "e" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") var success = false - m.render(root, m("div", {config: function(elem, isInitialized, ctx) {ctx.data = 1}})) - m.render(root, m("div", {config: function(elem, isInitialized, ctx) {success = ctx.data === 1}})) + + m.render(root, m("div", { + config: function (elem, isInit, ctx) { ctx.data = 1 } + })) + + m.render(root, m("div", { + config: function (elem, isInit, ctx) { success = ctx.data === 1 } + })) + return success }) - test(function() { + + test(function () { var root = mock.document.createElement("div") - var index = 0; - var success = true; - var statefulConfig = function(elem, isInitialized, ctx) {ctx.data = index++} - var node = m("div", {config: statefulConfig}); - m.render(root, [node, node]); + var index = 0 + var success = true - index = 0; - var checkConfig = function(elem, isInitialized, ctx) { + function statefulConfig(elem, isInit, ctx) { ctx.data = index++ } + + var node = m("div", {config: statefulConfig}) + m.render(root, [node, node]) + + index = 0 + + function checkConfig(elem, isInit, ctx) { success = success && (ctx.data === index++) } - node = m("div", {config: checkConfig}); - m.render(root, [node, node]); - return success; + + node = m("div", {config: checkConfig}) + m.render(root, [node, node]) + return success }) - test(function() { + + test(function () { var root = mock.document.createElement("div") var parent + m.render(root, m("div", m("a", { - config: function(el) {parent = el.parentNode.parentNode} - }))); + config: function (el) { parent = el.parentNode.parentNode } + }))) + return parent === root }) - test(function() { + + test(function () { var root = mock.document.createElement("div") var count = 0 + m.render(root, m("div", m("a", { - config: function() { + config: function () { var island = mock.document.createElement("div") count++ if (count > 2) throw new Error("too much recursion...") m.render(island, m("div")) } - }))); + }))) + return count === 1 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/129 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/129 var root = mock.document.createElement("div") - m.render(root, m("div", [["foo", "bar"], ["foo", "bar"], ["foo", "bar"]])); - m.render(root, m("div", ["asdf", "asdf2", "asdf3"])); + + m.render(root, m("div", [ + ["foo", "bar"], ["foo", "bar"], ["foo", "bar"] + ])) + + m.render(root, m("div", ["asdf", "asdf2", "asdf3"])) return true }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/98 - //insert at beginning + + test(function () { + // https://github.com/lhorie/mithril.js/issues/98 + // insert at beginning var root = mock.document.createElement("div") - m.render(root, [m("a", {key: 1}, 1), m("a", {key: 2}, 2), m("a", {key: 3}, 3)]) + + m.render(root, [ + m("a", {key: 1}, 1), + m("a", {key: 2}, 2), + m("a", {key: 3}, 3) + ]) + var firstBefore = root.childNodes[0] - m.render(root, [m("a", {key: 4}, 4), m("a", {key: 1}, 1), m("a", {key: 2}, 2), m("a", {key: 3}, 3)]) + + m.render(root, [ + m("a", {key: 4}, 4), + m("a", {key: 1}, 1), + m("a", {key: 2}, 2), + m("a", {key: 3}, 3) + ]) + var firstAfter = root.childNodes[1] - return firstBefore === firstAfter && root.childNodes[0].childNodes[0].nodeValue === "4" && root.childNodes.length === 4 + + return firstBefore === firstAfter && + root.childNodes[0].childNodes[0].nodeValue === "4" && + root.childNodes.length === 4 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/98 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/98 var root = mock.document.createElement("div") - m.render(root, [m("a", {key: 1}, 1), m("a", {key: 2}, 2), m("a", {key: 3}, 3)]) + + m.render(root, [ + m("a", {key: 1}, 1), + m("a", {key: 2}, 2), + m("a", {key: 3}, 3) + ]) + var firstBefore = root.childNodes[0] - m.render(root, [m("a", {key: 4}, 4), m("a", {key: 1}, 1), m("a", {key: 2}, 2)]) + + m.render(root, [ + m("a", {key: 4}, 4), + m("a", {key: 1}, 1), + m("a", {key: 2}, 2) + ]) + var firstAfter = root.childNodes[1] - return firstBefore === firstAfter && root.childNodes[0].childNodes[0].nodeValue === "4" && root.childNodes.length === 3 + + return firstBefore === firstAfter && + root.childNodes[0].childNodes[0].nodeValue === "4" && + root.childNodes.length === 3 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/98 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/98 var root = mock.document.createElement("div") - m.render(root, [m("a", {key: 1}, 1), m("a", {key: 2}, 2), m("a", {key: 3}, 3)]) + + m.render(root, [ + m("a", {key: 1}, 1), + m("a", {key: 2}, 2), + m("a", {key: 3}, 3) + ]) + var firstBefore = root.childNodes[1] - m.render(root, [m("a", {key: 2}, 2), m("a", {key: 3}, 3), m("a", {key: 4}, 4)]) + + m.render(root, [ + m("a", {key: 2}, 2), + m("a", {key: 3}, 3), + m("a", {key: 4}, 4) + ]) + var firstAfter = root.childNodes[0] - return firstBefore === firstAfter && root.childNodes[0].childNodes[0].nodeValue === "2" && root.childNodes.length === 3 + + return firstBefore === firstAfter && + root.childNodes[0].childNodes[0].nodeValue === "2" && + root.childNodes.length === 3 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/98 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/98 var root = mock.document.createElement("div") - m.render(root, [m("a", {key: 1}, 1), m("a", {key: 2}, 2), m("a", {key: 3}, 3), m("a", {key: 4}, 4), m("a", {key: 5}, 5)]) + + m.render(root, [ + m("a", {key: 1}, 1), + m("a", {key: 2}, 2), + m("a", {key: 3}, 3), + m("a", {key: 4}, 4), + m("a", {key: 5}, 5) + ]) + var firstBefore = root.childNodes[0] var secondBefore = root.childNodes[1] var fourthBefore = root.childNodes[3] - m.render(root, [m("a", {key: 4}, 4), m("a", {key: 10}, 10), m("a", {key: 1}, 1), m("a", {key: 2}, 2)]) + + m.render(root, [ + m("a", {key: 4}, 4), + m("a", {key: 10}, 10), + m("a", {key: 1}, 1), + m("a", {key: 2}, 2) + ]) + var firstAfter = root.childNodes[2] var secondAfter = root.childNodes[3] var fourthAfter = root.childNodes[0] - return firstBefore === firstAfter && secondBefore === secondAfter && fourthBefore === fourthAfter && root.childNodes[1].childNodes[0].nodeValue === "10" && root.childNodes.length === 4 + + return firstBefore === firstAfter && + secondBefore === secondAfter && + fourthBefore === fourthAfter && + root.childNodes[1].childNodes[0].nodeValue === "10" && + root.childNodes.length === 4 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/98 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/98 var root = mock.document.createElement("div") - m.render(root, [m("a", {key: 1}, 1), m("a", {key: 2}, 2), m("a", {key: 3}, 3), m("a", {key: 4}, 4), m("a", {key: 5}, 5)]) + + m.render(root, [ + m("a", {key: 1}, 1), + m("a", {key: 2}, 2), + m("a", {key: 3}, 3), + m("a", {key: 4}, 4), + m("a", {key: 5}, 5) + ]) + var firstBefore = root.childNodes[0] var secondBefore = root.childNodes[1] var fourthBefore = root.childNodes[3] - m.render(root, [m("a", {key: 4}, 4), m("a", {key: 10}, 10), m("a", {key: 2}, 2), m("a", {key: 1}, 1), m("a", {key: 6}, 6), m("a", {key: 7}, 7)]) + + m.render(root, [ + m("a", {key: 4}, 4), + m("a", {key: 10}, 10), + m("a", {key: 2}, 2), + m("a", {key: 1}, 1), + m("a", {key: 6}, 6), + m("a", {key: 7}, 7) + ]) + var firstAfter = root.childNodes[3] var secondAfter = root.childNodes[2] var fourthAfter = root.childNodes[0] - return firstBefore === firstAfter && secondBefore === secondAfter && fourthBefore === fourthAfter && root.childNodes[1].childNodes[0].nodeValue === "10" && root.childNodes[4].childNodes[0].nodeValue === "6" && root.childNodes[5].childNodes[0].nodeValue === "7" && root.childNodes.length === 6 + + return firstBefore === firstAfter && + secondBefore === secondAfter && + fourthBefore === fourthAfter && + root.childNodes[1].childNodes[0].nodeValue === "10" && + root.childNodes[4].childNodes[0].nodeValue === "6" && + root.childNodes[5].childNodes[0].nodeValue === "7" && + root.childNodes.length === 6 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/149 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/149 var root = mock.document.createElement("div") - m.render(root, [m("a", {key: 1}), m("a", {key: 2}), m("a"), m("a", {key: 4}), m("a", {key: 5})]) + + m.render(root, [ + m("a", {key: 1}), + m("a", {key: 2}), + m("a"), + m("a", {key: 4}), + m("a", {key: 5}) + ]) + var firstBefore = root.childNodes[0] var secondBefore = root.childNodes[1] var thirdBefore = root.childNodes[2] var fourthBefore = root.childNodes[3] var fifthBefore = root.childNodes[4] - m.render(root, [m("a", {key: 4}), m("a", {key: 5}), m("a"), m("a", {key: 1}), m("a", {key: 2})]) + + m.render(root, [ + m("a", {key: 4}), + m("a", {key: 5}), + m("a"), + m("a", {key: 1}), + m("a", {key: 2}) + ]) + var firstAfter = root.childNodes[3] var secondAfter = root.childNodes[4] var thirdAfter = root.childNodes[2] var fourthAfter = root.childNodes[0] var fifthAfter = root.childNodes[1] - return firstBefore === firstAfter && secondBefore === secondAfter && thirdBefore === thirdAfter && fourthBefore === fourthAfter && fifthBefore === fifthAfter + + return firstBefore === firstAfter && + secondBefore === secondAfter && + thirdBefore === thirdAfter && + fourthBefore === fourthAfter && + fifthBefore === fifthAfter }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/246 - //insert at beginning with non-keyed in the middle + + test(function () { + // https://github.com/lhorie/mithril.js/issues/246 + // insert at beginning with non-keyed in the middle var root = mock.document.createElement("div") + m.render(root, [m("a", {key: 1}, 1)]) + var firstBefore = root.childNodes[0] - m.render(root, [m("a", {key: 2}, 2), m("br"), m("a", {key: 1}, 1)]) + + m.render(root, [ + m("a", {key: 2}, 2), + m("br"), + m("a", {key: 1}, 1) + ]) + var firstAfter = root.childNodes[2] - return firstBefore === firstAfter && root.childNodes[0].childNodes[0].nodeValue === "2" && root.childNodes.length === 3 + + return firstBefore === firstAfter && + root.childNodes[0].childNodes[0].nodeValue === "2" && + root.childNodes.length === 3 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/134 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/134 var root = mock.document.createElement("div") m.render(root, m("div", {contenteditable: true}, "test")) mock.document.activeElement = root.childNodes[0] @@ -1957,237 +2490,408 @@ function testMithril(mock) { m.render(root, m("div", {contenteditable: false}, "test2")) return root.childNodes[0].childNodes[0].nodeValue === "test2" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/136 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/136 var root = mock.document.createElement("div") m.render(root, m("textarea", ["test"])) m.render(root, m("textarea", ["test1"])) return root.childNodes[0].value === "test1" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") var unloaded = 0 + m.render(root, [ m("div", { key: 1, - config: function(el, init, ctx) { - ctx.onunload = function() { + config: function (el, init, ctx) { + ctx.onunload = function () { unloaded++ } } }) ]) + m.render(root, [ m("div", {key: 2}), m("div", { key: 1, - config: function(el, init, ctx) { - ctx.onunload = function() { + config: function (el, init, ctx) { + ctx.onunload = function () { unloaded++ } } }) ]) + return unloaded === 0 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") var unloadedParent = 0 var unloadedChild = 0 - var configParent = function(el, init, ctx) { - ctx.onunload = function() { + + function configParent(el, init, ctx) { + ctx.onunload = function () { unloadedParent++ } } - var configChild = function(el, init, ctx) { - ctx.onunload = function() { + + function configChild(el, init, ctx) { + ctx.onunload = function () { unloadedChild++ } } - m.render(root, m("div", {config: configParent}, m("a", {config: configChild}))) - m.render(root, m("main", {config: configParent}, m("a", {config: configChild}))) + + m.render(root, m("div", {config: configParent}, [ + m("a", {config: configChild}) + ])) + + m.render(root, m("main", {config: configParent}, [ + m("a", {config: configChild}) + ])) + return unloadedParent === 1 && unloadedChild === 0 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") var unloadedParent = 0 var unloadedChild = 0 - var configParent = function(el, init, ctx) { - ctx.onunload = function() { + + function configParent(el, init, ctx) { + ctx.onunload = function () { unloadedParent++ } } - var configChild = function(el, init, ctx) { - ctx.onunload = function() { + + function configChild(el, init, ctx) { + ctx.onunload = function () { unloadedChild++ } } - m.render(root, m("div", {config: configParent}, m("a", {config: configChild}))) - m.render(root, m("main", {config: configParent}, m("b", {config: configChild}))) + + m.render(root, m("div", {config: configParent}, [ + m("a", {config: configChild}) + ])) + + m.render(root, m("main", {config: configParent}, [ + m("b", {config: configChild}) + ])) + return unloadedParent === 1 && unloadedChild === 1 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/150 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/150 var root = mock.document.createElement("div") m.render(root, [m("a"), m("div")]) m.render(root, [[], m("div")]) - return root.childNodes.length === 1 && root.childNodes[0].nodeName === "DIV" + + return root.childNodes.length === 1 && + root.childNodes[0].nodeName === "DIV" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/156 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/156 var root = mock.document.createElement("div") m.render(root, m("div", [ - ["a", "b", "c", "d"].map(function() { + ["a", "b", "c", "d"].map(function () { return [m("div"), " "] }), m("span") ])) return root.childNodes[0].childNodes[8].nodeName === "SPAN" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/157 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/157 var root = mock.document.createElement("div") - m.render(root, m("ul", [m("li", {key: 0}, 0), m("li", {key: 2}, 2), m("li", {key: 4}, 4)])) - m.render(root, m("ul", [m("li", {key: 0}, 0), m("li", {key: 1}, 1), m("li", {key: 2}, 2), m("li", {key: 3}, 3), m("li", {key: 4}, 4), m("li", {key: 5}, 5)])) - return root.childNodes[0].childNodes.map(function(n) {return n.childNodes[0].nodeValue}).join("") === "012345" + + m.render(root, m("ul", [ + m("li", {key: 0}, 0), + m("li", {key: 2}, 2), + m("li", {key: 4}, 4) + ])) + + m.render(root, m("ul", [ + m("li", {key: 0}, 0), + m("li", {key: 1}, 1), + m("li", {key: 2}, 2), + m("li", {key: 3}, 3), + m("li", {key: 4}, 4), + m("li", {key: 5}, 5) + ])) + + return root.childNodes[0].childNodes.map(function (n) { + return n.childNodes[0].nodeValue + }).join("") === "012345" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/157 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/157 var root = mock.document.createElement("div") m.render(root, m("input", {value: "a"})) m.render(root, m("input", {value: "aa"})) return root.childNodes[0].childNodes.length === 0 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/157 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/157 var root = mock.document.createElement("div") - m.render(root, m("br", {"class": "a"})) - m.render(root, m("br", {"class": "aa"})) + m.render(root, m("br", {class: "a"})) + m.render(root, m("br", {class: "aa"})) return root.childNodes[0].childNodes.length === 0 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/194 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/194 var root = mock.document.createElement("div") - m.render(root, m("ul", [m("li", {key: 0}, 0), m("li", {key: 1}, 1), m("li", {key: 2}, 2), m("li", {key: 3}, 3), m("li", {key: 4}, 4), m("li", {key: 5}, 5)])) - m.render(root, m("ul", [m("li", {key: 0}, 0), m("li", {key: 1}, 1), m("li", {key: 2}, 2), m("li", {key: 4}, 4), m("li", {key: 5}, 5)])) - return root.childNodes[0].childNodes.map(function(n) {return n.childNodes[0].nodeValue}).join("") === "01245" + + m.render(root, m("ul", [ + m("li", {key: 0}, 0), + m("li", {key: 1}, 1), + m("li", {key: 2}, 2), + m("li", {key: 3}, 3), + m("li", {key: 4}, 4), + m("li", {key: 5}, 5) + ])) + + m.render(root, m("ul", [ + m("li", {key: 0}, 0), + m("li", {key: 1}, 1), + m("li", {key: 2}, 2), + m("li", {key: 4}, 4), + m("li", {key: 5}, 5) + ])) + + return root.childNodes[0].childNodes.map(function (n) { + return n.childNodes[0].nodeValue + }).join("") === "01245" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/194 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/194 var root = mock.document.createElement("div") - m.render(root, m("ul", [m("li", {key: 0}, 0), m("li", {key: 1}, 1), m("li", {key: 2}, 2), m("li", {key: 3}, 3), m("li", {key: 4}, 4), m("li", {key: 5}, 5)])) - m.render(root, m("ul", [m("li", {key: 1}, 1), m("li", {key: 2}, 2), m("li", {key: 3}, 3), m("li", {key: 4}, 4), m("li", {key: 5}, 5), m("li", {key: 6}, 6)])) - m.render(root, m("ul", [m("li", {key: 12}, 12), m("li", {key: 13}, 13), m("li", {key: 14}, 14), m("li", {key: 15}, 15), m("li", {key: 16}, 16), m("li", {key: 17}, 17)])) - return root.childNodes[0].childNodes.map(function(n) {return n.childNodes[0].nodeValue}).join(",") === "12,13,14,15,16,17" + + m.render(root, m("ul", [ + m("li", {key: 0}, 0), + m("li", {key: 1}, 1), + m("li", {key: 2}, 2), + m("li", {key: 3}, 3), + m("li", {key: 4}, 4), + m("li", {key: 5}, 5) + ])) + + m.render(root, m("ul", [ + m("li", {key: 1}, 1), + m("li", {key: 2}, 2), + m("li", {key: 3}, 3), + m("li", {key: 4}, 4), + m("li", {key: 5}, 5), + m("li", {key: 6}, 6) + ])) + + m.render(root, m("ul", [ + m("li", {key: 12}, 12), + m("li", {key: 13}, 13), + m("li", {key: 14}, 14), + m("li", {key: 15}, 15), + m("li", {key: 16}, 16), + m("li", {key: 17}, 17) + ])) + + return root.childNodes[0].childNodes.map(function (n) { + return n.childNodes[0].nodeValue + }).join(",") === "12,13,14,15,16,17" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/206 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/206 var root = mock.document.createElement("div") m.render(root, m("div", undefined)) m.render(root, m("div", [m("div")])) return root.childNodes[0].childNodes.length === 1 }) - test(function() { + + test(function () { // https://github.com/lhorie/mithril.js/issues/206 var root = mock.document.createElement("div") m.render(root, m("div", null)) m.render(root, m("div", [m("div")])) return root.childNodes[0].childNodes.length === 1 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/200 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/200 var root = mock.document.createElement("div") var unloaded1 = false + function unloadable1(element, isInit, context) { - context.onunload = function() { + context.onunload = function () { unloaded1 = true } } - m.render(root, [ m("div", {config: unloadable1}) ]) - m.render(root, [ ]) + + m.render(root, [m("div", {config: unloadable1})]) + m.render(root, []) var unloaded2 = false + function unloadable2(element, isInit, context) { - context.onunload = function() { + context.onunload = function () { unloaded2 = true } } - m.render(root, [ m("div", {config: unloadable2}) ]) - m.render(root, [ ]) + + m.render(root, [m("div", {config: unloadable2})]) + m.render(root, []) return unloaded1 === true && unloaded2 === true }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, [m("div.blue")]) m.render(root, [m("div.green", [m("div")]), m("div.blue")]) return root.childNodes.length === 2 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/277 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/277 var root = mock.document.createElement("div") function Field() { - this.tag = "div"; - this.attrs = {}; - this.children = "hello"; + this.tag = "div" + this.attrs = {} + this.children = "hello" } m.render(root, new Field()) return root.childNodes.length === 1 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, {foo: 123}) return root.childNodes.length === 0 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/299 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/299 var root = mock.document.createElement("div") - m.render(root, m("div", [m("div", {key: 1}, 1), m("div", {key: 2}, 2), m("div", {key: 3}, 3), m("div", {key: 4}, 4), m("div", {key: 5}, 5), null, null, null, null, null, null, null, null, null, null])) - m.render(root, m("div", [null, null, m("div", {key: 3}, 3), null, null, m("div", {key: 6}, 6), null, null, m("div", {key: 9}, 9), null, null, m("div", {key: 12}, 12), null, null, m("div", {key: 15}, 15)])) - m.render(root, m("div", [m("div", {key: 1}, 1), m("div", {key: 2}, 2), m("div", {key: 3}, 3), m("div", {key: 4}, 4), m("div", {key: 5}, 5), null, null, null, null, null, null, null, null, null, null])) - return root.childNodes[0].childNodes.map(function(c) {return c.childNodes ? c.childNodes[0].nodeValue : c.nodeValue}).slice(0, 5).join("") === "12345" + + m.render(root, m("div", [ + m("div", {key: 1}, 1), + m("div", {key: 2}, 2), + m("div", {key: 3}, 3), + m("div", {key: 4}, 4), + m("div", {key: 5}, 5), + null, null, null, null, null, null, null, null, null, null + ])) + + m.render(root, m("div", [ + null, null, + m("div", {key: 3}, 3), + null, null, + m("div", {key: 6}, 6), + null, null, + m("div", {key: 9}, 9), + null, null, + m("div", {key: 12}, 12), + null, null, + m("div", {key: 15}, 15) + ])) + + m.render(root, m("div", [ + m("div", {key: 1}, 1), + m("div", {key: 2}, 2), + m("div", {key: 3}, 3), + m("div", {key: 4}, 4), + m("div", {key: 5}, 5), + null, null, null, null, null, null, null, null, null, null + ])) + + return root.childNodes[0].childNodes.map(function (c) { + return c.childNodes ? c.childNodes[0].nodeValue : c.nodeValue + }).slice(0, 5).join("") === "12345" }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/377 + + test(function () { + // https://github.com/lhorie/mithril.js/issues/377 var root = mock.document.createElement("div") - m.render(root, m("div", [m("div", 1), m("div", 2), [m("div", {key: 3}, 3), m("div", {key: 4}, 4), m("div", {key:5}, 5)], [m("div", {key: 6}, 6)]])) - m.render(root, m("div", [m("div", 1), null, [m("div", {key: 3}, 3), m("div", {key: 4}, 4), m("div", {key:5}, 5)], [m("div", {key: 6}, 6)]])) - return root.childNodes[0].childNodes.map(function(c) {return c.childNodes ? c.childNodes[0].nodeValue : c.nodeValue}).join("") === "13456" + + m.render(root, m("div", [ + m("div", 1), + m("div", 2), [m("div", {key: 3}, 3), + m("div", {key: 4}, 4), + m("div", {key: 5}, 5)], + [m("div", {key: 6}, 6)] + ])) + + m.render(root, m("div", [ + m("div", 1), + null, + [m("div", {key: 3}, 3), + m("div", {key: 4}, 4), + m("div", {key: 5}, 5)], + [m("div", {key: 6}, 6)] + ])) + + return root.childNodes[0].childNodes.map(function (c) { + return c.childNodes ? c.childNodes[0].nodeValue : c.nodeValue + }).join("") === "13456" }) - test(function() { + + test(function () { + // don't throw rendering console.log in Firefox var root = mock.document.createElement("div") - m.render(root, m("div", [console.log()])) // don't throw in Firefox + /* eslint-disable no-console */ + m.render(root, m("div", [console.log()])) + /* eslint-enable no-console */ return true }) - test(function() { + + test(function () { var root = mock.document.createElement("div") + m.render(root, [ m("#div-1", {key: 1}), m("#div-2", {key: 2}), m("#div-3", {key: 3}) ]) + root.appendChild(root.childNodes[1]) + m.render(root, [ m("#div-1", {key: 1}), m("#div-3", {key: 3}), m("#div-2", {key: 2}) ]) - return root.childNodes.map(function(node) {return node.id}).join() === "div-1,div-3,div-2" + + return root.childNodes.map(function (node) { + return node.id + }).join() === "div-1,div-3,div-2" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") - m.render(root, m("div", function() {})) + m.render(root, m("div", function () {})) return root.childNodes[0].childNodes.length === 0 }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m("div", "foo", m("a"))) m.render(root, m("div", "test")) return root.childNodes[0].childNodes.length === 1 }) - test(function() { - //if an element is preceded by a conditional, it should not lose its identity + + test(function () { + // if an element is preceded by a conditional, it should not lose its + // identity var root = mock.document.createElement("div") m.render(root, m("div", [m("a"), m("input[autofocus]")])) var before = root.childNodes[0].childNodes[1] @@ -2195,200 +2899,328 @@ function testMithril(mock) { var after = root.childNodes[0].childNodes[1] return before === after }) - test(function() { - //unkeyed element should maintain identity if mixed w/ keyed elements and identity can be inferred + + test(function () { + // unkeyed element should maintain identity if mixed w/ keyed elements + // and identity can be inferred var root = mock.document.createElement("div") - m.render(root, m("div", [m("a", {key: 1}), m("a", {key: 2}), m("a", {key: 3}), m("i")])) + + m.render(root, m("div", [ + m("a", {key: 1}), + m("a", {key: 2}), + m("a", {key: 3}), + m("i") + ])) + var before = root.childNodes[0].childNodes[3] - m.render(root, m("div", [m("b", {key: 3}), m("b", {key: 4}), m("i"), m("b", {key: 1})])) + + m.render(root, m("div", [ + m("b", {key: 3}), + m("b", {key: 4}), + m("i"), + m("b", {key: 1}) + ])) + var after = root.childNodes[0].childNodes[2] + return before === after }) - test(function() { - //unkeyed element should maintain identity if mixed w/ keyed elements and text nodes and identity can be inferred + + test(function () { + // unkeyed element should maintain identity if mixed w/ keyed elements + // and text nodes and identity can be inferred var root = mock.document.createElement("div") - m.render(root, m("div", [m("a", {key: 1}), m("a", {key: 2}), "foo", m("a", {key: 3}), m("i")])) + + m.render(root, m("div", [ + m("a", {key: 1}), + m("a", {key: 2}), + "foo", + m("a", {key: 3}), + m("i") + ])) + var before = root.childNodes[0].childNodes[4] - m.render(root, m("div", [m("a", {key: 3}), m("a", {key: 4}), "bar", m("i"), m("a", {key: 1})])) + + m.render(root, m("div", [ + m("a", {key: 3}), + m("a", {key: 4}), + "bar", + m("i"), + m("a", {key: 1}) + ])) + var after = root.childNodes[0].childNodes[3] + return before === after }) - test(function() { + + test(function () { var root = mock.document.createElement("div") - m.render(root, m("div", [m("a", {key: 1}), m("a", {key: 2}), null, m("a", {key: 3}), m("i")])) + + m.render(root, m("div", [ + m("a", {key: 1}), + m("a", {key: 2}), + null, + m("a", {key: 3}), + m("i") + ])) + var before = root.childNodes[0].childNodes[4] - m.render(root, m("div", [m("a", {key: 3}), m("a", {key: 4}), null, m("i"), m("a", {key: 1})])) + + m.render(root, m("div", [ + m("a", {key: 3}), + m("a", {key: 4}), + null, + m("i"), + m("a", {key: 1}) + ])) + var after = root.childNodes[0].childNodes[3] + return before === after }) - test(function() { + + test(function () { var root = mock.document.createElement("div") - m.render(root, m("div", [m("a", {key: 1}), m("a", {key: 2}), undefined, m("a", {key: 3}), m("i")])) + + m.render(root, m("div", [ + m("a", {key: 1}), + m("a", {key: 2}), + undefined, + m("a", {key: 3}), + m("i") + ])) + var before = root.childNodes[0].childNodes[4] - m.render(root, m("div", [m("a", {key: 3}), m("a", {key: 4}), undefined, m("i"), m("a", {key: 1})])) + + m.render(root, m("div", [ + m("a", {key: 3}), + m("a", {key: 4}), + undefined, + m("i"), + m("a", {key: 1}) + ])) + var after = root.childNodes[0].childNodes[3] + return before === after }) - test(function() { + + test(function () { var root = mock.document.createElement("div") - m.render(root, m("div", [m("a", {key: 1}), m("a", {key: 2}), m.trust("a"), m("a", {key: 3}), m("i")])) + + m.render(root, m("div", [ + m("a", {key: 1}), + m("a", {key: 2}), + m.trust("a"), + m("a", {key: 3}), + m("i") + ])) + var before = root.childNodes[0].childNodes[4] - m.render(root, m("div", [m("a", {key: 3}), m("a", {key: 4}), m.trust("a"), m("i"), m("a", {key: 1})])) + + m.render(root, m("div", [ + m("a", {key: 3}), + m("a", {key: 4}), + m.trust("a"), + m("i"), + m("a", {key: 1}) + ])) + var after = root.childNodes[0].childNodes[3] + return before === after }) - test(function() { + + test(function () { var root = mock.document.createElement("div") - var vdom = m("div.a", {"class": undefined}) + var vdom = m("div.a", {class: undefined}) m.render(root, vdom) - return root.childNodes[0]["class"] === "a" + return root.childNodes[0].class === "a" }) - test(function() { + + test(function () { var root = mock.document.createElement("div") m.render(root, m(".a", [1])) m.render(root, m(".a", [])) return root.childNodes[0].childNodes.length === 0 }) - //end m.render + // end m.render - //m.redraw - test(function() { - mock.requestAnimationFrame.$resolve() //setup + // m.redraw + test(function () { + mock.requestAnimationFrame.$resolve() // setup var controller var root = mock.document.createElement("div") m.mount(root, { - controller: function() {controller = this}, - view: function(ctrl) {return ctrl.value} + controller: function () { + /* eslint-disable consistent-this, no-invalid-this */ + controller = this + /* eslint-enable consistent-this, no-invalid-this */ + }, + view: function (ctrl) { return ctrl.value } }) + mock.requestAnimationFrame.$resolve() + var valueBefore = root.childNodes[0].nodeValue controller.value = "foo" + m.redraw() + mock.requestAnimationFrame.$resolve() + return valueBefore === "" && root.childNodes[0].nodeValue === "foo" }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup var count = 0 var root = mock.document.createElement("div") m.mount(root, { - controller: function() {}, - view: function() { - count++ - } + controller: function () {}, + view: function () { count++ } }) - mock.requestAnimationFrame.$resolve() //teardown - m.redraw() //should run synchronously + mock.requestAnimationFrame.$resolve() // teardown + m.redraw() // should run synchronously - m.redraw() //rest should run asynchronously since they're spamming + m.redraw() // rest should run asynchronously since they're spamming m.redraw() m.redraw() - mock.requestAnimationFrame.$resolve() //teardown + mock.requestAnimationFrame.$resolve() // teardown return count === 3 }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup var count = 0 var root = mock.document.createElement("div") + m.mount(root, { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { count++ } }) - mock.requestAnimationFrame.$resolve() //teardown - m.redraw(true) //should run synchronously - m.redraw(true) //forced to run synchronously + mock.requestAnimationFrame.$resolve() // teardown + + m.redraw(true) // should run synchronously + + m.redraw(true) // forced to run synchronously m.redraw(true) m.redraw(true) - mock.requestAnimationFrame.$resolve() //teardown + + mock.requestAnimationFrame.$resolve() // teardown return count === 5 }) - //m.route - test(function() { - mock.requestAnimationFrame.$resolve() //setup + // m.route + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" + m.route(root, "/test1", { - "/test1": {controller: function() {}, view: function() {return "foo"}} + "/test1": { + controller: function () {}, + view: function () { return "foo" } + } }) + mock.requestAnimationFrame.$resolve() - var result = mock.location.search === "?/test1" && root.childNodes[0].nodeValue === "foo" + var result = mock.location.search === "?/test1" && + root.childNodes[0].nodeValue === "foo" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.pathname = "/" var root = mock.document.createElement("div") m.route.mode = "pathname" m.route(root, "/test2", { "/test2": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return [ "foo", - m("a", { href: "/test2", config: m.route }, "Test2") + m("a", {href: "/test2", config: m.route}, "Test2") ] } } }) mock.requestAnimationFrame.$resolve() - var result = mock.location.pathname === "/test2" && root.childNodes[0].nodeValue === "foo" && root.childNodes[1].href === "/test2" + var result = mock.location.pathname === "/test2" && + root.childNodes[0].nodeValue === "foo" && + root.childNodes[1].href === "/test2" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.hash = "#" var root = mock.document.createElement("div") m.route.mode = "hash" m.route(root, "/test3", { - "/test3": {controller: function() {}, view: function() {return "foo"}} + "/test3": { + controller: function () {}, + view: function () { return "foo" } + } }) mock.requestAnimationFrame.$resolve() - var result = mock.location.hash === "#/test3" && root.childNodes[0].nodeValue === "foo" + var result = mock.location.hash === "#/test3" && + root.childNodes[0].nodeValue === "foo" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/test4/foo", { - "/test4/:test": {controller: function() {}, view: function() {return m.route.param("test")}} + "/test4/:test": { + controller: function () {}, + view: function () { return m.route.param("test") } + } }) mock.requestAnimationFrame.$resolve() - var result = mock.location.search === "?/test4/foo" && root.childNodes[0].nodeValue === "foo" + var result = mock.location.search === "?/test4/foo" && + root.childNodes[0].nodeValue === "foo" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" - var component = {controller: function() {}, view: function() {return m.route.param("test")}} + var component = { + controller: function () {}, + view: function () { return m.route.param("test") } + } var root = mock.document.createElement("div") m.route.mode = "search" @@ -2402,17 +3234,23 @@ function testMithril(mock) { var paramValueAfter = m.route.param("test") mock.requestAnimationFrame.$resolve() - var result = mock.location.search === "?/" && paramValueBefore === "foo" && paramValueAfter === undefined + var result = mock.location.search === "?/" && + paramValueBefore === "foo" && + paramValueAfter === undefined - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" - var component = {controller: function() {}, view: function() {return m.route.param("a1")}} + var component = { + controller: function () {}, + view: function () { return m.route.param("a1") } + } var root = mock.document.createElement("div") m.route.mode = "search" @@ -2426,18 +3264,24 @@ function testMithril(mock) { var paramValueAfter = m.route.param("a1") mock.requestAnimationFrame.$resolve() - var result = mock.location.search === "?/" && paramValueBefore === "foo" && paramValueAfter === undefined + var result = mock.location.search === "?/" && + paramValueBefore === "foo" && + paramValueAfter === undefined - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/61 - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + // https://github.com/lhorie/mithril.js/issues/61 + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" - var component = {controller: function() {}, view: function() {return m.route.param("a1")}} + var component = { + controller: function () {}, + view: function () { return m.route.param("a1") } + } var root = mock.document.createElement("div") m.route.mode = "search" @@ -2451,66 +3295,72 @@ function testMithril(mock) { var routeValueAfter = m.route() mock.requestAnimationFrame.$resolve() - var result = routeValueBefore === "/test7/foo" && routeValueAfter === "/" + var result = routeValueBefore === "/test7/foo" && + routeValueAfter === "/" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/test8/foo/SEP/bar/baz", { "/test8/:test/SEP/:path...": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return m.route.param("test") + "_" + m.route.param("path") } } }) mock.requestAnimationFrame.$resolve() - var result = mock.location.search === "?/test8/foo/SEP/bar/baz" && root.childNodes[0].nodeValue === "foo_bar/baz" + var result = mock.location.search === "?/test8/foo/SEP/bar/baz" && + root.childNodes[0].nodeValue === "foo_bar/baz" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/test9/foo/bar/SEP/baz", { "/test9/:test.../SEP/:path": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return m.route.param("test") + "_" + m.route.param("path") } } }) mock.requestAnimationFrame.$resolve() - var result = mock.location.search === "?/test9/foo/bar/SEP/baz" && root.childNodes[0].nodeValue === "foo/bar_baz" + var result = mock.location.search === "?/test9/foo/bar/SEP/baz" && + root.childNodes[0].nodeValue === "foo/bar_baz" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/test10/foo%20bar", { "/test10/:test": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return m.route.param("test") } } @@ -2519,141 +3369,181 @@ function testMithril(mock) { var result = root.childNodes[0].nodeValue === "foo bar" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { - "/": {controller: function() {}, view: function() {return "foo"}}, - "/test11": {controller: function() {}, view: function() {return "bar"}} + "/": { + controller: function () {}, + view: function () { return "foo" } + }, + "/test11": { + controller: function () {}, + view: function () { return "bar" } + } }) mock.requestAnimationFrame.$resolve() m.route("/test11/") mock.requestAnimationFrame.$resolve() - var result = mock.location.search === "?/test11/" && root.childNodes[0].nodeValue === "bar" + var result = mock.location.search === "?/test11/" && + root.childNodes[0].nodeValue === "bar" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { - "/": {controller: function() {}, view: function() {}}, - "/test12": {controller: function() {}, view: function() {}} + "/": {controller: function () {}, view: function () {}}, + "/test12": {controller: function () {}, view: function () {}} }) mock.requestAnimationFrame.$resolve() m.route("/test12?a=foo&b=bar") mock.requestAnimationFrame.$resolve() - var result = mock.location.search === "?/test12?a=foo&b=bar" && m.route.param("a") === "foo" && m.route.param("b") === "bar" + var result = mock.location.search === "?/test12?a=foo&b=bar" && + m.route.param("a") === "foo" && + m.route.param("b") === "bar" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { - "/": {controller: function() {}, view: function() {return "bar"}}, - "/test13/:test": {controller: function() {}, view: function() {return m.route.param("test")}} + "/": { + controller: function () {}, + view: function () { return "bar" } + }, + "/test13/:test": { + controller: function () {}, + view: function () { return m.route.param("test") } + } }) mock.requestAnimationFrame.$resolve() m.route("/test13/foo?test=bar") mock.requestAnimationFrame.$resolve() - var result = mock.location.search === "?/test13/foo?test=bar" && root.childNodes[0].nodeValue === "foo" + var result = mock.location.search === "?/test13/foo?test=bar" && + root.childNodes[0].nodeValue === "foo" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { - "/": {controller: function() {}, view: function() {return "bar"}}, - "/test14": {controller: function() {}, view: function() {return "foo"}} + "/": { + controller: function () {}, + view: function () { return "bar" } + }, + "/test14": { + controller: function () {}, + view: function () { return "foo" } + } }) mock.requestAnimationFrame.$resolve() m.route("/test14?test&test2=") mock.requestAnimationFrame.$resolve() - var result = mock.location.search === "?/test14?test&test2=" && m.route.param("test") == null && m.route.param("test2") === "" + var result = mock.location.search === "?/test14?test&test2=" && + m.route.param("test") == null && + m.route.param("test2") === "" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { - "/": {controller: function() {}, view: function() {}}, - "/test12": {controller: function() {}, view: function() {}} + "/": {controller: function () {}, view: function () {}}, + "/test12": {controller: function () {}, view: function () {}} }) mock.requestAnimationFrame.$resolve() m.route("/test12", {a: "foo", b: "bar"}) mock.requestAnimationFrame.$resolve() - var result = mock.location.search === "?/test12?a=foo&b=bar" && m.route.param("a") === "foo" && m.route.param("b") === "bar" + var result = mock.location.search === "?/test12?a=foo&b=bar" && + m.route.param("a") === "foo" && + m.route.param("b") === "bar" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { // test route params returning params object if no key is given - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + // test route params returning params object if no key is given + mock.requestAnimationFrame.$resolve() // setup var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { - "/": {controller: function() {}, view: function() {}}, - "/test12": {controller: function() {}, view: function() {}} + "/": {controller: function () {}, view: function () {}}, + "/test12": {controller: function () {}, view: function () {}} }) mock.requestAnimationFrame.$resolve() m.route("/test12", {a: "foo", b: "bar"}) mock.requestAnimationFrame.$resolve() - var params = m.route.param(); + var params = m.route.param() var result = params.a === "foo" && params.b === "bar" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") var route1, route2 m.route.mode = "search" m.route(root, "/", { - "/": {controller: function() {route1 = m.route()}, view: function() {}}, - "/test13": {controller: function() {route2 = m.route()}, view: function() {}} + "/": { + controller: function () { route1 = m.route() }, + view: function () {} + }, + "/test13": { + controller: function () { route2 = m.route() }, + view: function () {} + } }) mock.requestAnimationFrame.$resolve() m.route("/test13") @@ -2661,12 +3551,13 @@ function testMithril(mock) { var result = route1 === "/" && route2 === "/test13" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") @@ -2674,18 +3565,18 @@ function testMithril(mock) { m.route.mode = "search" m.route(root, "/", { "/": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return m("div", { - config: function(el, init, ctx) { - ctx.onunload = function() { + config: function (el, init, ctx) { + ctx.onunload = function () { unloaded++ } } }) } }, - "/test14": {controller: function() {}, view: function() {}} + "/test14": {controller: function () {}, view: function () {}} }) mock.requestAnimationFrame.$resolve() m.route("/test14") @@ -2693,12 +3584,13 @@ function testMithril(mock) { var result = unloaded === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") @@ -2706,13 +3598,13 @@ function testMithril(mock) { m.route.mode = "search" m.route(root, "/", { "/": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return [ m("div"), m("div", { - config: function(el, init, ctx) { - ctx.onunload = function() { + config: function (el, init, ctx) { + ctx.onunload = function () { unloaded++ } } @@ -2721,8 +3613,8 @@ function testMithril(mock) { } }, "/test15": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return [m("div")] } } @@ -2733,12 +3625,13 @@ function testMithril(mock) { var result = unloaded === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") @@ -2746,11 +3639,11 @@ function testMithril(mock) { m.route.mode = "search" m.route(root, "/", { "/": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return m("div", { - config: function(el, init, ctx) { - ctx.onunload = function() { + config: function (el, init, ctx) { + ctx.onunload = function () { unloaded++ } } @@ -2758,8 +3651,8 @@ function testMithril(mock) { } }, "/test16": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return m("a") } } @@ -2770,12 +3663,13 @@ function testMithril(mock) { var result = unloaded === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") @@ -2783,12 +3677,12 @@ function testMithril(mock) { m.route.mode = "search" m.route(root, "/", { "/": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return [ m("div", { - config: function(el, init, ctx) { - ctx.onunload = function() { + config: function (el, init, ctx) { + ctx.onunload = function () { unloaded++ } } @@ -2797,8 +3691,8 @@ function testMithril(mock) { } }, "/test17": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return m("a") } } @@ -2809,12 +3703,13 @@ function testMithril(mock) { var result = unloaded === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") @@ -2822,11 +3717,11 @@ function testMithril(mock) { m.route.mode = "search" m.route(root, "/", { "/": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return m("div", { - config: function(el, init, ctx) { - ctx.onunload = function() { + config: function (el, init, ctx) { + ctx.onunload = function () { unloaded++ } } @@ -2834,8 +3729,8 @@ function testMithril(mock) { } }, "/test18": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return [m("a")] } } @@ -2846,12 +3741,13 @@ function testMithril(mock) { var result = unloaded === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") @@ -2859,13 +3755,13 @@ function testMithril(mock) { m.route.mode = "search" m.route(root, "/", { "/": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return [ m("div", { key: 1, - config: function(el, init, ctx) { - ctx.onunload = function() { + config: function (el, init, ctx) { + ctx.onunload = function () { unloaded++ } } @@ -2874,13 +3770,13 @@ function testMithril(mock) { } }, "/test20": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return [ m("div", { key: 2, - config: function(el, init, ctx) { - ctx.onunload = function() { + config: function (el, init, ctx) { + ctx.onunload = function () { unloaded++ } } @@ -2895,12 +3791,13 @@ function testMithril(mock) { var result = unloaded === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") @@ -2908,13 +3805,13 @@ function testMithril(mock) { m.route.mode = "search" m.route(root, "/", { "/": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return [ m("div", { key: 1, - config: function(el, init, ctx) { - ctx.onunload = function() { + config: function (el, init, ctx) { + ctx.onunload = function () { unloaded++ } } @@ -2923,12 +3820,12 @@ function testMithril(mock) { } }, "/test21": { - controller: function() {}, - view: function() { + controller: function () {}, + view: function () { return [ m("div", { - config: function(el, init, ctx) { - ctx.onunload = function() { + config: function (el, init, ctx) { + ctx.onunload = function () { unloaded++ } } @@ -2943,65 +3840,67 @@ function testMithril(mock) { var result = unloaded === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/foo", { "/foo": { - controller: function() {}, - view: function() { - return m("div", "foo"); + controller: function () {}, + view: function () { + return m("div", "foo") } }, "/bar": { - controller: function() {}, - view: function() { - return m("div", "bar"); + controller: function () {}, + view: function () { + return m("div", "bar") } } }) mock.requestAnimationFrame.$resolve() - var foo = root.childNodes[0].childNodes[0].nodeValue; + var foo = root.childNodes[0].childNodes[0].nodeValue m.route("/bar") mock.requestAnimationFrame.$resolve() - var bar = root.childNodes[0].childNodes[0].nodeValue; + var bar = root.childNodes[0].childNodes[0].nodeValue var result = (foo === "foo" && bar === "bar") - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") var unloaded = 0 - var config = function(el, init, ctx) { - ctx.onunload = function() { + function config(el, init, ctx) { + ctx.onunload = function () { unloaded++ } } m.route.mode = "search" m.route(root, "/foo1", { "/foo1": { - controller: function() {}, - view: function() { - return m("div", m("a", {config: config}, "foo")); + controller: function () {}, + view: function () { + return m("div", m("a", {config: config}, "foo")) } }, "/bar1": { - controller: function() {}, - view: function() { - return m("main", m("a", {config: config}, "foo")); + controller: function () {}, + view: function () { + return m("main", m("a", {config: config}, "foo")) } } }) @@ -3011,12 +3910,13 @@ function testMithril(mock) { var result = unloaded === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") @@ -3024,12 +3924,12 @@ function testMithril(mock) { m.route.mode = "search" m.route(root, "/foo1", { "/foo1": { - controller: function() { + controller: function () { strategy = m.redraw.strategy() m.redraw.strategy("none") }, - view: function() { - return m("div"); + view: function () { + return m("div") } } }) @@ -3037,32 +3937,34 @@ function testMithril(mock) { var result = strategy === "all" && root.childNodes.length === 0 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") - var strategy, count = 0 - var config = function(el, init) {if (!init) count++} + var count = 0 + var strategy + function config(el, init) { if (!init) count++ } m.route.mode = "search" m.route(root, "/foo1", { "/foo1": { - controller: function() {}, - view: function() { - return m("div", {config: config}); + controller: function () {}, + view: function () { + return m("div", {config: config}) } }, "/bar1": { - controller: function() { + controller: function () { strategy = m.redraw.strategy() m.redraw.strategy("redraw") }, - view: function() { - return m("div", {config: config}); + view: function () { + return m("div", {config: config}) } } }) @@ -3072,12 +3974,13 @@ function testMithril(mock) { var result = strategy === "all" && count === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") @@ -3085,40 +3988,45 @@ function testMithril(mock) { m.route.mode = "search" m.route(root, "/foo1", { "/foo1": { - controller: function() {this.number = 1}, - view: function(ctrl) { - return m("div", {onclick: function() { + controller: function () { this.number = 1 }, + view: function (ctrl) { + return m("div", {onclick: function () { strategy = m.redraw.strategy() ctrl.number++ m.redraw.strategy("none") - }}, ctrl.number); + }}, ctrl.number) } } }) root.childNodes[0].onclick({}) mock.requestAnimationFrame.$resolve() - var result = strategy === "diff" && root.childNodes[0].childNodes[0].nodeValue === "1" + var result = strategy === "diff" && + root.childNodes[0].childNodes[0].nodeValue === "1" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") var count = 0 - var config = function(el, init ) {if (!init) count++} + function config(el, init) { if (!init) count++ } m.route.mode = "search" m.route(root, "/foo1", { "/foo1": { - controller: function() {}, - view: function() { - return m("div", {config: config, onclick: function() { - m.redraw.strategy("all") - }}); + controller: function () {}, + view: function () { + return m("div", { + config: config, + onclick: function () { + m.redraw.strategy("all") + } + }) } } }) @@ -3127,123 +4035,144 @@ function testMithril(mock) { var result = count === 2 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") var value m.route(root, "/foo+bar", { "/:arg": { - controller: function() {value = m.route.param("arg")}, - view: function() { + controller: function () { value = m.route.param("arg") }, + view: function () { return "" } } }) var result = value === "foo+bar" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { - "/": {controller: function() {}, view: function() {return "foo"}}, - "/test22": {controller: function() {}, view: function() {return "bar"}} + "/": { + controller: function () {}, + view: function () { return "foo" } + }, + "/test22": { + controller: function () {}, + view: function () { return "bar" } + } }) mock.requestAnimationFrame.$resolve() m.route(String("/test22/")) mock.requestAnimationFrame.$resolve() - var result = mock.location.search === "?/test22/" && root.childNodes[0].nodeValue === "bar" + var result = mock.location.search === "?/test22/" && + root.childNodes[0].nodeValue === "bar" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { - "/": {controller: function() {}, view: function() {return "foo"}}, - "/test23": {controller: function() {}, view: function() {return "bar"}} + "/": { + controller: function () {}, + view: function () { return "foo" } + }, + "/test23": { + controller: function () {}, + view: function () { return "bar" } + } }) mock.requestAnimationFrame.$resolve() - m.route(new String("/test23/")) + m.route(new String("/test23/")) // eslint-disable-line no-new-wrappers mock.requestAnimationFrame.$resolve() - var result = mock.location.search === "?/test23/" && root.childNodes[0].nodeValue === "bar" + var result = mock.location.search === "?/test23/" && + root.childNodes[0].nodeValue === "bar" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") var value m.route(root, String("/foo+bar"), { "/:arg": { - controller: function() {value = m.route.param("arg")}, - view: function() { - return "" - } + controller: function () { value = m.route.param("arg") }, + view: function () { return "" } } }) var result = value === "foo+bar" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - mock.requestAnimationFrame.$resolve() //setup + + test(function () { + mock.requestAnimationFrame.$resolve() // setup mock.location.search = "?" var root = mock.document.createElement("div") + /* eslint-disable no-new-wrappers */ + var initial = new String("/foo+bar") + /* eslint-enable no-new-wrappers */ var value - m.route(root, new String("/foo+bar"), { + m.route(root, initial, { "/:arg": { - controller: function() {value = m.route.param("arg")}, - view: function() { + controller: function () { value = m.route.param("arg") }, + view: function () { return "" } } }) var result = value === "foo+bar" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var a = {} - a.controller = function() {m.route("/b")} - a.view = function() {return "a"} + a.controller = function () { m.route("/b") } + a.view = function () { return "a" } var b = {} - b.controller = function() {} - b.view = function() {return "b"} + b.controller = function () {} + b.view = function () { return "b" } m.route(root, "/a", { "/a": a, @@ -3253,25 +4182,26 @@ function testMithril(mock) { var result = root.childNodes[0].nodeValue === "b" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var a = {} - a.controller = function() { + a.controller = function () { m.route("/b?foo=1", {foo: 2}) } - a.view = function() {return "a"} + a.view = function () { return "a" } var b = {} - b.controller = function() {} - b.view = function() {return "b"} + b.controller = function () {} + b.view = function () { return "b" } m.route(root, "/", { "/": a, @@ -3281,12 +4211,12 @@ function testMithril(mock) { var result = mock.location.search === "?/b?foo=2" - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result - }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" mock.history.$$length = 0 @@ -3294,12 +4224,12 @@ function testMithril(mock) { var root = mock.document.createElement("div") var a = {} - a.controller = function() {} - a.view = function() {return "a"} + a.controller = function () {} + a.view = function () { return "a" } var b = {} - b.controller = function() {} - b.view = function() {return "b"} + b.controller = function () {} + b.view = function () { return "b" } m.route(root, "/a", { "/a": a, @@ -3313,12 +4243,12 @@ function testMithril(mock) { var result = mock.history.$$length === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result - }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" mock.history.$$length = 0 @@ -3326,12 +4256,12 @@ function testMithril(mock) { var root = mock.document.createElement("div") var a = {} - a.controller = function() {} - a.view = function() {return "a"} + a.controller = function () {} + a.view = function () { return "a" } var b = {} - b.controller = function() {} - b.view = function() {return "b"} + b.controller = function () {} + b.view = function () { return "b" } m.route(root, "/a", { "/a": a, @@ -3345,11 +4275,12 @@ function testMithril(mock) { var result = mock.history.$$length === 0 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3357,15 +4288,15 @@ function testMithril(mock) { var initCount = 0 var a = {} - a.controller = function() {} - a.view = function() { - return m("a", {config: function(el, init) { + a.controller = function () {} + a.view = function () { + return m("a", {config: function (el, init) { if (!init) initCount++ }}) } var b = {} - b.controller = function() {} + b.controller = function () {} b.view = a.view m.route(root, "/a", { @@ -3380,11 +4311,12 @@ function testMithril(mock) { var result = initCount === 2 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3392,16 +4324,16 @@ function testMithril(mock) { var initCount = 0 var a = {} - a.controller = function() {} - a.view = function() { - return m("a", {config: function(el, init, ctx) { + a.controller = function () {} + a.view = function () { + return m("a", {config: function (el, init, ctx) { ctx.retain = false if (!init) initCount++ }}) } var b = {} - b.controller = function() {} + b.controller = function () {} b.view = a.view m.route(root, "/a", { @@ -3416,11 +4348,12 @@ function testMithril(mock) { var result = initCount === 2 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3428,16 +4361,16 @@ function testMithril(mock) { var initCount = 0 var a = {} - a.controller = function() {} - a.view = function() { - return m("a", {config: function(el, init, ctx) { + a.controller = function () {} + a.view = function () { + return m("a", {config: function (el, init, ctx) { ctx.retain = true if (!init) initCount++ }}) } var b = {} - b.controller = function() {} + b.controller = function () {} b.view = a.view m.route(root, "/a", { @@ -3452,11 +4385,12 @@ function testMithril(mock) { var result = initCount === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3464,15 +4398,15 @@ function testMithril(mock) { var initCount = 0 var a = {} - a.controller = function() {m.redraw.strategy("diff")} - a.view = function() { - return m("a", {config: function(el, init) { + a.controller = function () { m.redraw.strategy("diff") } + a.view = function () { + return m("a", {config: function (el, init) { if (!init) initCount++ }}) } var b = {} - b.controller = function() {m.redraw.strategy("diff")} + b.controller = function () { m.redraw.strategy("diff") } b.view = a.view m.route(root, "/a", { @@ -3487,11 +4421,12 @@ function testMithril(mock) { var result = initCount === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3499,16 +4434,16 @@ function testMithril(mock) { var initCount = 0 var a = {} - a.controller = function() {m.redraw.strategy("diff")} - a.view = function() { - return m("a", {config: function(el, init, ctx) { + a.controller = function () { m.redraw.strategy("diff") } + a.view = function () { + return m("a", {config: function (el, init, ctx) { ctx.retain = true if (!init) initCount++ }}) } var b = {} - b.controller = function() {m.redraw.strategy("diff")} + b.controller = function () { m.redraw.strategy("diff") } b.view = a.view m.route(root, "/a", { @@ -3523,11 +4458,12 @@ function testMithril(mock) { var result = initCount === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3535,16 +4471,16 @@ function testMithril(mock) { var initCount = 0 var a = {} - a.controller = function() {m.redraw.strategy("diff")} - a.view = function() { - return m("a", {config: function(el, init, ctx) { + a.controller = function () { m.redraw.strategy("diff") } + a.view = function () { + return m("a", {config: function (el, init, ctx) { ctx.retain = false if (!init) initCount++ }}) } var b = {} - b.controller = function() {m.redraw.strategy("diff")} + b.controller = function () { m.redraw.strategy("diff") } b.view = a.view m.route(root, "/a", { @@ -3559,11 +4495,12 @@ function testMithril(mock) { var result = initCount === 2 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3571,18 +4508,18 @@ function testMithril(mock) { var initCount = 0 var a = {} - a.controller = function() {} - a.view = function() { - return m("div", m("a", {config: function(el, init, ctx) { + a.controller = function () {} + a.view = function () { + return m("div", m("a", {config: function (el, init, ctx) { ctx.retain = true if (!init) initCount++ }})) } var b = {} - b.controller = function() {} - b.view = function() { - return m("section", m("a", {config: function(el, init, ctx) { + b.controller = function () {} + b.view = function () { + return m("section", m("a", {config: function (el, init, ctx) { ctx.retain = true if (!init) initCount++ }})) @@ -3600,11 +4537,12 @@ function testMithril(mock) { var result = initCount === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3612,18 +4550,18 @@ function testMithril(mock) { var initCount = 0 var a = {} - a.controller = function() {} - a.view = function() { - return m("div", m("a", {config: function(el, init, ctx) { + a.controller = function () {} + a.view = function () { + return m("div", m("a", {config: function (el, init, ctx) { ctx.retain = false if (!init) initCount++ }})) } var b = {} - b.controller = function() {} - b.view = function() { - return m("section", m("a", {config: function(el, init, ctx) { + b.controller = function () {} + b.view = function () { + return m("section", m("a", {config: function (el, init, ctx) { ctx.retain = false if (!init) initCount++ }})) @@ -3641,11 +4579,12 @@ function testMithril(mock) { var result = initCount === 2 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3653,17 +4592,17 @@ function testMithril(mock) { var initCount = 0 var a = {} - a.controller = function() {} - a.view = function() { - return m("div", m("a", {config: function(el, init) { + a.controller = function () {} + a.view = function () { + return m("div", m("a", {config: function (el, init) { if (!init) initCount++ }})) } var b = {} - b.controller = function() {} - b.view = function() { - return m("section", m("a", {config: function(el, init) { + b.controller = function () {} + b.view = function () { + return m("section", m("a", {config: function (el, init) { if (!init) initCount++ }})) } @@ -3680,11 +4619,12 @@ function testMithril(mock) { var result = initCount === 2 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3692,18 +4632,18 @@ function testMithril(mock) { var initCount = 0 var a = {} - a.controller = function() {m.redraw.strategy("diff")} - a.view = function() { - return m("div", m("a", {config: function(el, init, ctx) { + a.controller = function () { m.redraw.strategy("diff") } + a.view = function () { + return m("div", m("a", {config: function (el, init, ctx) { ctx.retain = true if (!init) initCount++ }})) } var b = {} - b.controller = function() {m.redraw.strategy("diff")} - b.view = function() { - return m("section", m("a", {config: function(el, init, ctx) { + b.controller = function () { m.redraw.strategy("diff") } + b.view = function () { + return m("section", m("a", {config: function (el, init, ctx) { ctx.retain = true if (!init) initCount++ }})) @@ -3721,11 +4661,12 @@ function testMithril(mock) { var result = initCount === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3733,18 +4674,18 @@ function testMithril(mock) { var initCount = 0 var a = {} - a.controller = function() {m.redraw.strategy("diff")} - a.view = function() { - return m("div", m("a", {config: function(el, init, ctx) { + a.controller = function () { m.redraw.strategy("diff") } + a.view = function () { + return m("div", m("a", {config: function (el, init, ctx) { ctx.retain = false if (!init) initCount++ }})) } var b = {} - b.controller = function() {m.redraw.strategy("diff")} - b.view = function() { - return m("section", m("a", {config: function(el, init, ctx) { + b.controller = function () { m.redraw.strategy("diff") } + b.view = function () { + return m("section", m("a", {config: function (el, init, ctx) { ctx.retain = false if (!init) initCount++ }})) @@ -3762,11 +4703,12 @@ function testMithril(mock) { var result = initCount === 2 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3774,17 +4716,17 @@ function testMithril(mock) { var initCount = 0 var a = {} - a.controller = function() {m.redraw.strategy("diff")} - a.view = function() { - return m("div", m("a", {config: function(el, init) { + a.controller = function () { m.redraw.strategy("diff") } + a.view = function () { + return m("div", m("a", {config: function (el, init) { if (!init) initCount++ }})) } var b = {} - b.controller = function() {m.redraw.strategy("diff")} - b.view = function() { - return m("section", m("a", {config: function(el, init) { + b.controller = function () { m.redraw.strategy("diff") } + b.view = function () { + return m("section", m("a", {config: function (el, init) { if (!init) initCount++ }})) } @@ -3801,12 +4743,13 @@ function testMithril(mock) { var result = initCount === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { - //retain flag should work inside component + + test(function () { + // retain flag should work inside component mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3814,26 +4757,26 @@ function testMithril(mock) { var initCount = 0 var a = {} - a.controller = function() {} - a.view = function() { - return m("div", m("a", {config: function(el, init, ctx) { + a.controller = function () {} + a.view = function () { + return m("div", m("a", {config: function (el, init, ctx) { ctx.retain = true if (!init) initCount++ }})) } var b = {} - b.controller = function() {m.redraw.strategy("diff")} - b.view = function() { - return m("section", m("a", {config: function(el, init, ctx) { + b.controller = function () { m.redraw.strategy("diff") } + b.view = function () { + return m("section", m("a", {config: function (el, init, ctx) { ctx.retain = true if (!init) initCount++ }})) } m.route(root, "/a", { - "/a": {view: function() {return m("div", a)}}, - "/b": {view: function() {return m("div", b)}} + "/a": {view: function () { return m("div", a) }}, + "/b": {view: function () { return m("div", b) }} }) mock.requestAnimationFrame.$resolve() @@ -3842,11 +4785,12 @@ function testMithril(mock) { mock.requestAnimationFrame.$resolve() var result = initCount === 1 - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result }) - test(function() { + + test(function () { // https://github.com/lhorie/mithril.js/pull/571 mock.requestAnimationFrame.$resolve() mock.location.search = "?" @@ -3854,16 +4798,16 @@ function testMithril(mock) { var root = mock.document.createElement("div") var a = {} - a.controller = function() {} - a.view = function() { - return m("div", {config: function(elm) { + a.controller = function () {} + a.view = function () { + return m("div", {config: function (elm) { elm.childNodes[0].modified = true }}, m("div")) } var b = {} - b.controller = function() {} - b.view = function() { + b.controller = function () {} + b.view = function () { return m("div", m("div")) } @@ -3876,29 +4820,43 @@ function testMithril(mock) { m.route("/b") mock.requestAnimationFrame.$resolve() - var result = !root.childNodes[0].childNodes[0].modified; + var result = !root.childNodes[0].childNodes[0].modified - m.mount(root, null) //teardown + m.mount(root, null) // teardown return result - }); - //end m.route + }) + // end m.route - //m.route.parseQueryString - test(function() { - var args = m.route.parseQueryString("foo=bar&hello%5B%5D=world&hello%5B%5D=mars&hello%5B%5D=pluto") - return args["hello[]"] instanceof Array && args["hello[]"].indexOf("world") > -1 && args["hello[]"].indexOf("mars") > -1 && args["hello[]"].indexOf("pluto") > -1 + // m.route.parseQueryString + test(function () { + var str = "foo=bar&hello%5B%5D=world&hello%5B%5D=mars&hello%5B%5D=pluto" + var args = m.route.parseQueryString(str) + + return args["hello[]"] instanceof Array && + args["hello[]"].indexOf("world") > -1 && + args["hello[]"].indexOf("mars") > -1 && + args["hello[]"].indexOf("pluto") > -1 }) - test(function() { - var args = m.route.parseQueryString("foo=bar&hello=world&hello=mars&bam=&yup") - return args.foo === "bar" && args.hello[0] === "world" && args.hello[1] === "mars" && args.bam === "" && args.yup == null + + test(function () { + var str = "foo=bar&hello=world&hello=mars&bam=&yup" + var args = m.route.parseQueryString(str) + + return args.foo === "bar" && + args.hello[0] === "world" && + args.hello[1] === "mars" && + args.bam === "" && + args.yup == null }) - test(function() { + + test(function () { var args = m.route.parseQueryString("") return Object.keys(args).length === 0 }) - //m.route.buildQueryString - test(function() { + + // m.route.buildQueryString + test(function () { var string = m.route.buildQueryString({ foo: "bar", hello: ["world", "mars", "mars"], @@ -3909,38 +4867,47 @@ function testMithril(mock) { yup: null, removed: undefined }) - return string === "foo=bar&hello=world&hello=mars&world%5Btest%5D=3&bam=&yup" + var expected = "foo=bar&hello=world&hello=mars&" + + "world%5Btest%5D=3&bam=&yup" + return string === expected }) - test(function() { - var string = m.route.buildQueryString({}); + + test(function () { + var string = m.route.buildQueryString({}) return string === "" }) - //m.prop - test(function() { + + // m.prop + test(function () { var prop = m.prop("test") return prop() === "test" }) - test(function() { + + test(function () { var prop = m.prop("test") prop("foo") return prop() === "foo" }) - test(function() { + + test(function () { var prop = m.prop("test") return JSON.stringify(prop) === '"test"' }) - test(function() { + + test(function () { var obj = {prop: m.prop("test")} return JSON.stringify(obj) === '{"prop":"test"}' }) - test(function() { + + test(function () { var defer = m.deferred() var prop = m.prop(defer.promise) defer.resolve("test") return prop() === "test" }) - test(function() { + + test(function () { var defer = m.deferred() var prop = m.prop(defer.promise).then(function () { return "test2" @@ -3949,113 +4916,183 @@ function testMithril(mock) { return prop() === "test2" }) - test(function() { + + test(function () { var prop = m.prop(null) return prop() === null }) - //m.request - test(function() { + // m.request + test(function () { var prop = m.request({method: "GET", url: "test"}) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().method === "GET" && prop().url === "test" }) - test(function() { - var prop = m.request({method: "GET", url: "test"}).then(function() {return "foo"}) + + test(function () { + var prop = m.request({method: "GET", url: "test"}) + .then(function () { return "foo" }) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop() === "foo" }) - test(function() { - var prop = m.request({method: "POST", url: "http://domain.com:80", data: {}}).then(function(value) {return value}) + + test(function () { + var prop = m.request({ + method: "POST", url: "http://domain.com:80", + data: {} + }).then(function (value) { return value }) + mock.XMLHttpRequest.$instances.pop().onreadystatechange() + return prop().url === "http://domain.com:80" }) - test(function() { - var prop = m.request({method: "POST", url: "http://domain.com:80/:test1", data: {test1: "foo"}}).then(function(value) {return value}) + + test(function () { + var prop = m.request({ + method: "POST", + url: "http://domain.com:80/:test1", + data: {test1: "foo"} + }).then(function (value) { return value }) + mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().url === "http://domain.com:80/foo" }) - test(function() { + + test(function () { var error = m.prop("no error") - var prop = m.request({method: "GET", url: "test", deserialize: function() {throw new Error("error occurred")}}).then(null, error) + + var prop = m.request({ + method: "GET", + url: "test", + deserialize: function () { throw new Error("error occurred") } + }).then(null, error) + mock.XMLHttpRequest.$instances.pop().onreadystatechange() - return prop().message === "error occurred" && error().message === "error occurred" + return prop().message === "error occurred" && + error().message === "error occurred" }) - test(function() { + + test(function () { var error = m.prop("no error") - var prop = m.request({method: "GET", url: "test", deserialize: function() {throw new Error("error occurred")}})["catch"](error) + + var prop = m.request({ + method: "GET", + url: "test", + deserialize: function () { throw new Error("error occurred") } + }).catch(error) + mock.XMLHttpRequest.$instances.pop().onreadystatechange() - return prop().message === "error occurred" && error().message === "error occurred" + return prop().message === "error occurred" && + error().message === "error occurred" }) - 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) - try {mock.XMLHttpRequest.$instances.pop().onreadystatechange()} - catch (e) {exception = e} - return prop() === undefined && error() === "no error" && exception.message === "error occurred" - }) - test(function() { + + test(function () { var error = m.prop("no error") - m.request({method: "POST", url: "test", data: {foo: 1}}).then(null, error) + var exception + + var prop = m.request({ + method: "GET", + url: "test", + deserialize: function () { throw new TypeError("error occurred") } + }).then(null, error) + + try { + mock.XMLHttpRequest.$instances.pop().onreadystatechange() + } catch (e) { + exception = e + } + + return prop() === undefined && + error() === "no error" && + exception.message === "error occurred" + }) + + test(function () { + var error = m.prop("no error") + + m.request({method: "POST", url: "test", data: {foo: 1}}) + .then(null, error) + var xhr = mock.XMLHttpRequest.$instances.pop() xhr.onreadystatechange() - return xhr.$headers["Content-Type"] === "application/json; charset=utf-8" + + var expected = "application/json; charset=utf-8" + + return xhr.$headers["Content-Type"] === expected }) - test(function() { + + test(function () { var error = m.prop("no error") m.request({method: "POST", url: "test"}).then(null, error) var xhr = mock.XMLHttpRequest.$instances.pop() xhr.onreadystatechange() return xhr.$headers["Content-Type"] === undefined }) - test(function() { - var prop = m.request({method: "POST", url: "test", initialValue: "foo"}).then(function(data) { return data; }) - var initialValue = prop(); - mock.XMLHttpRequest.$instances.pop().onreadystatechange() - return initialValue === "foo" - }) - test(function() { + test(function () { var prop = m.request({method: "POST", url: "test", initialValue: "foo"}) - var initialValue = prop(); + .then(function (data) { return data }) + + var initialValue = prop() mock.XMLHttpRequest.$instances.pop().onreadystatechange() return initialValue === "foo" }) - test(function() { - var prop = m.request({method: "POST", url: "test", initialValue: "foo"}).then(function() {return "bar"}) + + test(function () { + var prop = m.request({method: "POST", url: "test", initialValue: "foo"}) + var initialValue = prop() + mock.XMLHttpRequest.$instances.pop().onreadystatechange() + + return initialValue === "foo" + }) + + test(function () { + var prop = m.request({method: "POST", url: "test", initialValue: "foo"}) + .then(function () { return "bar" }) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop() === "bar" }) - test(function() { + + test(function () { var prop = m.request({method: "GET", url: "test", data: {foo: 1}}) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().url === "test?foo=1" }) - test(function() { + + test(function () { var prop = m.request({method: "POST", url: "test", data: {foo: 1}}) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().url === "test" }) - test(function() { + + test(function () { var prop = m.request({method: "GET", url: "test", data: {foo: [1, 2]}}) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().url === "test?foo=1&foo=2" }) - test(function() { + + test(function () { var value var prop1 = m.request({method: "GET", url: "test", initialValue: 123}) + var val1 = prop1() - var prop2 = prop1.then(function() {return 1}) + var prop2 = prop1.then(function () { return 1 }) var val2 = prop2() - var prop3 = prop1.then(function(v) {value = v}) + var prop3 = prop1.then(function (v) { value = v }) var val3 = prop3() + mock.XMLHttpRequest.$instances.pop().onreadystatechange() - return val1 === 123 && val2 === 123 && val3 === 123 && value.method === "GET" && value.url === "test" + + return val1 === 123 && + val2 === 123 && + val3 === 123 && + value.method === "GET" && + value.url === "test" }) // m.request over jsonp - test(function(){ + test(function (){ // script tags cannot be appended directly on the document var body = mock.document.createElement("body") mock.document.body = body @@ -4063,18 +5100,22 @@ function testMithril(mock) { var error = m.prop("no error") var data - m.request({url: "/test", dataType: "jsonp"}).then(function(received) {data = received}, error) - var callbackKey = Object.keys(mock).filter(function(globalKey){ + m.request({url: "/test", dataType: "jsonp"}) + .then(function (received) { data = received }, error) + var callbackKey = Object.keys(mock).filter(function (globalKey){ return globalKey.indexOf("mithril_callback") > -1 }).pop() - var scriptTag = [].slice.call(mock.document.getElementsByTagName("script")).filter(function(script){ + var scripts = mock.document.getElementsByTagName("script") + var scriptTag = [].slice.call(scripts).filter(function (script){ return script.src.indexOf(callbackKey) > -1 }).pop() mock[callbackKey]({foo: "bar"}) mock.document.removeChild(body) - return scriptTag.src.indexOf("/test?callback=mithril_callback") > -1 && data.foo === "bar" + return scriptTag.src.indexOf("/test?callback=mithril_callback") > -1 && + data.foo === "bar" }) - test(function(){ + + test(function (){ // script tags cannot be appended directly on the document var body = mock.document.createElement("body") mock.document.body = body @@ -4082,300 +5123,418 @@ function testMithril(mock) { var error = m.prop("no error") var data - m.request({url: "/test", dataType: "jsonp", callbackKey: "jsonpCallback"}).then(function(received) {data = received}, error) - var callbackKey = Object.keys(mock).filter(function(globalKey){ + m.request({ + url: "/test", + dataType: "jsonp", + callbackKey: "jsonpCallback" + }).then(function (received) { data = received }, error) + + var callbackKey = Object.keys(mock).filter(function (globalKey){ return globalKey.indexOf("mithril_callback") > -1 }).pop() - var scriptTag = [].slice.call(mock.document.getElementsByTagName("script")).filter(function(script){ + + var scripts = mock.document.getElementsByTagName("script") + var scriptTag = [].slice.call(scripts).filter(function (script){ return script.src.indexOf(callbackKey) > -1 - }).pop(); + }).pop() + mock[callbackKey]({foo: "bar1"}) mock.document.removeChild(body) - return scriptTag.src.indexOf("/test?jsonpCallback=mithril_callback") > -1 && data.foo === "bar1" + + var url = "/test?jsonpCallback=mithril_callback" + return scriptTag.src.indexOf(url) > -1 && + data.foo === "bar1" }) - test(function(){ + + test(function (){ var body = mock.document.createElement("body") mock.document.body = body mock.document.appendChild(body) var req = m.request({url: "/test", dataType: "jsonp"}) - var callbackKey = Object.keys(mock).filter(function(globalKey){ + var callbackKey = Object.keys(mock).filter(function (globalKey){ return globalKey.indexOf("mithril_callback") > -1 }).pop() - ;[].slice.call(mock.document.getElementsByTagName("script")).filter(function(script){ + var scripts = mock.document.getElementsByTagName("script") + ;[].slice.call(scripts).filter(function (script){ return script.src.indexOf(callbackKey) > -1 - }).pop(); + }).pop() mock[callbackKey]({foo: "bar1"}) var out = {foo: "bar1"} mock.document.removeChild(body) return JSON.stringify(out) === JSON.stringify(req()) }) - test(function(){ + + test(function (){ var body = mock.document.createElement("body") mock.document.body = body mock.document.appendChild(body) m.request({url: "/test", dataType: "jsonp", data: {foo: "bar"}}) - var callbackKey = Object.keys(mock).filter(function(globalKey){ + var callbackKey = Object.keys(mock).filter(function (globalKey){ return globalKey.indexOf("mithril_callback") > -1 }).pop() - var scriptTag = [].slice.call(mock.document.getElementsByTagName("script")).filter(function(script){ + var scripts = mock.document.getElementsByTagName("script") + var scriptTag = [].slice.call(scripts).filter(function (script){ return script.src.indexOf(callbackKey) > -1 - }).pop(); + }).pop() mock[callbackKey]({foo: "bar"}) return scriptTag.src.indexOf("foo=bar") > -1 }) - test(function(){ - var body = mock.document.createElement("body"); - mock.document.body = body; - mock.document.appendChild(body); - m.request({url: "/test", dataType: "jsonp", method: "GET", data: {foo: "bar"}}); - var callbackKey = Object.keys(mock).filter(function(globalKey){ + test(function (){ + var body = mock.document.createElement("body") + mock.document.body = body + mock.document.appendChild(body) + + m.request({ + url: "/test", + dataType: "jsonp", + method: "GET", + data: {foo: "bar"} + }) + var callbackKey = Object.keys(mock).filter(function (globalKey){ return globalKey.indexOf("mithril_callback") > -1 }).pop() - var scriptTag = [].slice.call(mock.document.getElementsByTagName("script")).filter(function(script){ + var scripts = mock.document.getElementsByTagName("script") + var scriptTag = [].slice.call(scripts).filter(function (script){ return script.src.indexOf(callbackKey) > -1 - }).pop(); + }).pop() mock[callbackKey]({foo: "bar"}) - mock.document.removeChild(body); - return scriptTag.src.match(/foo=bar/g).length === 1; + mock.document.removeChild(body) + return scriptTag.src.match(/foo=bar/g).length === 1 }) - //m.deferred - test(function() { - var value + // m.deferred + test(function () { var deferred = m.deferred() - deferred.promise.then(function(data) {value = data}) + var value + deferred.promise.then(function (data) { value = data }) deferred.resolve("test") return value === "test" }) - test(function() { - var value + + test(function () { var deferred = m.deferred() - deferred.promise.then(function() {return "foo"}).then(function(data) {value = data}) + var value + + deferred.promise + .then(function () { return "foo" }) + .then(function (data) { value = data }) + deferred.resolve("test") return value === "foo" }) - test(function() { - var value + + test(function () { var deferred = m.deferred() - deferred.promise.then(null, function(data) {value = data}) + var value + deferred.promise.then(null, function (data) { value = data }) deferred.reject("test") return value === "test" }) - test(function() { + + test(function () { var value var deferred = m.deferred() - deferred.promise["catch"](function(data) {value = data}) + deferred.promise.catch(function (data) { value = data }) deferred.reject("test") return value === "test" }) - test(function() { - var value + + test(function () { var deferred = m.deferred() - deferred.promise.then(null, function() {return "foo"}).then(function(data) {value = data}) + var value + + deferred.promise + .then(null, function () { return "foo" }) + .then(function (data) { value = data }) + deferred.reject("test") return value === "foo" }) - test(function() { - var value + + test(function () { var deferred = m.deferred() - deferred.promise["catch"](function() {return "foo"}).then(function(data) {value = data}) + var value + + deferred.promise + .catch(function () { return "foo" }) + .then(function (data) { value = data }) + deferred.reject("test") return value === "foo" }) - test(function() { + + test(function () { + var deferred = m.deferred() var value1, value2 - var deferred = m.deferred() - deferred.promise.then(function() {throw new Error()}).then(function() {value1 = 1}, function(data) {value2 = data}) + + deferred.promise + .then(function () { throw new Error() }) + .then(function () { value1 = 1 }, function (data) { value2 = data }) + deferred.resolve("test") return value1 === undefined && value2 instanceof Error }) - test(function() { - //Let unchecked exceptions bubble up in order to allow meaningful error messages in common cases like null reference exceptions due to typos - //An unchecked exception is defined as an object that is a subclass of Error (but not a direct instance of Error itself) - basically anything that can be thrown without an explicit `throw` keyword and that we'd never want to programmatically manipulate. In other words, an unchecked error is one where we only care about its line number and where the only reasonable way to deal with it is to change the buggy source code that caused the error to be thrown in the first place. - //By contrast, a checked exception is defined as anything that is explicitly thrown via the `throw` keyword and that can be programmatically handled, for example to display a validation error message on the UI. If an exception is a subclass of Error for whatever reason, but it is meant to be handled as a checked exception (i.e. follow the rejection rules for A+), it can be rethrown as an instance of Error - //This test tests two implementation details that differ from the Promises/A+ spec: - //1) A+ requires the `then` callback to be called in a different event loop from the resolve call, i.e. it must be asynchronous (this requires a setImmediate polyfill, which cannot be implemented in a reasonable way for Mithril's purpose - the possible polyfills are either too big or too slow) - //2) A+ swallows exceptions in a unrethrowable way, i.e. it's not possible to see default error messages on the console for runtime errors thrown from within a promise chain - var value1, value2, value3 + + test(function () { + // Let unchecked exceptions bubble up in order to allow meaningful error + // messages in common cases like null reference exceptions due to typos + // + // An unchecked exception is defined as an object that is a subclass of + // Error (but not a direct instance of Error itself) - basically + // anything that can be thrown without an explicit `throw` keyword and + // that we'd never want to programmatically manipulate. In other words, + // an unchecked error is one where we only care about its line number + // and where the only reasonable way to deal with it is to change the + // buggy source code that caused the error to be thrown in the first + // place. + // + // By contrast, a checked exception is defined as anything that is + // explicitly thrown via the `throw` keyword and that can be + // programmatically handled, for example to display a validation error + // message on the UI. If an exception is a subclass of Error for + // whatever reason, but it is meant to be handled as a checked exception + // (i.e. follow the rejection rules for A+), it can be rethrown as an + // instance of Error + // + // This test tests two implementation details that differ from the + // Promises/A+ spec: + // + // 1) A+ requires the `then` callback to be called in a different event + // loop from the resolve call, i.e. it must be asynchronous (this + // requires a setImmediate polyfill, which cannot be implemented in a + // reasonable way for Mithril's purpose - the possible polyfills are + // either too big or too slow) + // + // 2) A+ swallows exceptions in a unrethrowable way, i.e. it's not + // possible to see default error messages on the console for runtime + // errors thrown from within a promise chain var deferred = m.deferred() + var value1, value2, value3 + try { deferred.promise - .then(function() {foo.bar.baz}) //throws ReferenceError - .then(function() {value1 = 1}, function(data) {value2 = data}) + /* eslint-disable no-undef */ + // throws ReferenceError + .then(function () { return foo.bar.baz }) + /* eslint-enable no-undef */ + .then( + function () { value1 = 1 }, + function (data) { value2 = data } + ) deferred.resolve("test") + } catch (e) { + value3 = e } - catch (e) {value3 = e} - return value1 === undefined && value2 === undefined && (value3 instanceof ReferenceError || value3 instanceof TypeError) + + return value1 === undefined && + value2 === undefined && + (value3 instanceof ReferenceError || value3 instanceof TypeError) }) - test(function() { + + test(function () { var deferred1 = m.deferred() var deferred2 = m.deferred() var value1, value2 - deferred1.promise.then(function(data) { + deferred1.promise.then(function (data) { value1 = data return deferred2.promise - }).then(function(data) { + }).then(function (data) { value2 = data }) deferred1.resolve(1) deferred2.resolve(2) return value1 === 1 && value2 === 2 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/80 - var deferred = m.deferred(), value + + test(function () { + // https://github.com/lhorie/mithril.js/issues/80 + var deferred = m.deferred() + var value + deferred.resolve(1) - deferred.promise.then(function(data) { + deferred.promise.then(function (data) { value = data }) + return value === 1 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/80 - var deferred = m.deferred(), value + + test(function () { + // https://github.com/lhorie/mithril.js/issues/80 + var deferred = m.deferred() + var value + deferred.reject(1) - deferred.promise.then(null, function(data) { + deferred.promise.then(null, function (data) { value = data }) + return value === 1 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/80 - var deferred = m.deferred(), value + + test(function () { + // https://github.com/lhorie/mithril.js/issues/80 + var deferred = m.deferred() + var value deferred.resolve(1) deferred.resolve(2) - deferred.promise.then(function(data) { + deferred.promise.then(function (data) { value = data }) return value === 1 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/80 - var deferred = m.deferred(), value - deferred.promise.then(function(data) { + + test(function () { + // https://github.com/lhorie/mithril.js/issues/80 + var deferred = m.deferred() + var value + deferred.promise.then(function (data) { value = data }) deferred.resolve(1) deferred.resolve(2) return value === 1 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/80 - var deferred = m.deferred(), value1, value2 - deferred.promise.then(function(data) { + + test(function () { + // https://github.com/lhorie/mithril.js/issues/80 + var deferred = m.deferred() + var value1, value2 + deferred.promise.then(function (data) { value1 = data - }, function(data) { + }, function (data) { value2 = data }) deferred.resolve(1) deferred.reject(2) return value1 === 1 && value2 === undefined }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/80 - var deferred = m.deferred(), value1, value2 - deferred.promise.then(function(data) { + + test(function () { + // https://github.com/lhorie/mithril.js/issues/80 + var deferred = m.deferred() + var value1, value2 + deferred.promise.then(function (data) { value1 = data - }, function(data) { + }, function (data) { value2 = data }) deferred.reject(1) deferred.resolve(2) return value1 === undefined && value2 === 1 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/80 - var deferred = m.deferred(), value - deferred.promise.then(null, function(data) { + + test(function () { + // https://github.com/lhorie/mithril.js/issues/80 + var deferred = m.deferred() + var value + deferred.promise.then(null, function (data) { value = data }) deferred.reject(1) deferred.reject(2) return value === 1 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/85 - var deferred = m.deferred(), value + + test(function () { + // https://github.com/lhorie/mithril.js/issues/85 + var deferred = m.deferred() + var value deferred.resolve() - deferred.promise.then(function() { + deferred.promise.then(function () { value = 1 }) return value === 1 }) - test(function() { - //https://github.com/lhorie/mithril.js/issues/85 - var deferred = m.deferred(), value + + test(function () { + // https://github.com/lhorie/mithril.js/issues/85 + var deferred = m.deferred() + var value deferred.reject() - deferred.promise.then(null, function() { + deferred.promise.then(null, function () { value = 1 }) return value === 1 }) - test(function() { + + test(function () { var deferred = m.deferred() deferred.resolve(1) return deferred.promise() === 1 }) - test(function() { + + test(function () { var deferred = m.deferred() - var promise = deferred.promise.then(function(data) {return data + 1}) + var promise = deferred.promise.then(function (data) { return data + 1 }) deferred.resolve(1) return promise() === 2 }) - test(function() { + + test(function () { var deferred = m.deferred() deferred.reject(1) return deferred.promise() === undefined }) - //m.sync - test(function() { + // m.sync + test(function () { var value var deferred1 = m.deferred() var deferred2 = m.deferred() - m.sync([deferred1.promise, deferred2.promise]).then(function(data) {value = data}) + + m.sync([deferred1.promise, deferred2.promise]) + .then(function (data) { value = data }) + deferred1.resolve("test") deferred2.resolve("foo") return value[0] === "test" && value[1] === "foo" }) - test(function() { + + test(function () { var value var deferred1 = m.deferred() var deferred2 = m.deferred() - m.sync([deferred1.promise, deferred2.promise]).then(function(data) {value = data}) + + m.sync([deferred1.promise, deferred2.promise]) + .then(function (data) { value = data }) + deferred2.resolve("foo") deferred1.resolve("test") return value[0] === "test" && value[1] === "foo" }) - test(function() { + + test(function () { var value var deferred = m.deferred() - m.sync([deferred.promise])["catch"](function(data) {value = data}) + m.sync([deferred.promise]).catch(function (data) { value = data }) deferred.reject("fail") return value[0] === "fail" }) - test(function() { + + test(function () { var value = 1 - m.sync([]).then(function() {value = 2}) + m.sync([]).then(function () { value = 2 }) return value === 2 }) - test(function() { + + test(function () { var success - m.sync([]).then(function(value) {success = value instanceof Array}) + m.sync([]).then(function (value) { success = value instanceof Array }) return success }) - //m.startComputation/m.endComputation - test(function() { + // m.startComputation/m.endComputation + test(function () { mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var controller = m.mount(root, { - controller: function() {}, - view: function(ctrl) {return ctrl.value} + controller: function () {}, + view: function (ctrl) { return ctrl.value } }) mock.requestAnimationFrame.$resolve() @@ -4388,44 +5547,45 @@ function testMithril(mock) { }) // config context - test(function() { + test(function () { var root = mock.document.createElement("div") - var success = false; - m.render(root, m("div", {config: function(elem, isInitialized, ctx) {ctx.data=1}})); - m.render(root, m("div", {config: function(elem, isInitialized, ctx) {success = ctx.data===1}})); - return success; + var success = false + + m.render(root, m("div", { + config: function (elem, isInit, ctx) { ctx.data = 1 } + })) + + m.render(root, m("div", { + config: function (elem, isInit, ctx) { success = ctx.data === 1 } + })) + + return success }) // more complex config context - test(function() { + test(function () { var root = mock.document.createElement("div") - var idx = 0; - var success = true; - var statefulConfig = function(elem, isInitialized, ctx) {ctx.data=idx++} - var node = m("div", {config: statefulConfig}); - m.render(root, [node, node]); + var idx = 0 + var success = true + function statefulConfig(elem, isInit, ctx) { ctx.data = idx++ } + var node = m("div", {config: statefulConfig}) + m.render(root, [node, node]) - idx = 0; - var checkConfig = function(elem, isInitialized, ctx) { + idx = 0 + + function checkConfig(elem, isInit, ctx) { success = success && (ctx.data === idx++) } - node = m("div", {config: checkConfig}); - m.render(root, [node, node]); - return success; + + node = m("div", {config: checkConfig}) + m.render(root, [node, node]) + + return success }) - //console.log presence - test(function() { - return m.deps.factory.toString().indexOf("console") < 0 + test.print(function (value) { + console.log(value) // eslint-disable-line no-console }) - test(function() { - return m.deps.factory.toString().indexOf("document.write") < 0 - }) -} - -//mock -testMithril(mock.window); - -test.print(function(value) {console.log(value)}) +})() diff --git a/tests/mock.js b/tests/mock.js index c1a8e88e..ee39d861 100644 --- a/tests/mock.js +++ b/tests/mock.js @@ -1,40 +1,49 @@ -if (!Array.prototype.indexOf) { - Array.prototype.indexOf = function (item) { - for (var i = 0; i < this.length; i++) { - if (this[i] === item) return i - } - return -1 - } -} -if (!Array.prototype.map) { - Array.prototype.map = function (callback) { - var results = [] - for (var i = 0; i < this.length; i++) { - results[i] = callback(this[i], i, this) - } - return results - } -} -if (!Array.prototype.filter) { - Array.prototype.filter = function (callback) { - var results = [] - for (var i = 0; i < this.length; i++) { - if (callback(this[i], i, this)) results.push(this[i]) - } - return results - } -} -if (!Object.keys) { - Object.keys = function () { - var keys = [] - for (var i in this) keys.push(i) - return keys - } -} +(function (global) { // eslint-disable-line max-statements + "use strict" -var mock = {} -mock.window = (function () { - var window = {} + /* eslint-disable no-extend-native */ + if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function (item) { + for (var i = 0; i < this.length; i++) { + if (this[i] === item) return i + } + return -1 + } + } + + if (!Array.prototype.map) { + Array.prototype.map = function (callback) { + var results = [] + for (var i = 0; i < this.length; i++) { + results[i] = callback(this[i], i, this) + } + return results + } + } + + if (!Array.prototype.filter) { + Array.prototype.filter = function (callback) { + var results = [] + for (var i = 0; i < this.length; i++) { + if (callback(this[i], i, this)) results.push(this[i]) + } + return results + } + } + + if (!Object.keys) { + Object.keys = function () { + var keys = [] + for (var i in this) if ({}.hasOwnProperty.call(this, i)) { + keys.push(i) + } + return keys + } + } + /* eslint-enable no-extend-native */ + + var window = global.mock = {window: window} + window.window = window window.document = {} window.document.childNodes = [] window.document.createElement = function (tag) { @@ -46,6 +55,7 @@ mock.window = (function () { appendChild: window.document.appendChild, removeChild: window.document.removeChild, replaceChild: window.document.replaceChild, + insertBefore: function (node, reference) { node.parentNode = this var referenceIndex = this.childNodes.indexOf(reference) @@ -54,15 +64,18 @@ mock.window = (function () { if (referenceIndex < 0) this.childNodes.push(node) else this.childNodes.splice(referenceIndex, 0, node) }, + insertAdjacentHTML: function (position, html) { - //todo: accept markup + // todo: accept markup if (position === "beforebegin") { - this.parentNode.insertBefore(window.document.createTextNode(html), this) - } - else if (position === "beforeend") { + this.parentNode.insertBefore( + window.document.createTextNode(html), + this) + } else if (position === "beforeend") { this.appendChild(window.document.createTextNode(html)) } }, + setAttribute: function (name, value) { this[name] = value.toString() }, @@ -70,7 +83,7 @@ mock.window = (function () { this.namespaceURI = namespace this[name] = value.toString() }, - getAttribute: function (name, value) { + getAttribute: function (name) { return this[name] }, addEventListener: function () {}, @@ -104,16 +117,18 @@ mock.window = (function () { this.childNodes.splice(index, 1) child.parentNode = null } - //getElementsByTagName is only used by JSONP tests, it's not required by Mithril + // getElementsByTagName is only used by JSONP tests, it's not required by + // Mithril window.document.getElementsByTagName = function (name){ name = name.toLowerCase() var out = [] - var traverse = function (node){ + function traverse(node) { if (node.childNodes && node.childNodes.length > 0){ node.childNodes.map(function (curr){ - if (curr.nodeName.toLowerCase() === name) + if (curr.nodeName.toLowerCase() === name) { out.push(curr) + } traverse(curr) }) } @@ -136,8 +151,9 @@ mock.window = (function () { callback() } } + window.XMLHttpRequest = (function () { - var request = function () { + function XMLHttpRequest() { this.$headers = {} this.setRequestHeader = function (key, value) { this.$headers[key] = value @@ -150,21 +166,28 @@ mock.window = (function () { this.responseText = JSON.stringify(this) this.readyState = 4 this.status = 200 - request.$instances.push(this) + XMLHttpRequest.$instances.push(this) } } - request.$instances = [] - return request - }()) - window.location = {search: "", pathname: "", hash: ""}, + XMLHttpRequest.$instances = [] + return XMLHttpRequest + })() + + window.location = {search: "", pathname: "", hash: ""} + window.history = {} window.history.$$length = 0 + window.history.pushState = function (data, title, url) { window.history.$$length++ - window.location.pathname = window.location.search = window.location.hash = url - }, - window.history.replaceState = function (data, title, url) { - window.location.pathname = window.location.search = window.location.hash = url + window.location.pathname = + window.location.search = + window.location.hash = url } - return window -}()) + + window.history.replaceState = function (data, title, url) { + window.location.pathname = + window.location.search = + window.location.hash = url + } +})(this) diff --git a/tests/npm-debug.log b/tests/npm-debug.log deleted file mode 100644 index 2fc27644..00000000 --- a/tests/npm-debug.log +++ /dev/null @@ -1,19 +0,0 @@ -0 info it worked if it ends with ok -1 verbose cli [ 'c:\\Program Files\\nodejs\\node.exe', -1 verbose cli 'c:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js', -1 verbose cli 'test' ] -2 info using npm@1.4.3 -3 info using node@v0.10.26 -4 error Error: ENOENT, open 'C:\Users\Leo\Desktop\shared\work\mithril.js\tests\package.json' -5 error If you need help, you may report this *entire* log, -5 error including the npm and node versions, at: -5 error -6 error System Windows_NT 6.1.7601 -7 error command "c:\\Program Files\\nodejs\\node.exe" "c:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "test" -8 error cwd C:\Users\Leo\Desktop\shared\work\mithril.js\tests -9 error node -v v0.10.26 -10 error npm -v 1.4.3 -11 error path C:\Users\Leo\Desktop\shared\work\mithril.js\tests\package.json -12 error code ENOENT -13 error errno 34 -14 verbose exit [ 34, true ] diff --git a/tests/svg.html b/tests/svg.html deleted file mode 100644 index b57adf93..00000000 --- a/tests/svg.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - SVG test - - - -

Since it's not possible to test SVG functionality from a NodeJS environment, this page can be used to test it in a browser.

-

This page should contain:

- -

The links should open in a new tab. All items should display title tooltips when hovered over.

- -
- - - - diff --git a/tests/test.js b/tests/test.js index 992d6551..4a63552b 100644 --- a/tests/test.js +++ b/tests/test.js @@ -1,28 +1,38 @@ -if (!this.console) { - var log = function (value) { document.write("
" + value + "
") } - this.console = {log: log, error: log} -} +/* eslint-env browser */ -function test(condition) { - test.total++ +(function (global) { + "use strict" - try { - if (!condition()) throw new Error("failed") + function log(value) { + document.write("
" + value + "
") } - catch (e) { - console.error(e) - test.failures.push(condition) - } -} -test.total = 0 -test.failures = [] -test.print = function (print) { - for (var i = 0; i < test.failures.length; i++) { - print(test.failures[i].toString()) - } - print("tests: " + test.total + "\nfailures: " + test.failures.length) - if (test.failures.length > 0) { - throw new Error(test.failures.length + " tests did not pass") + if (!global.console) { + global.console = {log: log, error: log} } -} + + global.test = test + function test(condition) { + test.total++ + + try { + if (!condition()) throw new Error("failed") + } catch (e) { + console.error(e) // eslint-disable-line no-console + test.failures.push(condition) + } + } + test.total = 0 + test.failures = [] + test.print = function (print) { + for (var i = 0; i < test.failures.length; i++) { + print(test.failures[i].toString()) + } + + print("tests: " + test.total + "\nfailures: " + test.failures.length) + + if (test.failures.length > 0) { + throw new Error(test.failures.length + " tests did not pass") + } + } +})(this) diff --git a/tests/trust-test.html b/tests/trust-test.html deleted file mode 100644 index e69de29b..00000000