mithril-vndb/mithril.js
Tetsuro Yoshikawa fdf2985adf Error in IE11 due to setting of type attribute
If you assign an input type that is not supported by IE11 with an
assignment expression, an error will occur.
2017-02-09 22:27:55 +09:00

1165 lines
No EOL
42 KiB
JavaScript

new function() {
function Vnode(tag, key, attrs0, children, text, dom) {
return {tag: tag, key: key, attrs: attrs0, children: children, text: text, dom: dom, domSize: undefined, state: {}, events: undefined, instance: undefined, skip: false}
}
Vnode.normalize = function(node) {
if (Array.isArray(node)) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined)
if (node != null && typeof node !== "object") return Vnode("#", undefined, undefined, node === false ? "" : node, undefined, undefined)
return node
}
Vnode.normalizeChildren = function normalizeChildren(children) {
for (var i = 0; i < children.length; i++) {
children[i] = Vnode.normalize(children[i])
}
return children
}
var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g
var selectorCache = {}
function hyperscript(selector) {
if (selector == null || typeof selector !== "string" && typeof selector.view !== "function") {
throw Error("The selector must be either a string or a component.");
}
if (typeof selector === "string" && selectorCache[selector] === undefined) {
var match, tag, classes = [], attributes = {}
while (match = selectorParser.exec(selector)) {
var type = match[1], value = match[2]
if (type === "" && value !== "") tag = value
else if (type === "#") attributes.id = value
else if (type === ".") classes.push(value)
else if (match[3][0] === "[") {
var attrValue = match[6]
if (attrValue) attrValue = attrValue.replace(/\\(["'])/g, "$1").replace(/\\\\/g, "\\")
if (match[4] === "class") classes.push(attrValue)
else attributes[match[4]] = attrValue || true
}
}
if (classes.length > 0) attributes.className = classes.join(" ")
selectorCache[selector] = function(attrs, children) {
var hasAttrs = false, childList, text
var className = attrs.className || attrs.class
for (var key in attributes) attrs[key] = attributes[key]
if (className !== undefined) {
if (attrs.class !== undefined) {
attrs.class = undefined
attrs.className = className
}
if (attributes.className !== undefined) attrs.className = attributes.className + " " + className
}
for (var key in attrs) {
if (key !== "key") {
hasAttrs = true
break
}
}
if (Array.isArray(children) && children.length == 1 && children[0] != null && children[0].tag === "#") text = children[0].children
else childList = children
return Vnode(tag || "div", attrs.key, hasAttrs ? attrs : undefined, childList, text, undefined)
}
}
var attrs, children, childrenIndex
if (arguments[1] == null || typeof arguments[1] === "object" && arguments[1].tag === undefined && !Array.isArray(arguments[1])) {
attrs = arguments[1]
childrenIndex = 2
}
else childrenIndex = 1
if (arguments.length === childrenIndex + 1) {
children = Array.isArray(arguments[childrenIndex]) ? arguments[childrenIndex] : [arguments[childrenIndex]]
}
else {
children = []
for (var i = childrenIndex; i < arguments.length; i++) children.push(arguments[i])
}
if (typeof selector === "string") return selectorCache[selector](attrs || {}, Vnode.normalizeChildren(children))
return Vnode(selector, attrs && attrs.key, attrs || {}, Vnode.normalizeChildren(children), undefined, undefined)
}
hyperscript.trust = function(html) {
if (html == null) html = ""
return Vnode("<", undefined, undefined, html, undefined, undefined)
}
hyperscript.fragment = function(attrs1, children) {
return Vnode("[", attrs1.key, attrs1, Vnode.normalizeChildren(children), undefined, undefined)
}
var m = hyperscript
/** @constructor */
var PromisePolyfill = function(executor) {
if (!(this instanceof PromisePolyfill)) throw new Error("Promise must be called with `new`")
if (typeof executor !== "function") throw new TypeError("executor must be a function")
var self = this, resolvers = [], rejectors = [], resolveCurrent = handler(resolvers, true), rejectCurrent = handler(rejectors, false)
var instance = self._instance = {resolvers: resolvers, rejectors: rejectors}
var callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout
function handler(list, shouldAbsorb) {
return function execute(value) {
var then
try {
if (shouldAbsorb && value != null && (typeof value === "object" || typeof value === "function") && typeof (then = value.then) === "function") {
if (value === self) throw new TypeError("Promise can't be resolved w/ itself")
executeOnce(then.bind(value))
}
else {
callAsync(function() {
if (!shouldAbsorb && list.length === 0) console.error("Possible unhandled promise rejection:", value)
for (var i = 0; i < list.length; i++) list[i](value)
resolvers.length = 0, rejectors.length = 0
instance.state = shouldAbsorb
instance.retry = function() {execute(value)}
})
}
}
catch (e) {
rejectCurrent(e)
}
}
}
function executeOnce(then) {
var runs = 0
function run(fn) {
return function(value) {
if (runs++ > 0) return
fn(value)
}
}
var onerror = run(rejectCurrent)
try {then(run(resolveCurrent), onerror)} catch (e) {onerror(e)}
}
executeOnce(executor)
}
PromisePolyfill.prototype.then = function(onFulfilled, onRejection) {
var self = this, instance = self._instance
function handle(callback, list, next, state) {
list.push(function(value) {
if (typeof callback !== "function") next(value)
else try {resolveNext(callback(value))} catch (e) {if (rejectNext) rejectNext(e)}
})
if (typeof instance.retry === "function" && state === instance.state) instance.retry()
}
var resolveNext, rejectNext
var promise = new PromisePolyfill(function(resolve, reject) {resolveNext = resolve, rejectNext = reject})
handle(onFulfilled, instance.resolvers, resolveNext, true), handle(onRejection, instance.rejectors, rejectNext, false)
return promise
}
PromisePolyfill.prototype.catch = function(onRejection) {
return this.then(null, onRejection)
}
PromisePolyfill.resolve = function(value) {
if (value instanceof PromisePolyfill) return value
return new PromisePolyfill(function(resolve) {resolve(value)})
}
PromisePolyfill.reject = function(value) {
return new PromisePolyfill(function(resolve, reject) {reject(value)})
}
PromisePolyfill.all = function(list) {
return new PromisePolyfill(function(resolve, reject) {
var total = list.length, count = 0, values = []
if (list.length === 0) resolve([])
else for (var i = 0; i < list.length; i++) {
(function(i) {
function consume(value) {
count++
values[i] = value
if (count === total) resolve(values)
}
if (list[i] != null && (typeof list[i] === "object" || typeof list[i] === "function") && typeof list[i].then === "function") {
list[i].then(consume, reject)
}
else consume(list[i])
})(i)
}
})
}
PromisePolyfill.race = function(list) {
return new PromisePolyfill(function(resolve, reject) {
for (var i = 0; i < list.length; i++) {
list[i].then(resolve, reject)
}
})
}
if (typeof window !== "undefined") {
if (typeof window.Promise === "undefined") window.Promise = PromisePolyfill
var PromisePolyfill = window.Promise
} else if (typeof global !== "undefined") {
if (typeof global.Promise === "undefined") global.Promise = PromisePolyfill
var PromisePolyfill = global.Promise
} else {
}
var buildQueryString = function(object) {
if (Object.prototype.toString.call(object) !== "[object Object]") return ""
var args = []
for (var key0 in object) {
destructure(key0, object[key0])
}
return args.join("&")
function destructure(key0, value) {
if (Array.isArray(value)) {
for (var i = 0; i < value.length; i++) {
destructure(key0 + "[" + i + "]", value[i])
}
}
else if (Object.prototype.toString.call(value) === "[object Object]") {
for (var i in value) {
destructure(key0 + "[" + i + "]", value[i])
}
}
else args.push(encodeURIComponent(key0) + (value != null && value !== "" ? "=" + encodeURIComponent(value) : ""))
}
}
var _8 = function($window, Promise) {
var callbackCount = 0
var oncompletion
function setCompletionCallback(callback) {oncompletion = callback}
function finalizer() {
var count = 0
function complete() {if (--count === 0 && typeof oncompletion === "function") oncompletion()}
return function finalize(promise0) {
var then0 = promise0.then
promise0.then = function() {
count++
var next = then0.apply(promise0, arguments)
next.then(complete, function(e) {
complete()
if (count === 0) throw e
})
return finalize(next)
}
return promise0
}
}
function normalize(args, extra) {
if (typeof args === "string") {
var url = args
args = extra || {}
if (args.url == null) args.url = url
}
return args
}
function request(args, extra) {
var finalize = finalizer()
args = normalize(args, extra)
var promise0 = new Promise(function(resolve, reject) {
if (args.method == null) args.method = "GET"
args.method = args.method.toUpperCase()
var useBody = typeof args.useBody === "boolean" ? args.useBody : args.method !== "GET" && args.method !== "TRACE"
if (typeof args.serialize !== "function") args.serialize = typeof FormData !== "undefined" && args.data instanceof FormData ? function(value) {return value} : JSON.stringify
if (typeof args.deserialize !== "function") args.deserialize = deserialize
if (typeof args.extract !== "function") args.extract = extract
args.url = interpolate(args.url, args.data)
if (useBody) args.data = args.serialize(args.data)
else args.url = assemble(args.url, args.data)
var xhr = new $window.XMLHttpRequest()
xhr.open(args.method, args.url, typeof args.async === "boolean" ? args.async : true, typeof args.user === "string" ? args.user : undefined, typeof args.password === "string" ? args.password : undefined)
if (args.serialize === JSON.stringify && useBody) {
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8")
}
if (args.deserialize === deserialize) {
xhr.setRequestHeader("Accept", "application/json, text/*")
}
if (args.withCredentials) xhr.withCredentials = args.withCredentials
for (var key in args.headers) if ({}.hasOwnProperty.call(args.headers, key)) {
xhr.setRequestHeader(key, args.headers[key])
}
if (typeof args.config === "function") xhr = args.config(xhr, args) || xhr
xhr.onreadystatechange = function() {
// Don't throw errors on xhr.abort(). XMLHttpRequests ends up in a state of
// xhr.status == 0 and xhr.readyState == 4 if aborted after open, but before completion.
if (xhr.status && xhr.readyState === 4) {
try {
var response = (args.extract !== extract) ? args.extract(xhr, args) : args.deserialize(args.extract(xhr, args))
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
resolve(cast(args.type, response))
}
else {
var error = new Error(xhr.responseText)
for (var key in response) error[key] = response[key]
reject(error)
}
}
catch (e) {
reject(e)
}
}
}
if (useBody && (args.data != null)) xhr.send(args.data)
else xhr.send()
})
return args.background === true ? promise0 : finalize(promise0)
}
function jsonp(args, extra) {
var finalize = finalizer()
args = normalize(args, extra)
var promise0 = new Promise(function(resolve, reject) {
var callbackName = args.callbackName || "_mithril_" + Math.round(Math.random() * 1e16) + "_" + callbackCount++
var script = $window.document.createElement("script")
$window[callbackName] = function(data) {
script.parentNode.removeChild(script)
resolve(cast(args.type, data))
delete $window[callbackName]
}
script.onerror = function() {
script.parentNode.removeChild(script)
reject(new Error("JSONP request failed"))
delete $window[callbackName]
}
if (args.data == null) args.data = {}
args.url = interpolate(args.url, args.data)
args.data[args.callbackKey || "callback"] = callbackName
script.src = assemble(args.url, args.data)
$window.document.documentElement.appendChild(script)
})
return args.background === true? promise0 : finalize(promise0)
}
function interpolate(url, data) {
if (data == null) return url
var tokens = url.match(/:[^\/]+/gi) || []
for (var i = 0; i < tokens.length; i++) {
var key = tokens[i].slice(1)
if (data[key] != null) {
url = url.replace(tokens[i], data[key])
}
}
return url
}
function assemble(url, data) {
var querystring = buildQueryString(data)
if (querystring !== "") {
var prefix = url.indexOf("?") < 0 ? "?" : "&"
url += prefix + querystring
}
return url
}
function deserialize(data) {
try {return data !== "" ? JSON.parse(data) : null}
catch (e) {throw new Error(data)}
}
function extract(xhr) {return xhr.responseText}
function cast(type0, data) {
if (typeof type0 === "function") {
if (Array.isArray(data)) {
for (var i = 0; i < data.length; i++) {
data[i] = new type0(data[i])
}
}
else return new type0(data)
}
return data
}
return {request: request, jsonp: jsonp, setCompletionCallback: setCompletionCallback}
}
var requestService = _8(window, PromisePolyfill)
var coreRenderer = function($window) {
var $doc = $window.document
var $emptyFragment = $doc.createDocumentFragment()
var onevent
function setEventCallback(callback) {return onevent = callback}
//create
function createNodes(parent, vnodes, start, end, hooks, nextSibling, ns) {
for (var i = start; i < end; i++) {
var vnode = vnodes[i]
if (vnode != null) {
insertNode(parent, createNode(vnode, hooks, ns), nextSibling)
}
}
}
function createNode(vnode, hooks, ns) {
var tag = vnode.tag
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
if (typeof tag === "string") {
switch (tag) {
case "#": return createText(vnode)
case "<": return createHTML(vnode)
case "[": return createFragment(vnode, hooks, ns)
default: return createElement(vnode, hooks, ns)
}
}
else return createComponent(vnode, hooks, ns)
}
function createText(vnode) {
return vnode.dom = $doc.createTextNode(vnode.children)
}
function createHTML(vnode) {
var match1 = vnode.children.match(/^\s*?<(\w+)/im) || []
var parent = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"}[match1[1]] || "div"
var temp = $doc.createElement(parent)
temp.innerHTML = vnode.children
vnode.dom = temp.firstChild
vnode.domSize = temp.childNodes.length
var fragment = $doc.createDocumentFragment()
var child
while (child = temp.firstChild) {
fragment.appendChild(child)
}
return fragment
}
function createFragment(vnode, hooks, ns) {
var fragment = $doc.createDocumentFragment()
if (vnode.children != null) {
var children = vnode.children
createNodes(fragment, children, 0, children.length, hooks, null, ns)
}
vnode.dom = fragment.firstChild
vnode.domSize = fragment.childNodes.length
return fragment
}
function createElement(vnode, hooks, ns) {
var tag = vnode.tag
switch (vnode.tag) {
case "svg": ns = "http://www.w3.org/2000/svg"; break
case "math": ns = "http://www.w3.org/1998/Math/MathML"; break
}
var attrs2 = vnode.attrs
var is = attrs2 && attrs2.is
var element = ns ?
is ? $doc.createElementNS(ns, tag, {is: is}) : $doc.createElementNS(ns, tag) :
is ? $doc.createElement(tag, {is: is}) : $doc.createElement(tag)
vnode.dom = element
if (attrs2 != null) {
setAttrs(vnode, attrs2, ns)
}
if (vnode.attrs != null && vnode.attrs.contenteditable != null) {
setContentEditable(vnode)
}
else {
if (vnode.text != null) {
if (vnode.text !== "") element.textContent = vnode.text
else vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)]
}
if (vnode.children != null) {
var children = vnode.children
createNodes(element, children, 0, children.length, hooks, null, ns)
setLateAttrs(vnode)
}
}
return element
}
function createComponent(vnode, hooks, ns) {
vnode.state = Object.create(vnode.tag)
var view = vnode.tag.view
if (view.reentrantLock != null) return $emptyFragment
view.reentrantLock = true
initLifecycle(vnode.tag, vnode, hooks)
vnode.instance = Vnode.normalize(view.call(vnode.state, vnode))
view.reentrantLock = null
if (vnode.instance != null) {
if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as arguments")
var element = createNode(vnode.instance, hooks, ns)
vnode.dom = vnode.instance.dom
vnode.domSize = vnode.dom != null ? vnode.instance.domSize : 0
return element
}
else {
vnode.domSize = 0
return $emptyFragment
}
}
//update
function updateNodes(parent, old, vnodes, hooks, nextSibling, ns) {
if (old === vnodes || old == null && vnodes == null) return
else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, undefined)
else if (vnodes == null) removeNodes(old, 0, old.length, vnodes)
else {
if (old.length === vnodes.length) {
var isUnkeyed = false
for (var i = 0; i < vnodes.length; i++) {
if (vnodes[i] != null && old[i] != null) {
isUnkeyed = vnodes[i].key == null && old[i].key == null
break
}
}
if (isUnkeyed) {
for (var i = 0; i < old.length; i++) {
if (old[i] === vnodes[i]) continue
else if (old[i] == null && vnodes[i] != null) insertNode(parent, createNode(vnodes[i], hooks, ns), getNextSibling(old, i + 1, nextSibling))
else if (vnodes[i] == null) removeNodes(old, i, i + 1, vnodes)
else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), false, ns)
}
return
}
}
var recycling = isRecyclable(old, vnodes)
if (recycling) old = old.concat(old.pool)
var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map
while (oldEnd >= oldStart && end >= start) {
var o = old[oldStart], v = vnodes[start]
if (o === v && !recycling) oldStart++, start++
else if (o == null) oldStart++
else if (v == null) start++
else if (o.key === v.key) {
oldStart++, start++
updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), recycling, ns)
if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
}
else {
var o = old[oldEnd]
if (o === v && !recycling) oldEnd--, start++
else if (o == null) oldEnd--
else if (v == null) start++
else if (o.key === v.key) {
updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
if (recycling || start < end) insertNode(parent, toFragment(o), getNextSibling(old, oldStart, nextSibling))
oldEnd--, start++
}
else break
}
}
while (oldEnd >= oldStart && end >= start) {
var o = old[oldEnd], v = vnodes[end]
if (o === v && !recycling) oldEnd--, end--
else if (o == null) oldEnd--
else if (v == null) end--
else if (o.key === v.key) {
updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
if (o.dom != null) nextSibling = o.dom
oldEnd--, end--
}
else {
if (!map) map = getKeyMap(old, oldEnd)
if (v != null) {
var oldIndex = map[v.key]
if (oldIndex != null) {
var movable = old[oldIndex]
updateNode(parent, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
insertNode(parent, toFragment(movable), nextSibling)
old[oldIndex].skip = true
if (movable.dom != null) nextSibling = movable.dom
}
else {
var dom = createNode(v, hooks, undefined)
insertNode(parent, dom, nextSibling)
nextSibling = dom
}
}
end--
}
if (end < start) break
}
createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns)
removeNodes(old, oldStart, oldEnd + 1, vnodes)
}
}
function updateNode(parent, old, vnode, hooks, nextSibling, recycling, ns) {
var oldTag = old.tag, tag = vnode.tag
if (oldTag === tag) {
vnode.state = old.state
vnode.events = old.events
if (shouldUpdate(vnode, old)) return
if (vnode.attrs != null) {
updateLifecycle(vnode.attrs, vnode, hooks, recycling)
}
if (typeof oldTag === "string") {
switch (oldTag) {
case "#": updateText(old, vnode); break
case "<": updateHTML(parent, old, vnode, nextSibling); break
case "[": updateFragment(parent, old, vnode, hooks, nextSibling, ns); break
default: updateElement(old, vnode, hooks, ns)
}
}
else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns)
}
else {
removeNode(old, null)
insertNode(parent, createNode(vnode, hooks, ns), nextSibling)
}
}
function updateText(old, vnode) {
if (old.children.toString() !== vnode.children.toString()) {
old.dom.nodeValue = vnode.children
}
vnode.dom = old.dom
}
function updateHTML(parent, old, vnode, nextSibling) {
if (old.children !== vnode.children) {
toFragment(old)
insertNode(parent, createHTML(vnode), nextSibling)
}
else vnode.dom = old.dom, vnode.domSize = old.domSize
}
function updateFragment(parent, old, vnode, hooks, nextSibling, ns) {
updateNodes(parent, old.children, vnode.children, hooks, nextSibling, ns)
var domSize = 0, children = vnode.children
vnode.dom = null
if (children != null) {
for (var i = 0; i < children.length; i++) {
var child = children[i]
if (child != null && child.dom != null) {
if (vnode.dom == null) vnode.dom = child.dom
domSize += child.domSize || 1
}
}
if (domSize !== 1) vnode.domSize = domSize
}
}
function updateElement(old, vnode, hooks, ns) {
var element = vnode.dom = old.dom
switch (vnode.tag) {
case "svg": ns = "http://www.w3.org/2000/svg"; break
case "math": ns = "http://www.w3.org/1998/Math/MathML"; break
}
if (vnode.tag === "textarea") {
if (vnode.attrs == null) vnode.attrs = {}
if (vnode.text != null) {
vnode.attrs.value = vnode.text //FIXME handle0 multiple children
vnode.text = undefined
}
}
updateAttrs(vnode, old.attrs, vnode.attrs, ns)
if (vnode.attrs != null && vnode.attrs.contenteditable != null) {
setContentEditable(vnode)
}
else if (old.text != null && vnode.text != null && vnode.text !== "") {
if (old.text.toString() !== vnode.text.toString()) old.dom.firstChild.nodeValue = vnode.text
}
else {
if (old.text != null) old.children = [Vnode("#", undefined, undefined, old.text, undefined, old.dom.firstChild)]
if (vnode.text != null) vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)]
updateNodes(element, old.children, vnode.children, hooks, null, ns)
}
}
function updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) {
vnode.instance = Vnode.normalize(vnode.tag.view.call(vnode.state, vnode))
updateLifecycle(vnode.tag, vnode, hooks, recycling)
if (vnode.instance != null) {
if (old.instance == null) insertNode(parent, createNode(vnode.instance, hooks, ns), nextSibling)
else updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, recycling, ns)
vnode.dom = vnode.instance.dom
vnode.domSize = vnode.instance.domSize
}
else if (old.instance != null) {
removeNode(old.instance, null)
vnode.dom = undefined
vnode.domSize = 0
}
else {
vnode.dom = old.dom
vnode.domSize = old.domSize
}
}
function isRecyclable(old, vnodes) {
if (old.pool != null && Math.abs(old.pool.length - vnodes.length) <= Math.abs(old.length - vnodes.length)) {
var oldChildrenLength = old[0] && old[0].children && old[0].children.length || 0
var poolChildrenLength = old.pool[0] && old.pool[0].children && old.pool[0].children.length || 0
var vnodesChildrenLength = vnodes[0] && vnodes[0].children && vnodes[0].children.length || 0
if (Math.abs(poolChildrenLength - vnodesChildrenLength) <= Math.abs(oldChildrenLength - vnodesChildrenLength)) {
return true
}
}
return false
}
function getKeyMap(vnodes, end) {
var map = {}, i = 0
for (var i = 0; i < end; i++) {
var vnode = vnodes[i]
if (vnode != null) {
var key2 = vnode.key
if (key2 != null) map[key2] = i
}
}
return map
}
function toFragment(vnode) {
var count0 = vnode.domSize
if (count0 != null || vnode.dom == null) {
var fragment = $doc.createDocumentFragment()
if (count0 > 0) {
var dom = vnode.dom
while (--count0) fragment.appendChild(dom.nextSibling)
fragment.insertBefore(dom, fragment.firstChild)
}
return fragment
}
else return vnode.dom
}
function getNextSibling(vnodes, i, nextSibling) {
for (; i < vnodes.length; i++) {
if (vnodes[i] != null && vnodes[i].dom != null) return vnodes[i].dom
}
return nextSibling
}
function insertNode(parent, dom, nextSibling) {
if (nextSibling && nextSibling.parentNode) parent.insertBefore(dom, nextSibling)
else parent.appendChild(dom)
}
function setContentEditable(vnode) {
var children = vnode.children
if (children != null && children.length === 1 && children[0].tag === "<") {
var content = children[0].children
if (vnode.dom.innerHTML !== content) vnode.dom.innerHTML = content
}
else if (vnode.text != null || children != null && children.length !== 0) throw new Error("Child node of a contenteditable must be trusted")
}
//remove
function removeNodes(vnodes, start, end, context) {
for (var i = start; i < end; i++) {
var vnode = vnodes[i]
if (vnode != null) {
if (vnode.skip) vnode.skip = false
else removeNode(vnode, context)
}
}
}
function removeNode(vnode, context) {
var expected = 1, called = 0
if (vnode.attrs && vnode.attrs.onbeforeremove) {
var result = vnode.attrs.onbeforeremove.call(vnode.state, vnode)
if (result != null && typeof result.then === "function") {
expected++
result.then(continuation, continuation)
}
}
if (typeof vnode.tag !== "string" && vnode.tag.onbeforeremove) {
var result = vnode.tag.onbeforeremove.call(vnode.state, vnode)
if (result != null && typeof result.then === "function") {
expected++
result.then(continuation, continuation)
}
}
continuation()
function continuation() {
if (++called === expected) {
onremove(vnode)
if (vnode.dom) {
var count0 = vnode.domSize || 1
if (count0 > 1) {
var dom = vnode.dom
while (--count0) {
removeNodeFromDOM(dom.nextSibling)
}
}
removeNodeFromDOM(vnode.dom)
if (context != null && vnode.domSize == null && !hasIntegrationMethods(vnode.attrs) && typeof vnode.tag === "string") { //TODO test custom elements
if (!context.pool) context.pool = [vnode]
else context.pool.push(vnode)
}
}
}
}
}
function removeNodeFromDOM(node) {
var parent = node.parentNode
if (parent != null) parent.removeChild(node)
}
function onremove(vnode) {
if (vnode.attrs && vnode.attrs.onremove) vnode.attrs.onremove.call(vnode.state, vnode)
if (typeof vnode.tag !== "string" && vnode.tag.onremove) vnode.tag.onremove.call(vnode.state, vnode)
if (vnode.instance != null) onremove(vnode.instance)
else {
var children = vnode.children
if (Array.isArray(children)) {
for (var i = 0; i < children.length; i++) {
var child = children[i]
if (child != null) onremove(child)
}
}
}
}
//attrs2
function setAttrs(vnode, attrs2, ns) {
for (var key2 in attrs2) {
setAttr(vnode, key2, null, attrs2[key2], ns)
}
}
function setAttr(vnode, key2, old, value, ns) {
var element = vnode.dom
if (key2 === "key" || key2 === "is" || (old === value && !isFormAttribute(vnode, key2)) && typeof value !== "object" || typeof value === "undefined" || isLifecycleMethod(key2)) return
var nsLastIndex = key2.indexOf(":")
if (nsLastIndex > -1 && key2.substr(0, nsLastIndex) === "xlink") {
element.setAttributeNS("http://www.w3.org/1999/xlink", key2.slice(nsLastIndex + 1), value)
}
else if (key2[0] === "o" && key2[1] === "n" && typeof value === "function") updateEvent(vnode, key2, value)
else if (key2 === "style") updateStyle(element, old, value)
else if (key2 in element && !isAttribute(key2) && ns === undefined && !isCustomElement(vnode)) {
//setting input[value] to same value by typing on focused element moves cursor to end in Chrome
if (vnode.tag === "input" && key2 === "value" && vnode.dom.value === value && vnode.dom === $doc.activeElement) return
//setting select[value] to same value while having select open blinks select dropdown in Chrome
if (vnode.tag === "select" && key2 === "value" && vnode.dom.value === value && vnode.dom === $doc.activeElement) return
//setting option[value] to same value while having select open blinks select dropdown in Chrome
if (vnode.tag === "option" && key2 === "value" && vnode.dom.value === value) return
// If you assign an input type1 that is not supported by IE 11 with an assignment expression, an error0 will occur.
if (vnode.tag === "input" && key2 === "type") {
element.setAttribute(key2, value);
return
}
element[key2] = value
}
else {
if (typeof value === "boolean") {
if (value) element.setAttribute(key2, "")
else element.removeAttribute(key2)
}
else element.setAttribute(key2 === "className" ? "class" : key2, value)
}
}
function setLateAttrs(vnode) {
var attrs2 = vnode.attrs
if (vnode.tag === "select" && attrs2 != null) {
if ("value" in attrs2) setAttr(vnode, "value", null, attrs2.value, undefined)
if ("selectedIndex" in attrs2) setAttr(vnode, "selectedIndex", null, attrs2.selectedIndex, undefined)
}
}
function updateAttrs(vnode, old, attrs2, ns) {
if (attrs2 != null) {
for (var key2 in attrs2) {
setAttr(vnode, key2, old && old[key2], attrs2[key2], ns)
}
}
if (old != null) {
for (var key2 in old) {
if (attrs2 == null || !(key2 in attrs2)) {
if (key2 === "className") key2 = "class"
if (key2[0] === "o" && key2[1] === "n" && !isLifecycleMethod(key2)) updateEvent(vnode, key2, undefined)
else if (key2 !== "key") vnode.dom.removeAttribute(key2)
}
}
}
}
function isFormAttribute(vnode, attr) {
return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === $doc.activeElement
}
function isLifecycleMethod(attr) {
return attr === "oninit" || attr === "oncreate" || attr === "onupdate" || attr === "onremove" || attr === "onbeforeremove" || attr === "onbeforeupdate"
}
function isAttribute(attr) {
return attr === "href" || attr === "list" || attr === "form" || attr === "width" || attr === "height"// || attr === "type"
}
function isCustomElement(vnode){
return vnode.attrs.is || vnode.tag.indexOf("-") > -1
}
function hasIntegrationMethods(source) {
return source != null && (source.oncreate || source.onupdate || source.onbeforeremove || source.onremove)
}
//style
function updateStyle(element, old, style) {
if (old === style) element.style.cssText = "", old = null
if (style == null) element.style.cssText = ""
else if (typeof style === "string") element.style.cssText = style
else {
if (typeof old === "string") element.style.cssText = ""
for (var key2 in style) {
element.style[key2] = style[key2]
}
if (old != null && typeof old !== "string") {
for (var key2 in old) {
if (!(key2 in style)) element.style[key2] = ""
}
}
}
}
//event
function updateEvent(vnode, key2, value) {
var element = vnode.dom
var callback = typeof onevent !== "function" ? value : function(e) {
var result = value.call(element, e)
onevent.call(element, e)
return result
}
if (key2 in element) element[key2] = typeof value === "function" ? callback : null
else {
var eventName = key2.slice(2)
if (vnode.events === undefined) vnode.events = {}
if (vnode.events[key2] === callback) return
if (vnode.events[key2] != null) element.removeEventListener(eventName, vnode.events[key2], false)
if (typeof value === "function") {
vnode.events[key2] = callback
element.addEventListener(eventName, vnode.events[key2], false)
}
}
}
//lifecycle
function initLifecycle(source, vnode, hooks) {
if (typeof source.oninit === "function") source.oninit.call(vnode.state, vnode)
if (typeof source.oncreate === "function") hooks.push(source.oncreate.bind(vnode.state, vnode))
}
function updateLifecycle(source, vnode, hooks, recycling) {
if (recycling) initLifecycle(source, vnode, hooks)
else if (typeof source.onupdate === "function") hooks.push(source.onupdate.bind(vnode.state, vnode))
}
function shouldUpdate(vnode, old) {
var forceVnodeUpdate, forceComponentUpdate
if (vnode.attrs != null && typeof vnode.attrs.onbeforeupdate === "function") forceVnodeUpdate = vnode.attrs.onbeforeupdate.call(vnode.state, vnode, old)
if (typeof vnode.tag !== "string" && typeof vnode.tag.onbeforeupdate === "function") forceComponentUpdate = vnode.tag.onbeforeupdate.call(vnode.state, vnode, old)
if (!(forceVnodeUpdate === undefined && forceComponentUpdate === undefined) && !forceVnodeUpdate && !forceComponentUpdate) {
vnode.dom = old.dom
vnode.domSize = old.domSize
vnode.instance = old.instance
return true
}
return false
}
function render(dom, vnodes) {
if (!dom) throw new Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.")
var hooks = []
var active = $doc.activeElement
// First time0 rendering into a node clears it out
if (dom.vnodes == null) dom.textContent = ""
if (!Array.isArray(vnodes)) vnodes = [vnodes]
updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), hooks, null, undefined)
dom.vnodes = vnodes
for (var i = 0; i < hooks.length; i++) hooks[i]()
if ($doc.activeElement !== active) active.focus()
}
return {render: render, setEventCallback: setEventCallback}
}
function throttle(callback) {
//60fps translates to 16.6ms, round it down since setTimeout requires int
var time = 16
var last = 0, pending = null
var timeout = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout
return function() {
var now = Date.now()
if (last === 0 || now - last >= time) {
last = now
callback()
}
else if (pending === null) {
pending = timeout(function() {
pending = null
callback()
last = Date.now()
}, time - (now - last))
}
}
}
var _11 = function($window) {
var renderService = coreRenderer($window)
renderService.setEventCallback(function(e) {
if (e.redraw !== false) redraw()
})
var callbacks = []
function subscribe(key1, callback) {
unsubscribe(key1)
callbacks.push(key1, throttle(callback))
}
function unsubscribe(key1) {
var index = callbacks.indexOf(key1)
if (index > -1) callbacks.splice(index, 2)
}
function redraw() {
for (var i = 1; i < callbacks.length; i += 2) {
callbacks[i]()
}
}
return {subscribe: subscribe, unsubscribe: unsubscribe, redraw: redraw, render: renderService.render}
}
var redrawService = _11(window)
requestService.setCompletionCallback(redrawService.redraw)
var _16 = function(redrawService0) {
return function(root, component) {
if (component === null) {
redrawService0.render(root, [])
redrawService0.unsubscribe(root)
return
}
if (component.view == null) throw new Error("m.mount(element, component) expects a component, not a vnode")
var run0 = function() {
redrawService0.render(root, Vnode(component))
}
redrawService0.subscribe(root, run0)
redrawService0.redraw()
}
}
m.mount = _16(redrawService)
var Promise = PromisePolyfill
var parseQueryString = function(string) {
if (string === "" || string == null) return {}
if (string.charAt(0) === "?") string = string.slice(1)
var entries = string.split("&"), data0 = {}, counters = {}
for (var i = 0; i < entries.length; i++) {
var entry = entries[i].split("=")
var key5 = decodeURIComponent(entry[0])
var value = entry.length === 2 ? decodeURIComponent(entry[1]) : ""
if (value === "true") value = true
else if (value === "false") value = false
var levels = key5.split(/\]\[?|\[/)
var cursor = data0
if (key5.indexOf("[") > -1) levels.pop()
for (var j = 0; j < levels.length; j++) {
var level = levels[j], nextLevel = levels[j + 1]
var isNumber = nextLevel == "" || !isNaN(parseInt(nextLevel, 10))
var isValue = j === levels.length - 1
if (level === "") {
var key5 = levels.slice(0, j).join()
if (counters[key5] == null) counters[key5] = 0
level = counters[key5]++
}
if (cursor[level] == null) {
cursor[level] = isValue ? value : isNumber ? [] : {}
}
cursor = cursor[level]
}
}
return data0
}
var coreRouter = function($window) {
var supportsPushState = typeof $window.history.pushState === "function"
var callAsync0 = typeof setImmediate === "function" ? setImmediate : setTimeout
function normalize1(fragment0) {
var data = $window.location[fragment0].replace(/(?:%[a-f89][a-f0-9])+/gim, decodeURIComponent)
if (fragment0 === "pathname" && data[0] !== "/") data = "/" + data
return data
}
var asyncId
function debounceAsync(callback0) {
return function() {
if (asyncId != null) return
asyncId = callAsync0(function() {
asyncId = null
callback0()
})
}
}
function parsePath(path, queryData, hashData) {
var queryIndex = path.indexOf("?")
var hashIndex = path.indexOf("#")
var pathEnd = queryIndex > -1 ? queryIndex : hashIndex > -1 ? hashIndex : path.length
if (queryIndex > -1) {
var queryEnd = hashIndex > -1 ? hashIndex : path.length
var queryParams = parseQueryString(path.slice(queryIndex + 1, queryEnd))
for (var key4 in queryParams) queryData[key4] = queryParams[key4]
}
if (hashIndex > -1) {
var hashParams = parseQueryString(path.slice(hashIndex + 1))
for (var key4 in hashParams) hashData[key4] = hashParams[key4]
}
return path.slice(0, pathEnd)
}
var router = {prefix: "#!"}
router.getPath = function() {
var type2 = router.prefix.charAt(0)
switch (type2) {
case "#": return normalize1("hash").slice(router.prefix.length)
case "?": return normalize1("search").slice(router.prefix.length) + normalize1("hash")
default: return normalize1("pathname").slice(router.prefix.length) + normalize1("search") + normalize1("hash")
}
}
router.setPath = function(path, data, options) {
var queryData = {}, hashData = {}
path = parsePath(path, queryData, hashData)
if (data != null) {
for (var key4 in data) queryData[key4] = data[key4]
path = path.replace(/:([^\/]+)/g, function(match2, token) {
delete queryData[token]
return data[token]
})
}
var query = buildQueryString(queryData)
if (query) path += "?" + query
var hash = buildQueryString(hashData)
if (hash) path += "#" + hash
if (supportsPushState) {
var state = options ? options.state : null
var title = options ? options.title : null
$window.onpopstate()
if (options && options.replace) $window.history.replaceState(state, title, router.prefix + path)
else $window.history.pushState(state, title, router.prefix + path)
}
else $window.location.href = router.prefix + path
}
router.defineRoutes = function(routes, resolve, reject) {
function resolveRoute() {
var path = router.getPath()
var params = {}
var pathname = parsePath(path, params, params)
var state = $window.history.state
if (state != null) {
for (var k in state) params[k] = state[k]
}
for (var route0 in routes) {
var matcher = new RegExp("^" + route0.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$")
if (matcher.test(pathname)) {
pathname.replace(matcher, function() {
var keys = route0.match(/:[^\/]+/g) || []
var values = [].slice.call(arguments, 1, -2)
for (var i = 0; i < keys.length; i++) {
params[keys[i].replace(/:|\./g, "")] = decodeURIComponent(values[i])
}
resolve(routes[route0], params, path, route0)
})
return
}
}
reject(path, params)
}
if (supportsPushState) $window.onpopstate = debounceAsync(resolveRoute)
else if (router.prefix.charAt(0) === "#") $window.onhashchange = resolveRoute
resolveRoute()
}
return router
}
var _20 = function($window, redrawService0) {
var routeService = coreRouter($window)
var identity = function(v) {return v}
var render1, component, attrs3, currentPath, lastUpdate
var route = function(root, defaultRoute, routes) {
if (root == null) throw new Error("Ensure the DOM element that was passed to `m.route` is not undefined")
var run1 = function() {
if (render1 != null) redrawService0.render(root, render1(Vnode(component, attrs3.key, attrs3)))
}
var bail = function() {
routeService.setPath(defaultRoute, null, {replace: true})
}
routeService.defineRoutes(routes, function(payload, params, path) {
var update = lastUpdate = function(routeResolver, comp) {
if (update !== lastUpdate) return
component = comp != null && typeof comp.view === "function" ? comp : "div", attrs3 = params, currentPath = path, lastUpdate = null
render1 = (routeResolver.render || identity).bind(routeResolver)
run1()
}
if (payload.view) update({}, payload)
else {
if (payload.onmatch) {
Promise.resolve(payload.onmatch(params, path)).then(function(resolved) {
update(payload, resolved)
}, bail)
}
else update(payload, "div")
}
}, bail)
redrawService0.subscribe(root, run1)
}
route.set = function(path, data, options) {
if (lastUpdate != null) options = {replace: true}
lastUpdate = null
routeService.setPath(path, data, options)
}
route.get = function() {return currentPath}
route.prefix = function(prefix0) {routeService.prefix = prefix0}
route.link = function(vnode1) {
vnode1.dom.setAttribute("href", routeService.prefix + vnode1.attrs.href)
vnode1.dom.onclick = function(e) {
if (e.ctrlKey || e.metaKey || e.shiftKey || e.which === 2) return
e.preventDefault()
e.redraw = false
var href = this.getAttribute("href")
if (href.indexOf(routeService.prefix) === 0) href = href.slice(routeService.prefix.length)
route.set(href, undefined, undefined)
}
}
route.param = function(key3) {
if(typeof attrs3 !== "undefined" && typeof key3 !== "undefined") return attrs3[key3]
return attrs3
}
return route
}
m.route = _20(window, redrawService)
m.withAttr = function(attrName, callback1, context) {
return function(e) {
callback1.call(context || this, attrName in e.currentTarget ? e.currentTarget[attrName] : e.currentTarget.getAttribute(attrName))
}
}
var _28 = coreRenderer(window)
m.render = _28.render
m.redraw = redrawService.redraw
m.request = requestService.request
m.jsonp = requestService.jsonp
m.parseQueryString = parseQueryString
m.buildQueryString = buildQueryString
m.version = "1.0.0"
m.vnode = Vnode
if (typeof module !== "undefined") module["exports"] = m
else window.m = m
}