Created
July 10, 2014 17:29
-
-
Save AlexJWayne/3b6fa6d13b7f908c7234 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]") { | |
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 || b.index - a.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.toString() | |
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]) | |
} | |
} | |
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 autoredraw(callback, object, group) { | |
return function(e) { | |
e = e || event | |
m.startComputation() | |
try {return callback.call(object, e)} | |
finally {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 | |
cancel(lastRedrawId) | |
lastRedrawId = defer(redraw, 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 | |
} | |
} | |
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}) | |
;;; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment