2427 lines
No EOL
79 KiB
JavaScript
2427 lines
No EOL
79 KiB
JavaScript
Mithril = m = new function app(window) {
|
|
var type = {}.toString
|
|
var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, attrParser = /\[(.+?)(?:=("|'|)(.*?)\2)?\]/
|
|
|
|
function m() {
|
|
var args = arguments
|
|
var hasAttrs = type.call(args[1]) == "[object Object]" && !("tag" in args[1]) && !("subtree" in args[1])
|
|
var attrs = hasAttrs ? args[1] : {}
|
|
var classAttrName = "class" in attrs ? "class" : "className"
|
|
var cell = {tag: "div", attrs: {}}
|
|
var match, classes = []
|
|
while (match = parser.exec(args[0])) {
|
|
if (match[1] == "") 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)
|
|
}
|
|
}
|
|
if (classes.length > 0) cell.attrs[classAttrName] = classes.join(" ")
|
|
|
|
cell.children = hasAttrs ? args[2] : args[1]
|
|
|
|
for (var attrName in attrs) {
|
|
if (attrName == classAttrName) cell.attrs[attrName] = (cell.attrs[attrName] || "") + " " + attrs[attrName]
|
|
else cell.attrs[attrName] = attrs[attrName]
|
|
}
|
|
return cell
|
|
}
|
|
function build(parentElement, parentTag, parentCache, parentIndex, data, cached, shouldReattach, index, editable, namespace, configs) {
|
|
if (data === null || data === undefined) data = ""
|
|
if (data.subtree === "retain") return cached
|
|
|
|
var cachedType = type.call(cached), dataType = type.call(data)
|
|
if (cachedType != dataType) {
|
|
if (cached !== null && cached !== undefined) {
|
|
if (parentCache && parentCache.nodes) {
|
|
var offset = index - parentIndex
|
|
var end = offset + (dataType == "[object Array]" ? data : cached.nodes).length
|
|
clear(parentCache.nodes.slice(offset, end), parentCache.slice(offset, end))
|
|
}
|
|
else clear(cached.nodes, cached)
|
|
}
|
|
cached = new data.constructor
|
|
cached.nodes = []
|
|
}
|
|
|
|
if (dataType == "[object Array]") {
|
|
data = flatten(data)
|
|
var nodes = [], intact = cached.length === data.length, subArrayCount = 0
|
|
|
|
var DELETION = 1, INSERTION = 2 , MOVE = 3
|
|
var existing = {}, unkeyed = [], shouldMaintainIdentities = false
|
|
for (var i = 0; i < cached.length; i++) {
|
|
if (cached[i] && cached[i].attrs && cached[i].attrs.key !== undefined) {
|
|
shouldMaintainIdentities = true
|
|
existing[cached[i].attrs.key] = {action: DELETION, index: i}
|
|
}
|
|
}
|
|
if (shouldMaintainIdentities) {
|
|
for (var i = 0; i < data.length; i++) {
|
|
if (data[i] && data[i].attrs) {
|
|
if (data[i].attrs.key !== undefined) {
|
|
var key = data[i].attrs.key
|
|
if (!existing[key]) existing[key] = {action: INSERTION, index: i}
|
|
else existing[key] = {action: MOVE, index: i, from: existing[key].index, element: parentElement.childNodes[existing[key].index]}
|
|
}
|
|
else unkeyed.push({index: i, element: parentElement.childNodes[i]})
|
|
}
|
|
}
|
|
var actions = Object.keys(existing).map(function(key) {return existing[key]})
|
|
var changes = actions.sort(function(a, b) {return a.action - b.action || a.index - b.index})
|
|
var newCached = cached.slice()
|
|
|
|
for (var i = 0, change; change = changes[i]; i++) {
|
|
if (change.action == DELETION) {
|
|
clear(cached[change.index].nodes, cached[change.index])
|
|
newCached.splice(change.index, 1)
|
|
}
|
|
if (change.action == INSERTION) {
|
|
var dummy = window.document.createElement("div")
|
|
dummy.key = data[change.index].attrs.key
|
|
parentElement.insertBefore(dummy, parentElement.childNodes[change.index])
|
|
newCached.splice(change.index, 0, {attrs: {key: data[change.index].attrs.key}, nodes: [dummy]})
|
|
}
|
|
|
|
if (change.action == MOVE) {
|
|
if (parentElement.childNodes[change.index] !== change.element) {
|
|
parentElement.insertBefore(change.element, parentElement.childNodes[change.index])
|
|
}
|
|
newCached[change.index] = cached[change.from]
|
|
}
|
|
}
|
|
for (var i = 0; i < unkeyed.length; i++) {
|
|
var change = unkeyed[i]
|
|
parentElement.insertBefore(change.element, parentElement.childNodes[change.index])
|
|
newCached[change.index] = cached[change.index]
|
|
}
|
|
cached = newCached
|
|
cached.nodes = []
|
|
for (var i = 0, child; child = parentElement.childNodes[i]; i++) cached.nodes.push(child)
|
|
}
|
|
|
|
for (var i = 0, cacheCount = 0; i < data.length; i++) {
|
|
var item = build(parentElement, parentTag, cached, index, data[i], cached[cacheCount], shouldReattach, index + subArrayCount || subArrayCount, editable, namespace, configs)
|
|
if (item === undefined) continue
|
|
if (!item.nodes.intact) intact = false
|
|
var isArray = item instanceof Array
|
|
subArrayCount += isArray ? item.length : 1
|
|
cached[cacheCount++] = item
|
|
}
|
|
if (!intact) {
|
|
for (var i = 0; i < data.length; i++) {
|
|
if (cached[i] !== undefined) nodes = nodes.concat(cached[i].nodes)
|
|
}
|
|
for (var i = 0, node; node = cached.nodes[i]; i++) {
|
|
if (node.parentNode !== null && nodes.indexOf(node) < 0) node.parentNode.removeChild(node)
|
|
}
|
|
for (var i = cached.nodes.length, node; node = nodes[i]; i++) {
|
|
if (node.parentNode === null) parentElement.appendChild(node)
|
|
}
|
|
if (data.length < cached.length) cached.length = data.length
|
|
cached.nodes = nodes
|
|
}
|
|
|
|
}
|
|
else if (dataType == "[object Object]") {
|
|
if (data.tag != cached.tag || Object.keys(data.attrs).join() != Object.keys(cached.attrs).join() || data.attrs.id != cached.attrs.id) {
|
|
clear(cached.nodes)
|
|
if (cached.configContext && typeof cached.configContext.onunload == "function") cached.configContext.onunload()
|
|
}
|
|
if (typeof data.tag != "string") return
|
|
|
|
var node, isNew = cached.nodes.length === 0
|
|
if (data.attrs.xmlns) namespace = data.attrs.xmlns
|
|
else if (data.tag === "svg") namespace = "http://www.w3.org/2000/svg"
|
|
if (isNew) {
|
|
node = namespace === undefined ? window.document.createElement(data.tag) : window.document.createElementNS(namespace, data.tag)
|
|
cached = {
|
|
tag: data.tag,
|
|
//process children before attrs so that select.value works correctly
|
|
children: data.children !== undefined ? build(node, data.tag, undefined, undefined, data.children, cached.children, true, 0, data.attrs.contenteditable ? node : editable, namespace, configs) : undefined,
|
|
attrs: setAttributes(node, data.tag, data.attrs, {}, namespace),
|
|
nodes: [node]
|
|
}
|
|
parentElement.insertBefore(node, parentElement.childNodes[index] || null)
|
|
}
|
|
else {
|
|
node = cached.nodes[0]
|
|
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
|
|
if (shouldReattach === true) parentElement.insertBefore(node, parentElement.childNodes[index] || null)
|
|
}
|
|
if (type.call(data.attrs["config"]) == "[object Function]") {
|
|
configs.push(data.attrs["config"].bind(window, node, !isNew, cached.configContext = cached.configContext || {}, cached))
|
|
}
|
|
}
|
|
else {
|
|
var nodes
|
|
if (cached.nodes.length === 0) {
|
|
if (data.$trusted) {
|
|
nodes = injectHTML(parentElement, index, data)
|
|
}
|
|
else {
|
|
nodes = [window.document.createTextNode(data)]
|
|
parentElement.insertBefore(nodes[0], parentElement.childNodes[index] || null)
|
|
}
|
|
cached = "string number boolean".indexOf(typeof data) > -1 ? new data.constructor(data) : data
|
|
cached.nodes = nodes
|
|
}
|
|
else if (cached.valueOf() !== data.valueOf() || shouldReattach === true) {
|
|
nodes = cached.nodes
|
|
if (!editable || editable !== window.document.activeElement) {
|
|
if (data.$trusted) {
|
|
clear(nodes, cached)
|
|
nodes = injectHTML(parentElement, index, data)
|
|
}
|
|
else {
|
|
if (parentTag === "textarea") parentElement.value = data
|
|
else if (editable) editable.innerHTML = data
|
|
else {
|
|
if (nodes[0].nodeType == 1 || nodes.length > 1) { //was a trusted string
|
|
clear(cached.nodes, cached)
|
|
nodes = [window.document.createTextNode(data)]
|
|
}
|
|
parentElement.insertBefore(nodes[0], parentElement.childNodes[index] || null)
|
|
nodes[0].nodeValue = data
|
|
}
|
|
}
|
|
}
|
|
cached = new data.constructor(data)
|
|
cached.nodes = nodes
|
|
}
|
|
else cached.nodes.intact = true
|
|
}
|
|
|
|
return cached
|
|
}
|
|
function setAttributes(node, tag, dataAttrs, cachedAttrs, namespace) {
|
|
var groups = {}
|
|
for (var attrName in dataAttrs) {
|
|
var dataAttr = dataAttrs[attrName]
|
|
var cachedAttr = cachedAttrs[attrName]
|
|
if (!(attrName in cachedAttrs) || (cachedAttr !== dataAttr) || node === window.document.activeElement) {
|
|
cachedAttrs[attrName] = dataAttr
|
|
if (attrName === "config") continue
|
|
else if (typeof dataAttr == "function" && attrName.indexOf("on") == 0) {
|
|
node[attrName] = autoredraw(dataAttr, node)
|
|
}
|
|
else if (attrName === "style" && typeof dataAttr == "object") {
|
|
for (var rule in dataAttr) {
|
|
if (cachedAttr === undefined || cachedAttr[rule] !== dataAttr[rule]) node.style[rule] = dataAttr[rule]
|
|
}
|
|
for (var rule in cachedAttr) {
|
|
if (!(rule in dataAttr)) node.style[rule] = ""
|
|
}
|
|
}
|
|
else if (namespace !== undefined) {
|
|
if (attrName === "href") node.setAttributeNS("http://www.w3.org/1999/xlink", "href", dataAttr)
|
|
else if (attrName === "className") node.setAttribute("class", dataAttr)
|
|
else node.setAttribute(attrName, dataAttr)
|
|
}
|
|
else if (attrName === "value" && tag === "input") {
|
|
if (node.value !== dataAttr) node.value = dataAttr
|
|
}
|
|
else if (attrName in node && !(attrName == "list" || attrName == "style")) {
|
|
node[attrName] = dataAttr
|
|
}
|
|
else node.setAttribute(attrName, dataAttr)
|
|
}
|
|
}
|
|
return cachedAttrs
|
|
}
|
|
function clear(nodes, cached) {
|
|
for (var i = nodes.length - 1; i > -1; i--) {
|
|
if (nodes[i] && nodes[i].parentNode) {
|
|
nodes[i].parentNode.removeChild(nodes[i])
|
|
cached = [].concat(cached)
|
|
if (cached[i]) unload(cached[i])
|
|
}
|
|
}
|
|
if (nodes.length != 0) nodes.length = 0
|
|
}
|
|
function unload(cached) {
|
|
if (cached.configContext && typeof cached.configContext.onunload == "function") cached.configContext.onunload()
|
|
if (cached.children) {
|
|
if (cached.children instanceof Array) for (var i = 0; i < cached.children.length; i++) unload(cached.children[i])
|
|
else if (cached.children.tag) unload(cached.children)
|
|
}
|
|
}
|
|
function injectHTML(parentElement, index, data) {
|
|
var nextSibling = parentElement.childNodes[index]
|
|
if (nextSibling) {
|
|
var isElement = nextSibling.nodeType != 1
|
|
var placeholder = window.document.createElement("span")
|
|
if (isElement) {
|
|
parentElement.insertBefore(placeholder, nextSibling)
|
|
placeholder.insertAdjacentHTML("beforebegin", data)
|
|
parentElement.removeChild(placeholder)
|
|
}
|
|
else nextSibling.insertAdjacentHTML("beforebegin", data)
|
|
}
|
|
else parentElement.insertAdjacentHTML("beforeend", data)
|
|
var nodes = []
|
|
while (parentElement.childNodes[index] !== nextSibling) {
|
|
nodes.push(parentElement.childNodes[index])
|
|
index++
|
|
}
|
|
return nodes
|
|
}
|
|
function flatten(data) {
|
|
var flattened = []
|
|
for (var i = 0; i < data.length; i++) {
|
|
var item = data[i]
|
|
if (item instanceof Array) flattened.push.apply(flattened, flatten(item))
|
|
else flattened.push(item)
|
|
}
|
|
return flattened
|
|
}
|
|
function autoredraw(callback, object, group) {
|
|
return function(e) {
|
|
e = e || event
|
|
m.startComputation()
|
|
try {return callback.call(object, e)}
|
|
finally {
|
|
if (!lastRedrawId) lastRedrawId = -1;
|
|
m.endComputation()
|
|
}
|
|
}
|
|
}
|
|
|
|
var html
|
|
var documentNode = {
|
|
insertAdjacentHTML: function(_, data) {
|
|
window.document.write(data)
|
|
window.document.close()
|
|
},
|
|
appendChild: function(node) {
|
|
if (html === undefined) html = window.document.createElement("html")
|
|
if (node.nodeName == "HTML") html = node
|
|
else html.appendChild(node)
|
|
if (window.document.documentElement && window.document.documentElement !== html) {
|
|
window.document.replaceChild(html, window.document.documentElement)
|
|
}
|
|
else window.document.appendChild(html)
|
|
},
|
|
insertBefore: function(node) {
|
|
this.appendChild(node)
|
|
},
|
|
childNodes: []
|
|
}
|
|
var nodeCache = [], cellCache = {}
|
|
m.render = function(root, cell) {
|
|
var configs = []
|
|
if (!root) throw new Error("Please ensure the DOM element exists before rendering a template into it.")
|
|
var id = getCellCacheKey(root)
|
|
var node = root == window.document || root == window.document.documentElement ? documentNode : root
|
|
if (cellCache[id] === undefined) clear(node.childNodes)
|
|
cellCache[id] = build(node, null, undefined, undefined, cell, cellCache[id], false, 0, null, undefined, configs)
|
|
for (var i = 0; i < configs.length; i++) configs[i]()
|
|
}
|
|
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 roots = [], modules = [], controllers = [], lastRedrawId = 0, computePostRedrawHook = null
|
|
m.module = function(root, module) {
|
|
var index = roots.indexOf(root)
|
|
if (index < 0) index = roots.length
|
|
var isPrevented = false
|
|
if (controllers[index] && typeof controllers[index].onunload == "function") {
|
|
var event = {
|
|
preventDefault: function() {isPrevented = true}
|
|
}
|
|
controllers[index].onunload(event)
|
|
}
|
|
if (!isPrevented) {
|
|
m.startComputation()
|
|
roots[index] = root
|
|
modules[index] = module
|
|
controllers[index] = new module.controller
|
|
m.endComputation()
|
|
}
|
|
}
|
|
m.redraw = function() {
|
|
var cancel = window.cancelAnimationFrame || window.clearTimeout
|
|
var defer = window.requestAnimationFrame || window.setTimeout
|
|
if (lastRedrawId) {
|
|
cancel(lastRedrawId)
|
|
lastRedrawId = defer(redraw, 0)
|
|
}
|
|
else {
|
|
redraw()
|
|
lastRedrawId = defer(function() {lastRedrawId = null}, 0)
|
|
}
|
|
}
|
|
function redraw() {
|
|
for (var i = 0; i < roots.length; i++) {
|
|
if (controllers[i]) m.render(roots[i], modules[i].view(controllers[i]))
|
|
}
|
|
if (computePostRedrawHook) {
|
|
computePostRedrawHook()
|
|
computePostRedrawHook = null
|
|
}
|
|
lastRedrawId = null
|
|
}
|
|
|
|
var pendingRequests = 0
|
|
m.startComputation = function() {pendingRequests++}
|
|
m.endComputation = function() {
|
|
pendingRequests = Math.max(pendingRequests - 1, 0)
|
|
if (pendingRequests == 0) m.redraw()
|
|
}
|
|
|
|
m.withAttr = function(prop, withAttrCallback) {
|
|
return function(e) {
|
|
e = e || event
|
|
withAttrCallback(prop in e.currentTarget ? e.currentTarget[prop] : e.currentTarget.getAttribute(prop))
|
|
}
|
|
}
|
|
|
|
//routing
|
|
var modes = {pathname: "", hash: "#", search: "?"}
|
|
var redirect = function() {}, routeParams = {}, currentRoute
|
|
m.route = function() {
|
|
if (arguments.length === 0) return currentRoute
|
|
else if (arguments.length === 3 && typeof arguments[1] == "string") {
|
|
var root = arguments[0], defaultRoute = arguments[1], router = arguments[2]
|
|
redirect = function(source) {
|
|
var path = currentRoute = normalizeRoute(source)
|
|
if (!routeByValue(root, router, path)) {
|
|
m.route(defaultRoute, true)
|
|
}
|
|
}
|
|
var listener = m.route.mode == "hash" ? "onhashchange" : "onpopstate"
|
|
window[listener] = function() {
|
|
if (currentRoute != normalizeRoute(window.location[m.route.mode])) {
|
|
redirect(window.location[m.route.mode])
|
|
}
|
|
}
|
|
computePostRedrawHook = setScroll
|
|
window[listener]()
|
|
}
|
|
else if (arguments[0].addEventListener) {
|
|
var element = arguments[0]
|
|
var isInitialized = arguments[1]
|
|
if (element.href.indexOf(modes[m.route.mode]) < 0) {
|
|
element.href = window.location.pathname + modes[m.route.mode] + element.pathname
|
|
}
|
|
if (!isInitialized) {
|
|
element.removeEventListener("click", routeUnobtrusive)
|
|
element.addEventListener("click", routeUnobtrusive)
|
|
}
|
|
}
|
|
else if (typeof arguments[0] == "string") {
|
|
currentRoute = arguments[0]
|
|
var querystring = typeof arguments[1] == "object" ? buildQueryString(arguments[1]) : null
|
|
if (querystring) currentRoute += (currentRoute.indexOf("?") === -1 ? "?" : "&") + querystring
|
|
|
|
var shouldReplaceHistoryEntry = (arguments.length == 3 ? arguments[2] : arguments[1]) === true
|
|
|
|
if (window.history.pushState) {
|
|
computePostRedrawHook = function() {
|
|
window.history[shouldReplaceHistoryEntry ? "replaceState" : "pushState"](null, window.document.title, modes[m.route.mode] + currentRoute)
|
|
setScroll()
|
|
}
|
|
redirect(modes[m.route.mode] + currentRoute)
|
|
}
|
|
else window.location[m.route.mode] = currentRoute
|
|
}
|
|
}
|
|
m.route.param = function(key) {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)
|
|
}
|
|
|
|
for (var route in router) {
|
|
if (route == path) {
|
|
reset(root)
|
|
m.module(root, router[route])
|
|
return true
|
|
}
|
|
|
|
var matcher = new RegExp("^" + route.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$")
|
|
|
|
if (matcher.test(path)) {
|
|
reset(root)
|
|
path.replace(matcher, function() {
|
|
var keys = route.match(/:[^\/]+/g) || []
|
|
var values = [].slice.call(arguments, 1, -2)
|
|
for (var i = 0; i < keys.length; i++) routeParams[keys[i].replace(/:|\./g, "")] = decodeSpace(values[i])
|
|
m.module(root, router[route])
|
|
})
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
function reset(root) {
|
|
var cacheKey = getCellCacheKey(root)
|
|
clear(root.childNodes, cellCache[cacheKey])
|
|
cellCache[cacheKey] = undefined
|
|
}
|
|
function routeUnobtrusive(e) {
|
|
e = e || event
|
|
if (e.ctrlKey || e.metaKey || e.which == 2) return
|
|
e.preventDefault()
|
|
m.route(e.currentTarget[m.route.mode].slice(modes[m.route.mode].length))
|
|
}
|
|
function setScroll() {
|
|
if (m.route.mode != "hash" && window.location.hash) window.location.hash = window.location.hash
|
|
else window.scrollTo(0, 0)
|
|
}
|
|
function buildQueryString(object, prefix) {
|
|
var str = []
|
|
for(var prop in object) {
|
|
var key = prefix ? prefix + "[" + prop + "]" : prop, value = object[prop]
|
|
str.push(typeof value == "object" ? buildQueryString(value, key) : encodeURIComponent(key) + "=" + encodeURIComponent(value))
|
|
}
|
|
return str.join("&")
|
|
}
|
|
function parseQueryString(str) {
|
|
var pairs = str.split("&"), params = {}
|
|
for (var i = 0; i < pairs.length; i++) {
|
|
var pair = pairs[i].split("=")
|
|
params[decodeSpace(pair[0])] = pair[1] ? decodeSpace(pair[1]) : (pair.length === 1 ? true : "")
|
|
}
|
|
return params
|
|
}
|
|
function decodeSpace(string) {
|
|
return decodeURIComponent(string.replace(/\+/g, " "))
|
|
}
|
|
|
|
//model
|
|
m.prop = function(store) {
|
|
var prop = function() {
|
|
if (arguments.length) store = arguments[0]
|
|
return store
|
|
}
|
|
prop.toJSON = function() {
|
|
return store
|
|
}
|
|
return prop
|
|
}
|
|
|
|
var none = {}
|
|
m.deferred = function() {
|
|
var resolvers = [], rejecters = [], resolved = none, rejected = none, promise = m.prop()
|
|
var object = {
|
|
resolve: function(value) {
|
|
if (resolved === none) promise(resolved = value)
|
|
for (var i = 0; i < resolvers.length; i++) resolvers[i](value)
|
|
resolvers.length = rejecters.length = 0
|
|
},
|
|
reject: function(value) {
|
|
if (rejected === none) rejected = value
|
|
for (var i = 0; i < rejecters.length; i++) rejecters[i](value)
|
|
resolvers.length = rejecters.length = 0
|
|
},
|
|
promise: promise
|
|
}
|
|
object.promise.resolvers = resolvers
|
|
object.promise.then = function(success, error) {
|
|
var next = m.deferred()
|
|
if (!success) success = identity
|
|
if (!error) error = identity
|
|
function callback(method, callback) {
|
|
return function(value) {
|
|
try {
|
|
var result = callback(value)
|
|
if (result && typeof result.then == "function") result.then(next[method], error)
|
|
else next[method](result !== undefined ? result : value)
|
|
}
|
|
catch (e) {
|
|
if (e instanceof Error && e.constructor !== Error) throw e
|
|
else next.reject(e)
|
|
}
|
|
}
|
|
}
|
|
if (resolved !== none) callback("resolve", success)(resolved)
|
|
else if (rejected !== none) callback("reject", error)(rejected)
|
|
else {
|
|
resolvers.push(callback("resolve", success))
|
|
rejecters.push(callback("reject", error))
|
|
}
|
|
return next.promise
|
|
}
|
|
return object
|
|
}
|
|
m.sync = function(args) {
|
|
var method = "resolve"
|
|
function synchronizer(pos, resolved) {
|
|
return function(value) {
|
|
results[pos] = value
|
|
if (!resolved) method = "reject"
|
|
if (--outstanding == 0) {
|
|
deferred.promise(results)
|
|
deferred[method](results)
|
|
}
|
|
return value
|
|
}
|
|
}
|
|
|
|
var deferred = m.deferred()
|
|
var outstanding = args.length
|
|
var results = new Array(outstanding)
|
|
for (var i = 0; i < args.length; i++) {
|
|
args[i].then(synchronizer(i, true), synchronizer(i, false))
|
|
}
|
|
return deferred.promise
|
|
}
|
|
function identity(value) {return value}
|
|
|
|
function ajax(options) {
|
|
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.method != "GET") {
|
|
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
|
|
}
|
|
if (typeof options.config == "function") {
|
|
var maybeXhr = options.config(xhr, options)
|
|
if (maybeXhr !== undefined) xhr = maybeXhr
|
|
}
|
|
xhr.send(options.method == "GET" ? "" : options.data)
|
|
return xhr
|
|
}
|
|
function bindData(xhrOptions, data, serialize) {
|
|
if (data && Object.keys(data).length > 0) {
|
|
if (xhrOptions.method == "GET") {
|
|
xhrOptions.url = xhrOptions.url + (xhrOptions.url.indexOf("?") < 0 ? "?" : "&") + buildQueryString(data)
|
|
}
|
|
else xhrOptions.data = serialize(data)
|
|
}
|
|
return xhrOptions
|
|
}
|
|
function parameterizeUrl(url, data) {
|
|
var tokens = url.match(/:[a-z]\w+/gi)
|
|
if (tokens && data) {
|
|
for (var i = 0; i < tokens.length; i++) {
|
|
var key = tokens[i].slice(1)
|
|
url = url.replace(tokens[i], data[key])
|
|
delete data[key]
|
|
}
|
|
}
|
|
return url
|
|
}
|
|
|
|
m.request = function(xhrOptions) {
|
|
if (xhrOptions.background !== true) m.startComputation()
|
|
var deferred = m.deferred()
|
|
var serialize = xhrOptions.serialize = xhrOptions.serialize || JSON.stringify
|
|
var deserialize = xhrOptions.deserialize = xhrOptions.deserialize || JSON.parse
|
|
var extract = xhrOptions.extract || function(xhr) {
|
|
return xhr.responseText.length === 0 && deserialize === JSON.parse ? null : xhr.responseText
|
|
}
|
|
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)))
|
|
if (e.type == "load") {
|
|
if (response instanceof Array && xhrOptions.type) {
|
|
for (var i = 0; i < response.length; i++) response[i] = new xhrOptions.type(response[i])
|
|
}
|
|
else if (xhrOptions.type) response = new xhrOptions.type(response)
|
|
}
|
|
deferred[e.type == "load" ? "resolve" : "reject"](response)
|
|
}
|
|
catch (e) {
|
|
if (e instanceof SyntaxError) throw new SyntaxError("Could not parse HTTP response. See http://lhorie.github.io/mithril/mithril.request.html#using-variable-data-formats")
|
|
else if (e instanceof Error && e.constructor !== Error) throw e
|
|
else deferred.reject(e)
|
|
}
|
|
if (xhrOptions.background !== true) m.endComputation()
|
|
}
|
|
ajax(xhrOptions)
|
|
return deferred.promise
|
|
}
|
|
|
|
//testing API
|
|
m.deps = function(mock) {return window = mock}
|
|
//for internal testing only, do not use `m.deps.factory`
|
|
m.deps.factory = app
|
|
|
|
return m
|
|
}(typeof window != "undefined" ? window : {})
|
|
|
|
if (typeof module != "undefined" && module !== null) module.exports = m
|
|
if (typeof define == "function" && define.amd) define(function() {return m})
|
|
|
|
;;;
|
|
|
|
function test(condition) {
|
|
var duration = 0;
|
|
var start = 0;
|
|
var result = true;
|
|
test.total++
|
|
|
|
if (typeof window != "undefined") {
|
|
if (typeof performance != "undefined") {
|
|
start = performance.now();
|
|
}
|
|
try {if (!condition()) throw new Error}
|
|
catch (e) {result = false;console.error(e);test.failures.push(condition)}
|
|
if (typeof performance != "undefined") {
|
|
duration = performance.now() - start;
|
|
}
|
|
|
|
|
|
test_obj = {
|
|
name: "" + test.total,
|
|
result: result,
|
|
duration: duration
|
|
}
|
|
if (!result) {
|
|
message: "failed: " + condition,
|
|
window.global_test_results.tests.push(test_obj)
|
|
}
|
|
|
|
window.global_test_results.duration += duration;
|
|
if (result) {
|
|
window.global_test_results.passed++;
|
|
} else {
|
|
window.global_test_results.failed++;
|
|
}
|
|
}
|
|
}
|
|
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")
|
|
}
|
|
}
|
|
|
|
var mock = {}
|
|
mock.window = new function() {
|
|
var window = {}
|
|
window.document = {}
|
|
window.document.childNodes = []
|
|
window.document.createElement = function(tag) {
|
|
return {
|
|
style: {},
|
|
childNodes: [],
|
|
nodeType: 1,
|
|
nodeName: tag.toUpperCase(),
|
|
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)
|
|
if (referenceIndex < 0) this.childNodes.push(node)
|
|
else {
|
|
var index = this.childNodes.indexOf(node)
|
|
if (index > -1) this.childNodes.splice(index, 1)
|
|
this.childNodes.splice(referenceIndex, 0, node)
|
|
}
|
|
},
|
|
insertAdjacentHTML: function(position, html) {
|
|
//todo: accept markup
|
|
if (position == "beforebegin") {
|
|
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()
|
|
},
|
|
setAttributeNS: function(namespace, name, value) {
|
|
this.namespaceURI = namespace
|
|
this[name] = value.toString()
|
|
},
|
|
getAttribute: function(name, value) {
|
|
return this[name]
|
|
}
|
|
}
|
|
}
|
|
window.document.createElementNS = function(namespace, tag) {
|
|
var element = window.document.createElement(tag)
|
|
element.namespaceURI = namespace
|
|
return element
|
|
}
|
|
window.document.createTextNode = function(text) {
|
|
return {nodeValue: text.toString()}
|
|
}
|
|
window.document.documentElement = window.document.createElement("html")
|
|
window.document.replaceChild = function(newChild, oldChild) {
|
|
var index = this.childNodes.indexOf(oldChild)
|
|
if (index > -1) this.childNodes.splice(index, 1, newChild)
|
|
else this.childNodes.push(newChild)
|
|
newChild.parentNode = this
|
|
oldChild.parentNode = null
|
|
}
|
|
window.document.appendChild = function(child) {
|
|
var index = this.childNodes.indexOf(child)
|
|
if (index > -1) this.childNodes.splice(index, 1)
|
|
this.childNodes.push(child)
|
|
child.parentNode = this
|
|
}
|
|
window.document.removeChild = function(child) {
|
|
var index = this.childNodes.indexOf(child)
|
|
this.childNodes.splice(index, 1)
|
|
child.parentNode = null
|
|
}
|
|
window.scrollTo = function() {}
|
|
window.cancelAnimationFrame = function() {}
|
|
window.requestAnimationFrame = function(callback) {
|
|
window.requestAnimationFrame.$callback = callback
|
|
return window.requestAnimationFrame.$id++
|
|
}
|
|
window.requestAnimationFrame.$id = 1
|
|
window.requestAnimationFrame.$resolve = function() {
|
|
if (window.requestAnimationFrame.$callback) window.requestAnimationFrame.$callback()
|
|
window.requestAnimationFrame.$callback = null
|
|
}
|
|
window.XMLHttpRequest = new function() {
|
|
var request = function() {
|
|
this.$headers = {}
|
|
this.setRequestHeader = function(key, value) {
|
|
this.$headers[key] = value
|
|
}
|
|
this.open = function(method, url) {
|
|
this.method = method
|
|
this.url = url
|
|
}
|
|
this.send = function() {
|
|
this.responseText = JSON.stringify(this)
|
|
this.readyState = 4
|
|
this.status = 200
|
|
request.$instances.push(this)
|
|
}
|
|
}
|
|
request.$instances = []
|
|
return request
|
|
}
|
|
window.location = {search: "", pathname: "", hash: ""},
|
|
window.history = {}
|
|
window.history.pushState = function(data, title, url) {
|
|
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
|
|
}
|
|
return window
|
|
}
|
|
function testMithril(mock) {
|
|
m.deps(mock)
|
|
|
|
//m
|
|
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 === "test"})
|
|
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 === "test"})
|
|
test(function() {return m("div", {title: "bar"}, ["test"]).children[0] === "test"})
|
|
test(function() {return m("div", {title: "bar"}, m("div")).children.tag === "div"})
|
|
test(function() {return m("div", {title: "bar"}, [m("div")]).children[0].tag === "div"})
|
|
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.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"})
|
|
|
|
//m.module
|
|
test(function() {
|
|
mock.requestAnimationFrame.$resolve()
|
|
|
|
var root1 = mock.document.createElement("div")
|
|
m.module(root1, {
|
|
controller: function() {this.value = "test1"},
|
|
view: function(ctrl) {return ctrl.value}
|
|
})
|
|
|
|
var root2 = mock.document.createElement("div")
|
|
m.module(root2, {
|
|
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"
|
|
})
|
|
|
|
//m.withAttr
|
|
test(function() {
|
|
var value
|
|
var handler = m.withAttr("test", function(data) {value = data})
|
|
handler({currentTarget: {test: "foo"}})
|
|
return value === "foo"
|
|
})
|
|
|
|
//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() {
|
|
var root = mock.document.createElement("div")
|
|
m.render(root, m("div", {class: "a"}))
|
|
var elementBefore = root.childNodes[0]
|
|
m.render(root, m("div", {class: "b"}))
|
|
var elementAfter = root.childNodes[0]
|
|
return elementBefore === elementAfter
|
|
})
|
|
test(function() {
|
|
var root = mock.document.createElement("div")
|
|
m.render(root, m(".a"))
|
|
var elementBefore = root.childNodes[0]
|
|
m.render(root, m(".b"))
|
|
var elementAfter = root.childNodes[0]
|
|
return elementBefore === elementAfter
|
|
})
|
|
test(function() {
|
|
var root = mock.document.createElement("div")
|
|
m.render(root, m("div", {id: "a"}))
|
|
var elementBefore = root.childNodes[0]
|
|
m.render(root, m("div", {title: "b"}))
|
|
var elementAfter = root.childNodes[0]
|
|
return elementBefore !== elementAfter
|
|
})
|
|
test(function() {
|
|
var root = mock.document.createElement("div")
|
|
m.render(root, m("#a"))
|
|
var elementBefore = root.childNodes[0]
|
|
m.render(root, m("[title=b]"))
|
|
var elementAfter = root.childNodes[0]
|
|
return elementBefore !== elementAfter
|
|
})
|
|
test(function() {
|
|
var root = mock.document.createElement("div")
|
|
m.render(root, m("#a"))
|
|
var elementBefore = root.childNodes[0]
|
|
m.render(root, "test")
|
|
var elementAfter = root.childNodes[0]
|
|
return elementBefore !== elementAfter
|
|
})
|
|
test(function() {
|
|
var root = mock.document.createElement("div")
|
|
m.render(root, m("div", [undefined]))
|
|
return root.childNodes[0].childNodes[0].nodeValue === ""
|
|
})
|
|
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"
|
|
})
|
|
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() {
|
|
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() {
|
|
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() {
|
|
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.length == 2 && root.childNodes[0].childNodes[1].nodeValue === ""
|
|
})
|
|
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() {
|
|
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() {
|
|
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
|
|
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/29
|
|
var root = mock.document.createElement("div")
|
|
var list = [false, false]
|
|
m.render(root, list.reverse().map(function(flag, index) {
|
|
return m("input[type=checkbox]", {onclick: m.withAttr("checked", function(value) {list[index] = value}), checked: flag})
|
|
}))
|
|
|
|
mock.document.activeElement = root.childNodes[0]
|
|
root.childNodes[0].checked = true
|
|
root.childNodes[0].onclick({currentTarget: {checked: true}})
|
|
|
|
m.render(root, list.reverse().map(function(flag, index) {
|
|
return m("input[type=checkbox]", {onclick: m.withAttr("checked", function(value) {list[index] = value}), checked: flag})
|
|
}))
|
|
|
|
mock.document.activeElement = null
|
|
|
|
return root.childNodes[0].checked === false && root.childNodes[1].checked === true
|
|
})
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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")]))
|
|
return root.childNodes[0].childNodes[2].childNodes[0].nodeValue === "c"
|
|
})
|
|
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"
|
|
})
|
|
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"
|
|
})
|
|
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"
|
|
})
|
|
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"
|
|
})
|
|
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"
|
|
})
|
|
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"
|
|
})
|
|
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]
|
|
m.render(root, m("#b"))
|
|
var elementAfter = root.childNodes[0]
|
|
return elementBefore !== elementAfter
|
|
})
|
|
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
|
|
var root = mock.document.createElement("div")
|
|
m.render(root, m("div", "foo"))
|
|
return root.childNodes.length == 1
|
|
})
|
|
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
|
|
m.render(root, m("div", [undefined, m("ul")]))
|
|
var valueAfter = root.childNodes[0].childNodes[0].nodeValue
|
|
return valueBefore === "BUTTON" && valueAfter === ""
|
|
})
|
|
test(function() {
|
|
var root = mock.document.createElement("div")
|
|
m.render(root, m("div", [m("ul"), undefined]))
|
|
var valueBefore1 = root.childNodes[0].childNodes[0].nodeName
|
|
var valueBefore2 = root.childNodes[0].childNodes[1].nodeValue
|
|
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"
|
|
})
|
|
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
|
|
m.render(root, m("div", {style: {}}))
|
|
var valueAfter = root.childNodes[0].style.background
|
|
return valueBefore === "red" && valueAfter === ""
|
|
})
|
|
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() {
|
|
var root = mock.document.createElement("div")
|
|
m.render(root, m("div", {style: {background: "red"}}))
|
|
var valueBefore = root.childNodes[0].style.background
|
|
m.render(root, m("div", {}))
|
|
var valueAfter = root.childNodes[0].style.background
|
|
return valueBefore === "red" && valueAfter === undefined
|
|
})
|
|
test(function() {
|
|
var root = mock.document.createElement("div")
|
|
var module = {}, unloaded = false
|
|
module.controller = function() {
|
|
this.onunload = function() {unloaded = true}
|
|
}
|
|
module.view = function() {}
|
|
m.module(root, module)
|
|
m.module(root, {controller: function() {}, view: function() {}})
|
|
return unloaded === true
|
|
})
|
|
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"
|
|
})
|
|
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"
|
|
})
|
|
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"
|
|
})
|
|
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"
|
|
})
|
|
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"
|
|
})
|
|
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"
|
|
})
|
|
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
|
|
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"
|
|
})
|
|
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"
|
|
})
|
|
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"
|
|
})
|
|
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
|
|
})
|
|
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]);
|
|
|
|
index = 0;
|
|
var checkConfig = function(elem, isInitialized, ctx) {
|
|
success = success && (ctx.data === index++)
|
|
}
|
|
node = m("div", {config: checkConfig});
|
|
m.render(root, [node, node]);
|
|
return success;
|
|
})
|
|
test(function() {
|
|
var root = mock.document.createElement("div")
|
|
var parent
|
|
m.render(root, m("div", m("a", {
|
|
config: function(el) {parent = el.parentNode.parentNode}
|
|
})));
|
|
return parent === root
|
|
})
|
|
test(function() {
|
|
var root = mock.document.createElement("div")
|
|
var count = 0
|
|
m.render(root, m("div", m("a", {
|
|
config: function(el) {
|
|
var island = mock.document.createElement("div")
|
|
count++
|
|
if (count > 2) throw "too much recursion..."
|
|
m.render(island, m("div"))
|
|
}
|
|
})));
|
|
return count == 1
|
|
})
|
|
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"]));
|
|
return true
|
|
})
|
|
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}), m("a", {key: 2}), m("a", {key: 3})])
|
|
var firstBefore = root.childNodes[0]
|
|
m.render(root, [m("a", {key: 4}), m("a", {key: 1}), m("a", {key: 2}), m("a", {key: 3})])
|
|
var firstAfter = root.childNodes[1]
|
|
return firstBefore == firstAfter && root.childNodes[0].key == 4 && root.childNodes.length == 4
|
|
})
|
|
test(function() {
|
|
//https://github.com/lhorie/mithril.js/issues/98
|
|
var root = mock.document.createElement("div")
|
|
m.render(root, [m("a", {key: 1}), m("a", {key: 2}), m("a", {key: 3})])
|
|
var firstBefore = root.childNodes[0]
|
|
m.render(root, [m("a", {key: 4}), m("a", {key: 1}), m("a", {key: 2})])
|
|
var firstAfter = root.childNodes[1]
|
|
return firstBefore == firstAfter && root.childNodes[0].key == 4 && root.childNodes.length == 3
|
|
})
|
|
test(function() {
|
|
//https://github.com/lhorie/mithril.js/issues/98
|
|
var root = mock.document.createElement("div")
|
|
m.render(root, [m("a", {key: 1}), m("a", {key: 2}), m("a", {key: 3})])
|
|
var firstBefore = root.childNodes[1]
|
|
m.render(root, [m("a", {key: 2}), m("a", {key: 3}), m("a", {key: 4})])
|
|
var firstAfter = root.childNodes[0]
|
|
return firstBefore == firstAfter && root.childNodes[0].key === "2" && root.childNodes.length === 3
|
|
})
|
|
test(function() {
|
|
//https://github.com/lhorie/mithril.js/issues/98
|
|
var root = mock.document.createElement("div")
|
|
m.render(root, [m("a", {key: 1}), m("a", {key: 2}), m("a", {key: 3}), m("a", {key: 4}), m("a", {key: 5})])
|
|
var firstBefore = root.childNodes[0]
|
|
var secondBefore = root.childNodes[1]
|
|
var fourthBefore = root.childNodes[3]
|
|
m.render(root, [m("a", {key: 4}), m("a", {key: 10}), m("a", {key: 1}), m("a", {key: 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].key == "10" && root.childNodes.length === 4
|
|
})
|
|
test(function() {
|
|
//https://github.com/lhorie/mithril.js/issues/98
|
|
var root = mock.document.createElement("div")
|
|
m.render(root, [m("a", {key: 1}), m("a", {key: 2}), m("a", {key: 3}), m("a", {key: 4}), m("a", {key: 5})])
|
|
var firstBefore = root.childNodes[0]
|
|
var secondBefore = root.childNodes[1]
|
|
var fourthBefore = root.childNodes[3]
|
|
m.render(root, [m("a", {key: 4}), m("a", {key: 10}), m("a", {key: 2}), m("a", {key: 1}), m("a", {key: 6}), m("a", {key: 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].key == "10" && root.childNodes[4].key == "6" && root.childNodes[5].key == "7" && root.childNodes.length === 6
|
|
})
|
|
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})])
|
|
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})])
|
|
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
|
|
})
|
|
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]
|
|
m.render(root, m("div", {contenteditable: true}, "test1"))
|
|
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
|
|
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() {
|
|
var root = mock.document.createElement("div")
|
|
var unloaded = 0
|
|
m.render(root, [
|
|
m("div", {
|
|
key: 1,
|
|
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() {
|
|
unloaded++
|
|
}
|
|
}
|
|
})
|
|
])
|
|
return unloaded == 0
|
|
})
|
|
test(function() {
|
|
var root = mock.document.createElement("div")
|
|
var unloadedParent = 0
|
|
var unloadedChild = 0
|
|
var configParent = function(el, init, ctx) {
|
|
ctx.onunload = function() {
|
|
unloadedParent++
|
|
}
|
|
}
|
|
var configChild = function(el, init, ctx) {
|
|
ctx.onunload = function() {
|
|
unloadedChild++
|
|
}
|
|
}
|
|
var unloaded = 0
|
|
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() {
|
|
var root = mock.document.createElement("div")
|
|
var unloadedParent = 0
|
|
var unloadedChild = 0
|
|
var configParent = function(el, init, ctx) {
|
|
ctx.onunload = function() {
|
|
unloadedParent++
|
|
}
|
|
}
|
|
var configChild = function(el, init, ctx) {
|
|
ctx.onunload = function() {
|
|
unloadedChild++
|
|
}
|
|
}
|
|
var unloaded = 0
|
|
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
|
|
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"
|
|
})
|
|
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() {
|
|
return [m("div"), " "]
|
|
}),
|
|
m("span")
|
|
]))
|
|
return root.childNodes[0].childNodes[8].nodeName == "SPAN"
|
|
})
|
|
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}), m("li", {key: 2}), m("li", {key: 4})]))
|
|
m.render(root, m("ul", [m("li", {key: 0}), m("li", {key: 1}), m("li", {key: 2}), m("li", {key: 3}), m("li", {key: 4}), m("li", {key: 5})]))
|
|
return root.childNodes[0].childNodes.map(function(n) {return n.key}).join("") == "012345"
|
|
})
|
|
//end m.render
|
|
|
|
//m.redraw
|
|
test(function() {
|
|
mock.requestAnimationFrame.$resolve() //setup
|
|
var controller
|
|
var root = mock.document.createElement("div")
|
|
m.module(root, {
|
|
controller: function() {controller = 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
|
|
var count = 0
|
|
var root = mock.document.createElement("div")
|
|
m.module(root, {
|
|
controller: function() {},
|
|
view: function(ctrl) {
|
|
count++
|
|
}
|
|
})
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
m.redraw() //should run synchronously
|
|
|
|
m.redraw() //rest should run asynchronously since they're spamming
|
|
m.redraw()
|
|
m.redraw()
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return count === 3
|
|
})
|
|
|
|
//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"}}
|
|
})
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return mock.location.search == "?/test1" && root.childNodes[0].nodeValue === "foo"
|
|
})
|
|
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() {return "foo"}}
|
|
})
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return mock.location.pathname == "/test2" && root.childNodes[0].nodeValue === "foo"
|
|
})
|
|
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"}}
|
|
})
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return mock.location.hash == "#/test3" && root.childNodes[0].nodeValue === "foo"
|
|
})
|
|
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")}}
|
|
})
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return mock.location.search == "?/test4/foo" && root.childNodes[0].nodeValue === "foo"
|
|
})
|
|
test(function() {
|
|
mock.requestAnimationFrame.$resolve() //setup
|
|
mock.location.search = "?"
|
|
|
|
var module = {controller: function() {}, view: function() {return m.route.param("test")}}
|
|
|
|
var root = mock.document.createElement("div")
|
|
m.route.mode = "search"
|
|
m.route(root, "/test5/foo", {
|
|
"/": module,
|
|
"/test5/:test": module
|
|
})
|
|
var paramValueBefore = m.route.param("test")
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/")
|
|
var paramValueAfter = m.route.param("test")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return mock.location.search == "?/" && paramValueBefore === "foo" && paramValueAfter === undefined
|
|
})
|
|
test(function() {
|
|
mock.requestAnimationFrame.$resolve() //setup
|
|
mock.location.search = "?"
|
|
|
|
var module = {controller: function() {}, view: function() {return m.route.param("a1")}}
|
|
|
|
var root = mock.document.createElement("div")
|
|
m.route.mode = "search"
|
|
m.route(root, "/test6/foo", {
|
|
"/": module,
|
|
"/test6/:a1": module
|
|
})
|
|
var paramValueBefore = m.route.param("a1")
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/")
|
|
var paramValueAfter = m.route.param("a1")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return mock.location.search == "?/" && paramValueBefore === "foo" && paramValueAfter === undefined
|
|
})
|
|
test(function() {
|
|
//https://github.com/lhorie/mithril.js/issues/61
|
|
mock.requestAnimationFrame.$resolve() //setup
|
|
mock.location.search = "?"
|
|
|
|
var module = {controller: function() {}, view: function() {return m.route.param("a1")}}
|
|
|
|
var root = mock.document.createElement("div")
|
|
m.route.mode = "search"
|
|
m.route(root, "/test7/foo", {
|
|
"/": module,
|
|
"/test7/:a1": module
|
|
})
|
|
var routeValueBefore = m.route()
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/")
|
|
var routeValueAfter = m.route()
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return routeValueBefore === "/test7/foo" && routeValueAfter === "/"
|
|
})
|
|
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() {
|
|
return m.route.param("test") + "_" + m.route.param("path")
|
|
}
|
|
}
|
|
})
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return mock.location.search == "?/test8/foo/SEP/bar/baz" && root.childNodes[0].nodeValue === "foo_bar/baz"
|
|
})
|
|
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() {
|
|
return m.route.param("test") + "_" + m.route.param("path")
|
|
}
|
|
}
|
|
})
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return mock.location.search == "?/test9/foo/bar/SEP/baz" && root.childNodes[0].nodeValue === "foo/bar_baz"
|
|
})
|
|
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() {
|
|
return m.route.param("test")
|
|
}
|
|
}
|
|
})
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return root.childNodes[0].nodeValue === "foo bar"
|
|
})
|
|
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"}}
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/test11/")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return mock.location.search == "?/test11/" && root.childNodes[0].nodeValue === "bar"
|
|
})
|
|
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() {}}
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/test12?a=foo&b=bar")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return mock.location.search == "?/test12?a=foo&b=bar" && m.route.param("a") == "foo" && m.route.param("b") == "bar"
|
|
})
|
|
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")}}
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/test13/foo?test=bar")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return mock.location.search == "?/test13/foo?test=bar" && root.childNodes[0].nodeValue === "foo"
|
|
})
|
|
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"}}
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/test14?test&test2=")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return mock.location.search == "?/test14?test&test2=" && m.route.param("test") === true && m.route.param("test2") === ""
|
|
})
|
|
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() {}}
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/test12", {a: "foo", b: "bar"})
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return mock.location.search == "?/test12?a=foo&b=bar" && m.route.param("a") == "foo" && m.route.param("b") == "bar"
|
|
})
|
|
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() {}}
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/test13")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return route1 == "/" && route2 == "/test13"
|
|
})
|
|
test(function() {
|
|
mock.requestAnimationFrame.$resolve() //setup
|
|
mock.location.search = "?"
|
|
|
|
var root = mock.document.createElement("div")
|
|
var unloaded = 0
|
|
m.route.mode = "search"
|
|
m.route(root, "/", {
|
|
"/": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return m("div", {
|
|
config: function(el, init, ctx) {
|
|
ctx.onunload = function() {
|
|
unloaded++
|
|
}
|
|
}
|
|
})
|
|
}
|
|
},
|
|
"/test14": {controller: function() {}, view: function() {}}
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/test14")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return unloaded == 1
|
|
})
|
|
test(function() {
|
|
mock.requestAnimationFrame.$resolve() //setup
|
|
mock.location.search = "?"
|
|
|
|
var root = mock.document.createElement("div")
|
|
var unloaded = 0
|
|
m.route.mode = "search"
|
|
m.route(root, "/", {
|
|
"/": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return [
|
|
m("div"),
|
|
m("div", {
|
|
config: function(el, init, ctx) {
|
|
ctx.onunload = function() {
|
|
unloaded++
|
|
}
|
|
}
|
|
})
|
|
]
|
|
}
|
|
},
|
|
"/test15": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return [m("div")]
|
|
}
|
|
}
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/test15")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return unloaded == 1
|
|
})
|
|
test(function() {
|
|
mock.requestAnimationFrame.$resolve() //setup
|
|
mock.location.search = "?"
|
|
|
|
var root = mock.document.createElement("div")
|
|
var unloaded = 0
|
|
m.route.mode = "search"
|
|
m.route(root, "/", {
|
|
"/": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return m("div", {
|
|
config: function(el, init, ctx) {
|
|
ctx.onunload = function() {
|
|
unloaded++
|
|
}
|
|
}
|
|
})
|
|
}
|
|
},
|
|
"/test16": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return m("a")
|
|
}
|
|
}
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/test16")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return unloaded == 1
|
|
})
|
|
test(function() {
|
|
mock.requestAnimationFrame.$resolve() //setup
|
|
mock.location.search = "?"
|
|
|
|
var root = mock.document.createElement("div")
|
|
var unloaded = 0
|
|
m.route.mode = "search"
|
|
m.route(root, "/", {
|
|
"/": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return [
|
|
m("div", {
|
|
config: function(el, init, ctx) {
|
|
ctx.onunload = function() {
|
|
unloaded++
|
|
}
|
|
}
|
|
})
|
|
]
|
|
}
|
|
},
|
|
"/test17": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return m("a")
|
|
}
|
|
}
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/test17")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return unloaded == 1
|
|
})
|
|
test(function() {
|
|
mock.requestAnimationFrame.$resolve() //setup
|
|
mock.location.search = "?"
|
|
|
|
var root = mock.document.createElement("div")
|
|
var unloaded = 0
|
|
m.route.mode = "search"
|
|
m.route(root, "/", {
|
|
"/": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return m("div", {
|
|
config: function(el, init, ctx) {
|
|
ctx.onunload = function() {
|
|
unloaded++
|
|
}
|
|
}
|
|
})
|
|
}
|
|
},
|
|
"/test18": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return [m("a")]
|
|
}
|
|
}
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/test18")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return unloaded == 1
|
|
})
|
|
test(function() {
|
|
mock.requestAnimationFrame.$resolve() //setup
|
|
mock.location.search = "?"
|
|
|
|
var root = mock.document.createElement("div")
|
|
var unloaded = 0
|
|
m.route.mode = "search"
|
|
m.route(root, "/", {
|
|
"/": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return [
|
|
m("div", {
|
|
key: 1,
|
|
config: function(el, init, ctx) {
|
|
ctx.onunload = function() {
|
|
unloaded++
|
|
}
|
|
}
|
|
})
|
|
]
|
|
}
|
|
},
|
|
"/test20": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return [
|
|
m("div", {
|
|
key: 2,
|
|
config: function(el, init, ctx) {
|
|
ctx.onunload = function() {
|
|
unloaded++
|
|
}
|
|
}
|
|
})
|
|
]
|
|
}
|
|
}
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/test20")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return unloaded == 1
|
|
})
|
|
test(function() {
|
|
mock.requestAnimationFrame.$resolve() //setup
|
|
mock.location.search = "?"
|
|
|
|
var root = mock.document.createElement("div")
|
|
var unloaded = 0
|
|
m.route.mode = "search"
|
|
m.route(root, "/", {
|
|
"/": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return [
|
|
m("div", {
|
|
key: 1,
|
|
config: function(el, init, ctx) {
|
|
ctx.onunload = function() {
|
|
unloaded++
|
|
}
|
|
}
|
|
})
|
|
]
|
|
}
|
|
},
|
|
"/test21": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return [
|
|
m("div", {
|
|
config: function(el, init, ctx) {
|
|
ctx.onunload = function() {
|
|
unloaded++
|
|
}
|
|
}
|
|
})
|
|
]
|
|
}
|
|
}
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/test21")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return unloaded == 1
|
|
})
|
|
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");
|
|
}
|
|
},
|
|
"/bar": {
|
|
controller: function() {},
|
|
view: function() {
|
|
return m("div", "bar");
|
|
}
|
|
},
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
var foo = root.childNodes[0].childNodes[0].nodeValue;
|
|
m.route("/bar")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
var bar = root.childNodes[0].childNodes[0].nodeValue;
|
|
return (foo === "foo" && bar === "bar")
|
|
})
|
|
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() {
|
|
unloaded++
|
|
}
|
|
}
|
|
m.route.mode = "search"
|
|
m.route(root, "/foo1", {
|
|
"/foo1": {
|
|
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"));
|
|
}
|
|
},
|
|
})
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/bar1")
|
|
mock.requestAnimationFrame.$resolve() //teardown
|
|
return unloaded == 1
|
|
})
|
|
//end m.route
|
|
|
|
//m.prop
|
|
test(function() {
|
|
var prop = m.prop("test")
|
|
return prop() === "test"
|
|
})
|
|
test(function() {
|
|
var prop = m.prop("test")
|
|
prop("foo")
|
|
return prop() === "foo"
|
|
})
|
|
test(function() {
|
|
var prop = m.prop("test")
|
|
return JSON.stringify(prop) === '"test"'
|
|
})
|
|
test(function() {
|
|
var obj = {prop: m.prop("test")}
|
|
return JSON.stringify(obj) === '{"prop":"test"}'
|
|
})
|
|
|
|
//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(value) {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})
|
|
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})
|
|
mock.XMLHttpRequest.$instances.pop().onreadystatechange()
|
|
return prop().url === "http://domain.com:80/foo"
|
|
})
|
|
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)
|
|
mock.XMLHttpRequest.$instances.pop().onreadystatechange()
|
|
return prop() === undefined && 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}
|
|
m.endComputation()
|
|
return prop() === undefined && error() === "no error" && exception.message == "error occurred"
|
|
})
|
|
test(function() {
|
|
var error = m.prop("no error")
|
|
var prop = m.request({method: "POST", url: "test"}).then(null, error)
|
|
var xhr = mock.XMLHttpRequest.$instances.pop()
|
|
xhr.onreadystatechange()
|
|
return xhr.$headers["Content-Type"] == "application/json; charset=utf-8"
|
|
})
|
|
|
|
//m.deferred
|
|
test(function() {
|
|
var value
|
|
var deferred = m.deferred()
|
|
deferred.promise.then(function(data) {value = data})
|
|
deferred.resolve("test")
|
|
return value === "test"
|
|
})
|
|
test(function() {
|
|
var value
|
|
var deferred = m.deferred()
|
|
deferred.promise.then(function(data) {return "foo"}).then(function(data) {value = data})
|
|
deferred.resolve("test")
|
|
return value === "foo"
|
|
})
|
|
test(function() {
|
|
var value
|
|
var deferred = m.deferred()
|
|
deferred.promise.then(null, function(data) {value = data})
|
|
deferred.reject("test")
|
|
return value === "test"
|
|
})
|
|
test(function() {
|
|
var value
|
|
var deferred = m.deferred()
|
|
deferred.promise.then(null, function(data) {return "foo"}).then(null, function(data) {value = data})
|
|
deferred.reject("test")
|
|
return value === "foo"
|
|
})
|
|
test(function() {
|
|
var value1, value2
|
|
var deferred = m.deferred()
|
|
deferred.promise.then(function(data) {throw new Error}).then(function(data) {value1 = 1}, function(data) {value2 = data})
|
|
deferred.resolve("test")
|
|
return value1 === undefined && value2 instanceof Error
|
|
})
|
|
test(function() {
|
|
var deferred1 = m.deferred()
|
|
var deferred2 = m.deferred()
|
|
var value1, value2
|
|
deferred1.promise.then(function(data) {
|
|
value1 = data
|
|
return deferred2.promise
|
|
}).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
|
|
deferred.resolve(1)
|
|
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.reject(1)
|
|
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
|
|
deferred.resolve(1)
|
|
deferred.resolve(2)
|
|
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) {
|
|
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) {
|
|
value1 = 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() {
|
|
value1 = 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) {
|
|
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
|
|
deferred.resolve()
|
|
deferred.promise.then(function(data) {
|
|
value = 1
|
|
})
|
|
return value === 1
|
|
})
|
|
test(function() {
|
|
//https://github.com/lhorie/mithril.js/issues/85
|
|
var deferred = m.deferred(), value
|
|
deferred.reject()
|
|
deferred.promise.then(null, function(data) {
|
|
value = 1
|
|
})
|
|
return value === 1
|
|
})
|
|
test(function() {
|
|
var deferred = m.deferred(), value
|
|
deferred.resolve(1)
|
|
return deferred.promise() === 1
|
|
})
|
|
test(function() {
|
|
var deferred = m.deferred(), value
|
|
var promise = deferred.promise.then(function(data) {return data + 1})
|
|
deferred.resolve(1)
|
|
return promise() === 2
|
|
})
|
|
test(function() {
|
|
var deferred = m.deferred(), value
|
|
deferred.reject(1)
|
|
return deferred.promise() === undefined
|
|
})
|
|
|
|
//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})
|
|
deferred1.resolve("test")
|
|
deferred2.resolve("foo")
|
|
return value[0] === "test" && value[1] === "foo"
|
|
})
|
|
test(function() {
|
|
var value
|
|
var deferred1 = m.deferred()
|
|
var deferred2 = m.deferred()
|
|
m.sync([deferred1.promise, deferred2.promise]).then(function(data) {value = data})
|
|
deferred2.resolve("foo")
|
|
deferred1.resolve("test")
|
|
return value[0] === "test" && value[1] === "foo"
|
|
})
|
|
|
|
//m.startComputation/m.endComputation
|
|
test(function() {
|
|
mock.requestAnimationFrame.$resolve()
|
|
|
|
var controller
|
|
var root = mock.document.createElement("div")
|
|
m.module(root, {
|
|
controller: function() {controller = this},
|
|
view: function(ctrl) {return ctrl.value}
|
|
})
|
|
|
|
mock.requestAnimationFrame.$resolve()
|
|
|
|
m.startComputation()
|
|
controller.value = "foo"
|
|
m.endComputation()
|
|
mock.requestAnimationFrame.$resolve()
|
|
|
|
return root.childNodes[0].nodeValue === "foo"
|
|
})
|
|
|
|
//console.log presence
|
|
test(function() {
|
|
return m.deps.factory.toString().indexOf("console") < 0
|
|
})
|
|
|
|
// config context
|
|
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;
|
|
})
|
|
|
|
// more complex config context
|
|
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]);
|
|
|
|
idx = 0;
|
|
var checkConfig = function(elem, isInitialized, ctx) {
|
|
success = success && (ctx.data === idx++)
|
|
}
|
|
node = m("div", {config: checkConfig});
|
|
m.render(root, [node, node]);
|
|
return success;
|
|
})
|
|
|
|
}
|
|
|
|
//test reporting for saucelabs
|
|
if (typeof window != "undefined") {
|
|
window.global_test_results = {
|
|
tests: [],
|
|
duration: 0,
|
|
passed: 0,
|
|
failed: 0
|
|
};
|
|
}
|
|
|
|
//mock
|
|
testMithril(mock.window);
|
|
|
|
test.print(function(value){console.log(value)}); |