From b8627813be56e04c18baf38885f3a3dc0fb7496c Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Sun, 24 Jan 2016 02:29:13 +0100 Subject: Replace handlebars with mithril, hooks for i18n. The wallet is now a single page application. --- extension/lib/vendor/mithril.js | 1408 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1408 insertions(+) create mode 100644 extension/lib/vendor/mithril.js (limited to 'extension/lib/vendor/mithril.js') diff --git a/extension/lib/vendor/mithril.js b/extension/lib/vendor/mithril.js new file mode 100644 index 000000000..32bdf64c1 --- /dev/null +++ b/extension/lib/vendor/mithril.js @@ -0,0 +1,1408 @@ +var m = (function app(window, undefined) { + "use strict"; + var VERSION = "v0.2.2-rc.1"; + function isFunction(object) { + return typeof object === "function"; + } + function isObject(object) { + return type.call(object) === "[object Object]"; + } + function isString(object) { + return type.call(object) === "[object String]"; + } + var isArray = Array.isArray || function (object) { + return type.call(object) === "[object Array]"; + }; + var type = {}.toString; + var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, attrParser = /\[(.+?)(?:=("|'|)(.*?)\2)?\]/; + var voidElements = /^(AREA|BASE|BR|COL|COMMAND|EMBED|HR|IMG|INPUT|KEYGEN|LINK|META|PARAM|SOURCE|TRACK|WBR)$/; + var noop = function () {}; + + // caching commonly used variables + var $document, $location, $requestAnimationFrame, $cancelAnimationFrame; + + // self invoking function needed because of the way mocks work + function initialize(window) { + $document = window.document; + $location = window.location; + $cancelAnimationFrame = window.cancelAnimationFrame || window.clearTimeout; + $requestAnimationFrame = window.requestAnimationFrame || window.setTimeout; + } + + initialize(window); + + m.version = function() { + return VERSION; + }; + + /** + * @typedef {String} Tag + * A string that looks like -> div.classname#id[param=one][param2=two] + * Which describes a DOM node + */ + + /** + * + * @param {Tag} The DOM node tag + * @param {Object=[]} optional key-value pairs to be mapped to DOM attrs + * @param {...mNode=[]} Zero or more Mithril child nodes. Can be an array, or splat (optional) + * + */ + function m(tag, pairs) { + for (var args = [], i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + if (isObject(tag)) return parameterize(tag, args); + var hasAttrs = pairs != null && isObject(pairs) && !("tag" in pairs || "view" in pairs || "subtree" in pairs); + var attrs = hasAttrs ? pairs : {}; + var classAttrName = "class" in attrs ? "class" : "className"; + var cell = {tag: "div", attrs: {}}; + var match, classes = []; + if (!isString(tag)) throw new Error("selector in m(selector, attrs, children) should be a string"); + while ((match = parser.exec(tag)) != null) { + if (match[1] === "" && match[2]) cell.tag = match[2]; + else if (match[1] === "#") cell.attrs.id = match[2]; + else if (match[1] === ".") classes.push(match[2]); + else if (match[3][0] === "[") { + var pair = attrParser.exec(match[3]); + cell.attrs[pair[1]] = pair[3] || (pair[2] ? "" :true); + } + } + + var children = hasAttrs ? args.slice(1) : args; + if (children.length === 1 && isArray(children[0])) { + cell.children = children[0]; + } + else { + cell.children = children; + } + + for (var attrName in attrs) { + if (attrs.hasOwnProperty(attrName)) { + if (attrName === classAttrName && attrs[attrName] != null && attrs[attrName] !== "") { + classes.push(attrs[attrName]); + cell.attrs[attrName] = ""; //create key in correct iteration order + } + else cell.attrs[attrName] = attrs[attrName]; + } + } + if (classes.length) cell.attrs[classAttrName] = classes.join(" "); + + return cell; + } + function forEach(list, f) { + for (var i = 0; i < list.length && !f(list[i], i++);) {} + } + function forKeys(list, f) { + forEach(list, function (attrs, i) { + return (attrs = attrs && attrs.attrs) && attrs.key != null && f(attrs, i); + }); + } + // This function was causing deopts in Chrome. + function dataToString(data) { + //data.toString() might throw or return null if data is the return value of Console.log in Firefox (behavior depends on version) + try { + if (data == null || data.toString() == null) return ""; + } catch (e) { + return ""; + } + return data; + } + // This function was causing deopts in Chrome. + function injectTextNode(parentElement, first, index, data) { + try { + insertNode(parentElement, first, index); + first.nodeValue = data; + } catch (e) {} //IE erroneously throws error when appending an empty text node after a null + } + + function flatten(list) { + //recursively flatten array + for (var i = 0; i < list.length; i++) { + if (isArray(list[i])) { + list = list.concat.apply([], list); + //check current index again and flatten until there are no more nested arrays at that index + i--; + } + } + return list; + } + + function insertNode(parentElement, node, index) { + parentElement.insertBefore(node, parentElement.childNodes[index] || null); + } + + var DELETION = 1, INSERTION = 2, MOVE = 3; + + function handleKeysDiffer(data, existing, cached, parentElement) { + forKeys(data, function (key, i) { + existing[key = key.key] = existing[key] ? { + action: MOVE, + index: i, + from: existing[key].index, + element: cached.nodes[existing[key].index] || $document.createElement("div") + } : {action: INSERTION, index: i}; + }); + var actions = []; + for (var prop in existing) actions.push(existing[prop]); + var changes = actions.sort(sortChanges), newCached = new Array(cached.length); + newCached.nodes = cached.nodes.slice(); + + forEach(changes, function (change) { + var index = change.index; + if (change.action === DELETION) { + clear(cached[index].nodes, cached[index]); + newCached.splice(index, 1); + } + if (change.action === INSERTION) { + var dummy = $document.createElement("div"); + dummy.key = data[index].attrs.key; + insertNode(parentElement, dummy, index); + newCached.splice(index, 0, { + attrs: {key: data[index].attrs.key}, + nodes: [dummy] + }); + newCached.nodes[index] = dummy; + } + + if (change.action === MOVE) { + var changeElement = change.element; + var maybeChanged = parentElement.childNodes[index]; + if (maybeChanged !== changeElement && changeElement !== null) { + parentElement.insertBefore(changeElement, maybeChanged || null); + } + newCached[index] = cached[change.from]; + newCached.nodes[index] = changeElement; + } + }); + + return newCached; + } + + function diffKeys(data, cached, existing, parentElement) { + var keysDiffer = data.length !== cached.length; + if (!keysDiffer) { + forKeys(data, function (attrs, i) { + var cachedCell = cached[i]; + return keysDiffer = cachedCell && cachedCell.attrs && cachedCell.attrs.key !== attrs.key; + }); + } + + return keysDiffer ? handleKeysDiffer(data, existing, cached, parentElement) : cached; + } + + function diffArray(data, cached, nodes) { + //diff the array itself + + //update the list of DOM nodes by collecting the nodes from each item + forEach(data, function (_, i) { + if (cached[i] != null) nodes.push.apply(nodes, cached[i].nodes); + }) + //remove items from the end of the array if the new array is shorter than the old one. if errors ever happen here, the issue is most likely + //a bug in the construction of the `cached` data structure somewhere earlier in the program + forEach(cached.nodes, function (node, i) { + if (node.parentNode != null && nodes.indexOf(node) < 0) clear([node], [cached[i]]); + }) + if (data.length < cached.length) cached.length = data.length; + cached.nodes = nodes; + } + + function buildArrayKeys(data) { + var guid = 0; + forKeys(data, function () { + forEach(data, function (attrs) { + if ((attrs = attrs && attrs.attrs) && attrs.key == null) attrs.key = "__mithril__" + guid++; + }) + return 1; + }); + } + + function maybeRecreateObject(data, cached, dataAttrKeys) { + //if an element is different enough from the one in cache, recreate it + if (data.tag !== cached.tag || + dataAttrKeys.sort().join() !== Object.keys(cached.attrs).sort().join() || + data.attrs.id !== cached.attrs.id || + data.attrs.key !== cached.attrs.key || + (m.redraw.strategy() === "all" && (!cached.configContext || cached.configContext.retain !== true)) || + (m.redraw.strategy() === "diff" && cached.configContext && cached.configContext.retain === false)) { + if (cached.nodes.length) clear(cached.nodes); + if (cached.configContext && isFunction(cached.configContext.onunload)) cached.configContext.onunload(); + if (cached.controllers) { + forEach(cached.controllers, function (controller) { + if (controller.unload) controller.onunload({preventDefault: noop}); + }); + } + } + } + + function getObjectNamespace(data, namespace) { + return data.attrs.xmlns ? data.attrs.xmlns : + data.tag === "svg" ? "http://www.w3.org/2000/svg" : + data.tag === "math" ? "http://www.w3.org/1998/Math/MathML" : + namespace; + } + + function unloadCachedControllers(cached, views, controllers) { + if (controllers.length) { + cached.views = views; + cached.controllers = controllers; + forEach(controllers, function (controller) { + if (controller.onunload && controller.onunload.$old) controller.onunload = controller.onunload.$old; + if (pendingRequests && controller.onunload) { + var onunload = controller.onunload; + controller.onunload = noop; + controller.onunload.$old = onunload; + } + }); + } + } + + function scheduleConfigsToBeCalled(configs, data, node, isNew, cached) { + //schedule configs to be called. They are called after `build` + //finishes running + if (isFunction(data.attrs.config)) { + var context = cached.configContext = cached.configContext || {}; + + //bind + configs.push(function() { + return data.attrs.config.call(data, node, !isNew, context, cached); + }); + } + } + + function buildUpdatedNode(cached, data, editable, hasKeys, namespace, views, configs, controllers) { + var node = cached.nodes[0]; + if (hasKeys) setAttributes(node, data.tag, data.attrs, cached.attrs, namespace); + cached.children = build(node, data.tag, undefined, undefined, data.children, cached.children, false, 0, data.attrs.contenteditable ? node : editable, namespace, configs); + cached.nodes.intact = true; + + if (controllers.length) { + cached.views = views; + cached.controllers = controllers; + } + + return node; + } + + function handleNonexistentNodes(data, parentElement, index) { + var nodes; + if (data.$trusted) { + nodes = injectHTML(parentElement, index, data); + } + else { + nodes = [$document.createTextNode(data)]; + if (!parentElement.nodeName.match(voidElements)) insertNode(parentElement, nodes[0], index); + } + + var cached = typeof data === "string" || typeof data === "number" || typeof data === "boolean" ? new data.constructor(data) : data; + cached.nodes = nodes; + return cached; + } + + function reattachNodes(data, cached, parentElement, editable, index, parentTag) { + var nodes = cached.nodes; + if (!editable || editable !== $document.activeElement) { + if (data.$trusted) { + clear(nodes, cached) + nodes = injectHTML(parentElement, index, data) + } else if (parentTag === "textarea") { + //