diff --git a/bundler/bundle.js b/bundler/bundle.js index 4081de41..04d1b4b4 100644 --- a/bundler/bundle.js +++ b/bundler/bundle.js @@ -2,107 +2,125 @@ var fs = require("fs") var path = require("path") +var proc = require("child_process") -module.exports = function(input, output, options) { - function run(e, file) { +function read(filepath) { + try {return fs.readFileSync(filepath, "utf8")} catch (e) {throw new Error("File does not exist: " + filepath)} +} +function isFile(filepath) { + try {return fs.statSync(filepath).isFile()} catch (e) {return false} +} +function parse(file) { + var json = read(file) + try {return JSON.parse(json)} catch (e) {throw new Error("invalid JSON: " + json)} +} + +function run(input, output) { + try { var modules = {} - var usedVariables = {} - var globals = {} - - function resolve(dir, data) { - var replacements = [] + var bindings = {} + var declaration = /^\s*(?:var|let|const|function)[\t ]+([\w_$]+)/gm + var include = /(?:((?:var|let|const|,|)[\t ]*)([\w_$\.]+)(\s*=\s*))?require\(([^\)]+)\)(\s*[`\.\(\[])?/gm + var uuid = 0 + function process(filepath, data) { + data.replace(declaration, function(match, binding) {bindings[binding] = 0}) - var globalMatch = data.match(/window\.([\w_$]+)\s*=\s*/) - if (globalMatch) globals[globalMatch[1]] = true - - data = data.replace(/^\s*\/\/[^\n]*/g, "").replace(/((?:var|let|const|)[\t ]*)([\w_$\.]+)(\s*=\s*)require\(([^\)]+)\)/g, function(match, def, variable, eq, dep) { - usedVariables[variable] = usedVariables[variable] ? usedVariables[variable]++ : 1 - - var filename = new Function("return " + dep).call() + return data.replace(include, function(match, def, variable, eq, dep, rest) { + var filename = new Function("return " + dep).call(), pre = "" - //resolve npm dependencies - if (filename[0] !== ".") { - var meta - try {meta = JSON.parse(fs.readFileSync("./node_modules/" + filename + "/package.json"))} catch (e) {meta = {}} - var dependencyEntry = "./node_modules/" + filename + "/" + (meta.main || filename + ".js") - try {fs.statSync(dependencyEntry).isFile()} catch (e) {dependencyEntry = "./node_modules/" + filename + "/index.js"} - return process(dependencyEntry) - } - - //resolve local dependencies - return process(dir + "/" + filename + ".js") - - function process(dependency) { - var normalized = path.resolve(dir, filename) - if (modules[normalized] === undefined) { - modules[normalized] = variable - return resolve(path.dirname(dependency), exportCode(dependency, def, variable, eq)) - } - else { - if (modules[normalized] !== variable) { - replacements.push({variable: variable, replacement: modules[normalized]}) - } - return "" - } - } + def = def || "", variable = variable || "", eq = eq || "", rest = rest || "" + if (def[0] === ",") def = "\nvar ", pre = "\n" + var dependency = resolve(filepath, filename) + var code = process(dependency, pre + (modules[dependency] == null ? exportCode(filename, dependency, def, variable, eq, rest, uuid) : def + variable + eq + modules[dependency])) + modules[dependency] = rest ? "_" + uuid : variable + uuid++ + return code + rest }) - if (replacements.length > 0) { - for (var i = 0; i < replacements.length; i++) { - data = data.replace(new RegExp("\\b" + replacements[i].variable + "\\b", "g"), replacements[i].replacement) - } - } - return data - .replace(/(?:var|let|const)[\t ]([\w_$\.]+)(\s*=\s*)\1([\r\n;]+)/g, "$3") // remove assignments to itself - .replace(/([\r\n]){2,}/g, "$1") // remove multiple consecutive line breaks - .replace(/\}[\r\n]+\(/g, "}(") // remove space from iife - .replace(/(window\.){2}/g, "") // collapse window references - } - - function exportCode(file, def, variable, eq) { - var declared = {} - return fixCollisions(fs.readFileSync(file, "utf8")) - .replace(/("|')use strict\1;?/gm, "") // remove extraneous "use strict" - .replace(/module\.exports\s*=\s*/gm, def + variable + eq) - .replace(/module\.exports(\.|\[)/gm, function(match, token, length, code) { - if (new RegExp("\\b" + variable + "\\b").test(variable) && !declared[variable]) { - declared[variable] = true - return def + variable + eq + "{}\n" + variable + token - } - return variable + token - }) - } - - function fixCollisions(code) { - for (var variable in usedVariables) { - var collision = new RegExp("([^\\.])\\b" + variable + "\\b(?![\"'`])", "g") - var exported = new RegExp("module\\.exports\\s*=\\s*" + variable) - if (collision.test(code) && !exported.test(code) && !globals[variable.match(/[^\.]+/)]) { - var fixed = variable + usedVariables[variable]++ - code = code.replace(collision, "$1" + fixed) - } - } - return code - } - - function setVersion(code) { - var metadata = JSON.parse(fs.readFileSync(__dirname + "/../package.json")) - return code.replace("bleeding-edge", metadata.version) - } - - function bundle(input, output) { - console.log("bundling...") - var code = setVersion(resolve(path.dirname(input), fs.readFileSync(input, "utf8"))) - if (new Function(code)) fs.writeFileSync(output, "new function() {\n" + code + "\n}", "utf8") - console.log("done") } - if (file !== output && file !== output.replace(/\.js$/, ".min.js")) bundle(input, output) + function resolve(filepath, filename) { + if (filename[0] !== ".") { + // resolve as npm dependency + var packagePath = "./node_modules/" + filename + "/package.json" + var meta = isFile(packagePath) ? parse(packagePath) : {} + var main = "./node_modules/" + filename + "/" + (meta.main || filename + ".js") + return path.resolve(isFile(main) ? main : "./node_modules/" + filename + "/index.js") + } + else { + // resolve as local dependency + return path.resolve(path.dirname(filepath), filename + ".js") + } + } + + function exportCode(filename, filepath, def, variable, eq, rest, uuid) { + var code = read(filepath) + // if there's a syntax error, report w/ proper stack trace + try {new Function(code)} catch (e) { + proc.exec("node " + filename, function(error) { + if (error !== null) console.log("\x1b[31m" + error.message) + }) + } + + // disambiguate collisions + var ignored = {} + code.replace(include, function(match, def, variable, eq, dep, rest) { + var filename = new Function("return " + dep).call() + var binding = modules[resolve(filepath, filename)] + if (binding != null) ignored[binding] = true + }) + if (code.match(new RegExp("module\\.exports\\s*=\\s*" + variable + "\s*$", "m"))) ignored[variable] = true + for (var binding in bindings) { + if (!ignored[binding]) { + var before = code + code = code.replace(new RegExp("(\\b)" + binding + "\\b", "g"), binding + bindings[binding]) + if (before !== code) bindings[binding]++ + } + } + + // fix strings that got mangled by collision disambiguation + var string = /(["'])((?:\\\1|.)*?)(\1)/g + var candidates = Object.keys(bindings).map(function(binding) {return binding + (bindings[binding] - 1)}).join("|") + code = code.replace(string, function(match, open, data, close) { + var variables = new RegExp(Object.keys(bindings).map(function(binding) {return binding + (bindings[binding] - 1)}).join("|"), "g") + var fixed = data.replace(variables, function(match) { + return match.replace(/\d+$/, "") + }) + return open + fixed + close + }) + + //fix props + var props = new RegExp("(\\.\\s*)(" + candidates + ")|([\\{,]\\s*)(" + candidates + ")(\\s*:)", "gm") + code = code.replace(props, function(match, dot, a, pre, b, post) { + if (dot) return dot + a.replace(/\d+$/, "") + else return pre + b.replace(/\d+$/, "") + post + }) + + return code + .replace(/("|')use strict\1;?/gm, "") // remove extraneous "use strict" + .replace(/module\.exports\s*=\s*/gm, rest ? "var _" + uuid + eq : def + (rest ? "_" : "") + variable + eq) // export + + (rest ? "\n" + def + variable + eq + "_" + uuid : "") // if `rest` is truthy, it means the expression is fluent or higher-order (e.g. require(path).foo or require(path)(foo) + } + + var versionTag = "bleeding-edge" + var packageFile = __dirname + "/../package.json" + var code = process(path.resolve(input), read(input)) + .replace(/^\s*((?:var|let|const|)[\t ]*)([\w_$\.]+)(\s*=\s*)(\2)(?=[\s]+(\w)|;|$)/gm, "") // remove assignments to self + .replace(/;+(\r|\n|$)/g, ";$1") // remove redundant semicolons + .replace(/(\r|\n)+/g, "\n").replace(/(\r|\n)$/, "") // remove multiline breaks + .replace(versionTag, isFile(packageFile) ? parse(packageFile).version : versionTag) // set version + + fs.writeFileSync(output, "new function() {\n" + code + "\n}", "utf8") } - run() + catch (e) { + console.error(e.message) + } +} +module.exports = function(input, output, options) { + run(input, output) if (options && options.watch) { - fs.watch(process.cwd(), {recursive: true}, function(type, file) { - if (typeof file === "string" && path.resolve(output) !== path.resolve(file)) run() + fs.watch(process.cwd(), {recursive: true}, function(file, type) { + if (typeof file === "string" && path.resolve(output) !== path.resolve(file)) run(input, output) }) } } diff --git a/bundler/tests/test-bundler.js b/bundler/tests/test-bundler.js new file mode 100644 index 00000000..04a64b83 --- /dev/null +++ b/bundler/tests/test-bundler.js @@ -0,0 +1,333 @@ +var o = require("../../ospec/ospec") +var bundle = require("../bundle") + +var fs = require("fs") + +var ns = "bundler/tests/" +function read(filepath) { + try {return fs.readFileSync(ns + filepath, "utf8")} catch (e) {} +} +function write(filepath, data) { + try {var exists = fs.statSync(ns + filepath).isFile()} catch (e) {} + if (exists) throw new Error("Don't call `write('" + filepath + "')`. Cannot overwrite file") + fs.writeFileSync(ns + filepath, data, "utf8") +} +function remove(filepath) { + fs.unlinkSync(ns + filepath) +} + +o.spec("bundler", function() { + o("relative imports works", function() { + write("a.js", `var b = require("./b")`) + write("b.js", `module.exports = 1`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar b = 1\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("relative imports works with semicolons", function() { + write("a.js", `var b = require("./b");`) + write("b.js", `module.exports = 1;`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar b = 1;\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("relative imports works with let", function() { + write("a.js", `let b = require("./b")`) + write("b.js", `module.exports = 1`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nlet b = 1\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("relative imports works with const", function() { + write("a.js", 'const b = require("./b")') + write("b.js", `module.exports = 1`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nconst b = 1\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("relative imports works with assignment", function() { + write("a.js", `var a = {}\na.b = require("./b")`) + write("b.js", `module.exports = 1`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar a = {}\na.b = 1\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("relative imports works with reassignment", function() { + write("a.js", `var b = {}\nb = require("./b")`) + write("b.js", `module.exports = 1`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar b = {}\nb = 1\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("relative imports removes extra use strict", function() { + write("a.js", `"use strict"\nvar b = require("./b")`) + write("b.js", `"use strict"\nmodule.exports = 1`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\n"use strict"\nvar b = 1\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("relative imports removes extra use strict using single quotes", function() { + write("a.js", `'use strict'\nvar b = require("./b")`) + write("b.js", `'use strict'\nmodule.exports = 1`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\n'use strict'\nvar b = 1\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("relative imports removes extra use strict using mixed quotes", function() { + write("a.js", `"use strict"\nvar b = require("./b")`) + write("b.js", `'use strict'\nmodule.exports = 1`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\n"use strict"\nvar b = 1\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("works w/ window", function() { + write("a.js", `window.a = 1\nvar b = require("./b")`) + write("b.js", `module.exports = function() {return a}`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nwindow.a = 1\nvar b = function() {return a}\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("works without assignment", function() { + write("a.js", `require("./b")`) + write("b.js", `1 + 1`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\n1 + 1\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("works if used fluently", function() { + write("a.js", `var b = require("./b").toString()`) + write("b.js", `module.exports = []`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar _0 = []\nvar b = _0.toString()\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("works if used fluently w/ multiline", function() { + write("a.js", `var b = require("./b")\n\t.toString()`) + write("b.js", `module.exports = []`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar _0 = []\nvar b = _0\n\t.toString()\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("works if used w/ curry", function() { + write("a.js", `var b = require("./b")()`) + write("b.js", `module.exports = function() {}`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar _0 = function() {}\nvar b = _0()\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("works if used w/ curry w/ multiline", function() { + write("a.js", `var b = require("./b")\n()`) + write("b.js", `module.exports = function() {}`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar _0 = function() {}\nvar b = _0\n()\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("works if used fluently in one place and not in another", function() { + write("a.js", `var b = require("./b").toString()\nvar c = require("./c")`) + write("b.js", `module.exports = []`) + write("c.js", `var b = require("./b")\nmodule.exports = function() {return b}`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar _0 = []\nvar b = _0.toString()\nvar b0 = _0\nvar c = function() {return b0}\n}`) + + remove("a.js") + remove("b.js") + remove("c.js") + remove("out.js") + }) + o("works if used in sequence", function() { + write("a.js", `var b = require("./b"), c = require("./c")`) + write("b.js", `module.exports = 1`) + write("c.js", `var x\nmodule.exports = 2`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar b = 1\nvar x\nvar c = 2\n}`) + + remove("a.js") + remove("b.js") + remove("c.js") + remove("out.js") + }) + o("works if collision", function() { + write("a.js", `var b = require("./b")`) + write("b.js", `var b = 1\nmodule.exports = 2`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar b0 = 1\nvar b = 2\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("works if multiple aliases", function() { + write("a.js", `var b = require("./b")\n`) + write("b.js", `var b = require("./c")\nb.x = 1\nmodule.exports = b`) + write("c.js", `var b = {}\nmodule.exports = b`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar b = {}\nb.x = 1\n}`) + + remove("a.js") + remove("b.js") + remove("c.js") + remove("out.js") + }) + o("works if multiple collision", function() { + write("a.js", `var b = require("./b")\nvar c = require("./c")\nvar d = require("./d")`) + write("b.js", `var a = 1\nmodule.exports = a`) + write("c.js", `var a = 2\nmodule.exports = a`) + write("d.js", `var a = 3\nmodule.exports = a`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar a = 1\nvar b = a\nvar a0 = 2\nvar c = a0\nvar a1 = 3\nvar d = a1\n}`) + + remove("a.js") + remove("b.js") + remove("c.js") + remove("d.js") + remove("out.js") + }) + o("reuses binding if possible", function() { + write("a.js", `var b = require("./b")\nvar c = require("./c")`) + write("b.js", `var d = require("./d")\nmodule.exports = function() {return d + 1}`) + write("c.js", `var d = require("./d")\nmodule.exports = function() {return d + 2}`) + write("d.js", `module.exports = 1`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar d = 1\nvar b = function() {return d + 1}\nvar c = function() {return d + 2}\n}`) + + remove("a.js") + remove("b.js") + remove("c.js") + remove("d.js") + remove("out.js") + }) + o("disambiguates conflicts if imported collides with itself", function() { + write("a.js", `var b = require("./b")`) + write("b.js", `var b = 1\nmodule.exports = function() {return b}`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar b0 = 1\nvar b = function() {return b0}\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("disambiguates conflicts if imported collides with something else", function() { + write("a.js", `var a = 1\nvar b = require("./b")`) + write("b.js", `var a = 2\nmodule.exports = function() {return a}`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar a = 1\nvar a0 = 2\nvar b = function() {return a0}\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("disambiguates conflicts if imported collides with function declaration", function() { + write("a.js", `function a() {}\nvar b = require("./b")`) + write("b.js", `var a = 2\nmodule.exports = function() {return a}`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nfunction a() {}\nvar a0 = 2\nvar b = function() {return a0}\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("disambiguates conflicts if imported collides with another module's private", function() { + write("a.js", `var b = require("./b")\nvar c = require("./c")`) + write("b.js", `var a = 1\nmodule.exports = function() {return a}`) + write("c.js", `var a = 2\nmodule.exports = function() {return a}`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar a = 1\nvar b = function() {return a}\nvar a0 = 2\nvar c = function() {return a0}\n}`) + + remove("a.js") + remove("b.js") + remove("c.js") + remove("out.js") + }) + o("does not mess up strings", function() { + write("a.js", `var b = require("./b")`) + write("b.js", `var b = "b b b \\\" b"\nmodule.exports = function() {return b}`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar b0 = "b b b \\\" b"\nvar b = function() {return b0}\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) + o("does not mess up properties", function() { + write("a.js", `var b = require("./b")`) + write("b.js", `var b = {b: 1}\nmodule.exports = function() {return b.b}`) + bundle(ns + "a.js", ns + "out.js") + + o(read("out.js")).equals(`new function() {\nvar b0 = {b: 1}\nvar b = function() {return b0.b}\n}`) + + remove("a.js") + remove("b.js") + remove("out.js") + }) +}) \ No newline at end of file diff --git a/examples/dbmonster/mithril/index.html b/examples/dbmonster/mithril/index.html index f65c2fbf..7ccb5f22 100644 --- a/examples/dbmonster/mithril/index.html +++ b/examples/dbmonster/mithril/index.html @@ -10,8 +10,6 @@
- - diff --git a/hyperscript.js b/hyperscript.js index 48f06c9e..880a1594 100644 --- a/hyperscript.js +++ b/hyperscript.js @@ -1,6 +1,6 @@ var hyperscript = require("./render/hyperscript") + hyperscript.trust = require("./render/trust") hyperscript.fragment = require("./render/fragment") - module.exports = hyperscript diff --git a/index.js b/index.js index 6eb607f3..0d259df8 100644 --- a/index.js +++ b/index.js @@ -1,25 +1,21 @@ "use strict" var m = require("./hyperscript") -var renderService = require("./render") var requestService = require("./request") var redrawService = require("./redraw") -var parseQueryString = require("./querystring/parse") -var buildQueryString = require("./querystring/build") -var Stream = require("./stream") requestService.setCompletionCallback(redrawService.publish) m.mount = require("./mount") m.route = require("./route") m.withAttr = require("./util/withAttr") -m.prop = Stream -m.render = renderService.render +m.prop = require("./stream") +m.render = require("./render").render m.redraw = redrawService.publish m.request = requestService.request m.jsonp = requestService.jsonp -m.parseQueryString = parseQueryString -m.buildQueryString = buildQueryString +m.parseQueryString = require("./querystring/parse") +m.buildQueryString = require("./querystring/build") m.version = "bleeding-edge" module.exports = m diff --git a/mithril.js b/mithril.js index 2ade76ef..546bec54 100644 --- a/mithril.js +++ b/mithril.js @@ -1,7 +1,7 @@ new function() { -function Vnode(tag, key, attrs, children, text, dom) { - return {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: {}, events: undefined, instance: undefined, skip: false} +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 (node instanceof Array) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined) @@ -75,519 +75,11 @@ function hyperscript(selector) { hyperscript.trust = function(html) { return Vnode("<", undefined, undefined, html, undefined, undefined) } -hyperscript.fragment = function(attrs, children) { - return Vnode("[", attrs.key, attrs, Vnode.normalizeChildren(children), undefined, undefined) +hyperscript.fragment = function(attrs1, children) { + return Vnode("[", attrs1.key, attrs1, Vnode.normalizeChildren(children), undefined, undefined) } var m = hyperscript -var renderService = 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 match = 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"}[match[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 attrs = vnode.attrs - var is = attrs && attrs.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 (attrs != null) { - setAttrs(vnode, attrs, ns) - } - 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) { - // For object literals since `Vnode()` always sets the `state` field. - if (!vnode.state) vnode.state = {} - assign(vnode.state, vnode.tag) - initLifecycle(vnode.tag, vnode, hooks) - vnode.instance = Vnode.normalize(vnode.tag.view.call(vnode.state, vnode)) - 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(parent, old, 0, old.length, vnodes) - else { - var recycling = isRecyclable(old, vnodes) - if (recycling) old = old.concat(old.pool) - if (old.length === vnodes.length && vnodes[0] != null && vnodes[0].key == null) { - for (var i = 0; i < old.length; i++) { - if (old[i] === vnodes[i] || old[i] == null && vnodes[i] == null) continue - else if (old[i] == null) insertNode(parent, createNode(vnodes[i], hooks, ns), getNextSibling(old, i + 1, nextSibling)) - else if (vnodes[i] == null) removeNodes(parent, old, i, i + 1, vnodes) - else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), recycling, ns) - if (recycling && old[i].tag === vnodes[i].tag) insertNode(parent, toFragment(old[i]), getNextSibling(old, i + 1, nextSibling)) - } - } - else { - 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) oldStart++, start++ - else if (o != null && v != null && 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) oldEnd--, start++ - else if (o != null && v != null && o.key === v.key) { - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns) - if (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) oldEnd--, end-- - else if (o != null && v != null && 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(parent, 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(parent, old, null) - insertNode(parent, createNode(vnode, hooks, undefined), 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 handle multiple children - } - updateAttrs(vnode, old.attrs, vnode.attrs, ns) - 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(parent, 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 key = vnode.key - if (key != null) map[key] = i - } - } - return map - } - function toFragment(vnode) { - var count = vnode.domSize - if (count != null || vnode.dom == null) { - var fragment = $doc.createDocumentFragment() - if (count > 0) { - var dom = vnode.dom - while (--count) 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) - } - //remove - function removeNodes(parent, 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(parent, vnode, context) - } - } - } - function once(f) { - var called = false - return function() { - if (!called) { - called = true - f() - } - } - } - function removeNode(parent, vnode, context) { - var expected = 1, called = 0 - if (vnode.attrs && vnode.attrs.onbeforeremove) { - expected++ - vnode.attrs.onbeforeremove.call(vnode.state, vnode, once(continuation)) - } - if (typeof vnode.tag !== "string" && vnode.tag.onbeforeremove) { - expected++ - vnode.tag.onbeforeremove.call(vnode.state, vnode, once(continuation)) - } - continuation() - function continuation() { - if (++called === expected) { - onremove(vnode) - if (vnode.dom) { - var count = vnode.domSize || 1 - if (count > 1) { - var dom = vnode.dom - while (--count) { - parent.removeChild(dom.nextSibling) - } - } - if (vnode.dom.parentNode != null) parent.removeChild(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 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 (children instanceof Array) { - for (var i = 0; i < children.length; i++) { - var child = children[i] - if (child != null) onremove(child) - } - } - } - } - //attrs - function setAttrs(vnode, attrs, ns) { - for (var key in attrs) { - setAttr(vnode, key, null, attrs[key], ns) - } - } - function setAttr(vnode, key, old, value, ns) { - var element = vnode.dom - if (key === "key" || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || typeof value === "undefined" || isLifecycleMethod(key)) return - var nsLastIndex = key.indexOf(":") - if (nsLastIndex > -1 && key.substr(0, nsLastIndex) === "xlink") { - element.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(nsLastIndex + 1), value) - } - else if (key[0] === "o" && key[1] === "n" && typeof value === "function") updateEvent(vnode, key, value) - else if (key === "style") updateStyle(element, old, value) - else if (key in element && !isAttribute(key) && ns === undefined) { - //setting input[value] to same value by typing on focused element moves cursor to end in Chrome - if (vnode.tag === "input" && key === "value" && vnode.dom.value === value && vnode.dom === $doc.activeElement) return - element[key] = value - } - else { - if (typeof value === "boolean") { - if (value) element.setAttribute(key, "") - else element.removeAttribute(key) - } - else element.setAttribute(key === "className" ? "class" : key, value) - } - } - function setLateAttrs(vnode) { - var attrs = vnode.attrs - if (vnode.tag === "select" && attrs != null) { - if ("value" in attrs) setAttr(vnode, "value", null, attrs.value, undefined) - if ("selectedIndex" in attrs) setAttr(vnode, "selectedIndex", null, attrs.selectedIndex, undefined) - } - } - function updateAttrs(vnode, old, attrs, ns) { - if (attrs != null) { - for (var key in attrs) { - setAttr(vnode, key, old && old[key], attrs[key], ns) - } - } - if (old != null) { - for (var key in old) { - if (attrs == null || !(key in attrs)) { - if (key === "className") key = "class" - if (key[0] === "o" && key[1] === "n" && !isLifecycleMethod(key)) updateEvent(vnode, key, undefined) - else if (key !== "key") vnode.dom.removeAttribute(key) - } - } - } - } - 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 === "type" || attr === "width" || attr === "height" - } - 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 key in style) { - element.style[key] = style[key] - } - if (old != null && typeof old !== "string") { - for (var key in old) { - if (!(key in style)) element.style[key] = "" - } - } - } - } - //event - function updateEvent(vnode, key, value) { - var element = vnode.dom - var callback = function(e) { - var result = value.call(element, e) - if (typeof onevent === "function") onevent.call(element, e) - return result - } - if (key in element) element[key] = callback - else { - var eventName = key.slice(2) - if (vnode.events === undefined) vnode.events = {} - if (vnode.events[key] != null) element.removeEventListener(eventName, vnode.events[key], false) - if (typeof value === "function") { - vnode.events[key] = callback - element.addEventListener(eventName, vnode.events[key], 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 assign(target, source) { - Object.keys(source).forEach(function(k){target[k] = source[k]}) - } - 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 time rendering into a node clears it out - if (dom.vnodes == null) dom.textContent = "" - if (!(vnodes instanceof Array)) 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} -}(window) -var StreamFactory = function(log) { +var _7 = function(log) { var guid = 0, noop = function() {}, HALT = {} function createStream() { function stream() { @@ -777,40 +269,41 @@ var StreamFactory = function(log) { createStream.HALT = HALT return createStream } -var Stream = StreamFactory(console.log.bind(console)) +var Stream = _7(console.log.bind(console)) var buildQueryString = function(object) { if (Object.prototype.toString.call(object) !== "[object Object]") return "" var args = [] - for (var key in object) { - destructure(key, object[key]) + for (var key0 in object) { + destructure(key0, object[key0]) } return args.join("&") - function destructure(key, value) { - if (value instanceof Array) { - for (var i = 0; i < value.length; i++) { - destructure(key + "[" + i + "]", value[i]) + function destructure(key0, value1) { + if (value1 instanceof Array) { + for (var i = 0; i < value1.length; i++) { + destructure(key0 + "[" + i + "]", value1[i]) } } - else if (Object.prototype.toString.call(value) === "[object Object]") { - for (var i in value) { - destructure(key + "[" + i + "]", value[i]) + else if (Object.prototype.toString.call(value1) === "[object Object]") { + for (var i in value1) { + destructure(key0 + "[" + i + "]", value1[i]) } } - else args.push(encodeURIComponent(key) + (value != null && value !== "" ? "=" + encodeURIComponent(value) : "")) + else args.push(encodeURIComponent(key0) + (value1 != null && value1 !== "" ? "=" + encodeURIComponent(value1) : "")) } } -var requestService = function($window, Stream1) { +var StreamFactory = _7 +var _9 = function($window, Stream0) { var callbackCount = 0 var oncompletion function setCompletionCallback(callback) {oncompletion = callback} function request(args) { - var stream = Stream1() - if (args.initialValue !== undefined) stream(args.initialValue) + var stream0 = Stream0() + if (args.initialValue !== undefined) stream0(args.initialValue) 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.serialize !== "function") args.serialize = typeof FormData !== "undefined" && args.data instanceof FormData ? function(value0) {return value0} : JSON.stringify if (typeof args.deserialize !== "function") args.deserialize = deserialize if (typeof args.extract !== "function") args.extract = extract @@ -835,16 +328,16 @@ var requestService = function($window, Stream1) { 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) { - stream(cast(args.type, response)) + stream0(cast(args.type, response)) } else { var error = new Error(xhr.responseText) for (var key in response) error[key] = response[key] - stream.error(error) + stream0.error(error) } } catch (e) { - stream.error(e) + stream0.error(e) } if (typeof oncompletion === "function") oncompletion() } @@ -853,23 +346,23 @@ var requestService = function($window, Stream1) { if (useBody) xhr.send(args.data) else xhr.send() - return stream + return stream0 } function jsonp(args) { - var stream = Stream1() - if (args.initialValue !== undefined) stream(args.initialValue) + var stream0 = Stream0() + if (args.initialValue !== undefined) stream0(args.initialValue) 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) - stream(cast(args.type, data)) + stream0(cast(args.type, data)) if (typeof oncompletion === "function") oncompletion() delete $window[callbackName] } script.onerror = function() { script.parentNode.removeChild(script) - stream.error(new Error("JSONP request failed")) + stream0.error(new Error("JSONP request failed")) if (typeof oncompletion === "function") oncompletion() delete $window[callbackName] } @@ -878,7 +371,7 @@ var requestService = function($window, Stream1) { args.data[args.callbackKey || "callback"] = callbackName script.src = assemble(args.url, args.data) $window.document.documentElement.appendChild(script) - return stream + return stream0 } function interpolate(url, data) { if (data == null) return url @@ -906,25 +399,26 @@ var requestService = function($window, Stream1) { } function extract(xhr) {return xhr.responseText} - function cast(type, data) { - if (typeof type === "function") { + function cast(type0, data) { + if (typeof type0 === "function") { if (data instanceof Array) { for (var i = 0; i < data.length; i++) { - data[i] = new type(data[i]) + data[i] = new type0(data[i]) } } - else return new type(data) + else return new type0(data) } return data } return {request: request, jsonp: jsonp, setCompletionCallback: setCompletionCallback} -}(window, Stream) -var redrawService = function() { +} +var requestService = _9(window, Stream) +var _13 = function() { var callbacks = [] function unsubscribe(callback) { - var index = callbacks.indexOf(callback) - if (index > -1) callbacks.splice(index, 1) + var index0 = callbacks.indexOf(callback) + if (index0 > -1) callbacks.splice(index0, 1) } function publish() { for (var i = 0; i < callbacks.length; i++) { @@ -932,46 +426,519 @@ var redrawService = function() { } } return {subscribe: callbacks.push.bind(callbacks), unsubscribe: unsubscribe, publish: publish} -}() -var parseQueryString = function(string) { - if (string === "" || string == null) return {} - if (string.charAt(0) === "?") string = string.slice(1) - var entries = string.split("&"), data = {}, counters = {} - for (var i = 0; i < entries.length; i++) { - var entry = entries[i].split("=") - var key = decodeURIComponent(entry[0]) - var value = entry.length === 2 ? decodeURIComponent(entry[1]) : "" - //TODO refactor out - var number = Number(value) - if (value !== "" && !isNaN(number) || value === "NaN") value = number - else if (value === "true") value = true - else if (value === "false") value = false - else if (value.charAt(0) !== "/") { - var date = new Date(value) - if (!isNaN(date.getTime())) value = date - } - var levels = key.split(/\]\[?|\[/) - var cursor = data - if (key.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 key = levels.slice(0, j).join() - if (counters[key] == null) counters[key] = 0 - level = counters[key]++ +} +var redrawService = _13() +requestService.setCompletionCallback(redrawService.publish) +var _15 = function($window) { + var $doc = $window.document + var $emptyFragment = $doc.createDocumentFragment() + var onevent + function setEventCallback(callback) {return onevent = callback} + //create + function createNodes(parent0, vnodes, start, end, hooks, nextSibling, ns) { + for (var i = start; i < end; i++) { + var vnode = vnodes[i] + if (vnode != null) { + insertNode(parent0, createNode(vnode, hooks, ns), nextSibling) } - if (cursor[level] == null) { - cursor[level] = isValue ? value : isNumber ? [] : {} - } - cursor = cursor[level] } } - return data + 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 parent0 = {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(parent0) + 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.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) { + // For object literals since `Vnode()` always sets the `state0` field. + if (!vnode.state) vnode.state = {} + assign(vnode.state, vnode.tag) + initLifecycle(vnode.tag, vnode, hooks) + vnode.instance = Vnode.normalize(vnode.tag.view.call(vnode.state, vnode)) + 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 + } + } + //update0 + function updateNodes(parent0, old, vnodes, hooks, nextSibling, ns) { + if (old === vnodes || old == null && vnodes == null) return + else if (old == null) createNodes(parent0, vnodes, 0, vnodes.length, hooks, nextSibling, undefined) + else if (vnodes == null) removeNodes(parent0, old, 0, old.length, vnodes) + else { + var recycling = isRecyclable(old, vnodes) + if (recycling) old = old.concat(old.pool) + if (old.length === vnodes.length && vnodes[0] != null && vnodes[0].key == null) { + for (var i = 0; i < old.length; i++) { + if (old[i] === vnodes[i] || old[i] == null && vnodes[i] == null) continue + else if (old[i] == null) insertNode(parent0, createNode(vnodes[i], hooks, ns), getNextSibling(old, i + 1, nextSibling)) + else if (vnodes[i] == null) removeNodes(parent0, old, i, i + 1, vnodes) + else updateNode(parent0, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), recycling, ns) + if (recycling && old[i].tag === vnodes[i].tag) insertNode(parent0, toFragment(old[i]), getNextSibling(old, i + 1, nextSibling)) + } + } + else { + var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map0 + while (oldEnd >= oldStart && end >= start) { + var o = old[oldStart], v = vnodes[start] + if (o === v) oldStart++, start++ + else if (o != null && v != null && o.key === v.key) { + oldStart++, start++ + updateNode(parent0, o, v, hooks, getNextSibling(old, oldStart, nextSibling), recycling, ns) + if (recycling && o.tag === v.tag) insertNode(parent0, toFragment(o), nextSibling) + } + else { + var o = old[oldEnd] + if (o === v) oldEnd--, start++ + else if (o != null && v != null && o.key === v.key) { + updateNode(parent0, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns) + if (start < end) insertNode(parent0, 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) oldEnd--, end-- + else if (o != null && v != null && o.key === v.key) { + updateNode(parent0, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns) + if (recycling && o.tag === v.tag) insertNode(parent0, toFragment(o), nextSibling) + if (o.dom != null) nextSibling = o.dom + oldEnd--, end-- + } + else { + if (!map0) map0 = getKeyMap(old, oldEnd) + if (v != null) { + var oldIndex = map0[v.key] + if (oldIndex != null) { + var movable = old[oldIndex] + updateNode(parent0, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns) + insertNode(parent0, toFragment(movable), nextSibling) + old[oldIndex].skip = true + if (movable.dom != null) nextSibling = movable.dom + } + else { + var dom = createNode(v, hooks, undefined) + insertNode(parent0, dom, nextSibling) + nextSibling = dom + } + } + end-- + } + if (end < start) break + } + createNodes(parent0, vnodes, start, end + 1, hooks, nextSibling, ns) + removeNodes(parent0, old, oldStart, oldEnd + 1, vnodes) + } + } + } + function updateNode(parent0, 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(parent0, old, vnode, nextSibling); break + case "[": updateFragment(parent0, old, vnode, hooks, nextSibling, ns); break + default: updateElement(old, vnode, hooks, ns) + } + } + else updateComponent(parent0, old, vnode, hooks, nextSibling, recycling, ns) + } + else { + removeNode(parent0, old, null) + insertNode(parent0, createNode(vnode, hooks, undefined), nextSibling) + } + } + function updateText(old, vnode) { + if (old.children.toString() !== vnode.children.toString()) { + old.dom.nodeValue = vnode.children + } + vnode.dom = old.dom + } + function updateHTML(parent0, old, vnode, nextSibling) { + if (old.children !== vnode.children) { + toFragment(old) + insertNode(parent0, createHTML(vnode), nextSibling) + } + else vnode.dom = old.dom, vnode.domSize = old.domSize + } + function updateFragment(parent0, old, vnode, hooks, nextSibling, ns) { + updateNodes(parent0, 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 handle multiple children + } + updateAttrs(vnode, old.attrs, vnode.attrs, ns) + 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(parent0, 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(parent0, createNode(vnode.instance, hooks, ns), nextSibling) + else updateNode(parent0, old.instance, vnode.instance, hooks, nextSibling, recycling, ns) + vnode.dom = vnode.instance.dom + vnode.domSize = vnode.instance.domSize + } + else if (old.instance != null) { + removeNode(parent0, 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 map0 = {}, i = 0 + for (var i = 0; i < end; i++) { + var vnode = vnodes[i] + if (vnode != null) { + var key1 = vnode.key + if (key1 != null) map0[key1] = i + } + } + return map0 + } + function toFragment(vnode) { + var count = vnode.domSize + if (count != null || vnode.dom == null) { + var fragment = $doc.createDocumentFragment() + if (count > 0) { + var dom = vnode.dom + while (--count) 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(parent0, dom, nextSibling) { + if (nextSibling && nextSibling.parentNode) parent0.insertBefore(dom, nextSibling) + else parent0.appendChild(dom) + } + //remove + function removeNodes(parent0, 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(parent0, vnode, context) + } + } + } + function once(f) { + var called = false + return function() { + if (!called) { + called = true + f() + } + } + } + function removeNode(parent0, vnode, context) { + var expected = 1, called = 0 + if (vnode.attrs && vnode.attrs.onbeforeremove) { + expected++ + vnode.attrs.onbeforeremove.call(vnode.state, vnode, once(continuation)) + } + if (typeof vnode.tag !== "string" && vnode.tag.onbeforeremove) { + expected++ + vnode.tag.onbeforeremove.call(vnode.state, vnode, once(continuation)) + } + continuation() + function continuation() { + if (++called === expected) { + onremove(vnode) + if (vnode.dom) { + var count = vnode.domSize || 1 + if (count > 1) { + var dom = vnode.dom + while (--count) { + parent0.removeChild(dom.nextSibling) + } + } + if (vnode.dom.parentNode != null) parent0.removeChild(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 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 (children instanceof Array) { + 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 key1 in attrs2) { + setAttr(vnode, key1, null, attrs2[key1], ns) + } + } + function setAttr(vnode, key1, old, value2, ns) { + var element = vnode.dom + if (key1 === "key" || (old === value2 && !isFormAttribute(vnode, key1)) && typeof value2 !== "object" || typeof value2 === "undefined" || isLifecycleMethod(key1)) return + var nsLastIndex = key1.indexOf(":") + if (nsLastIndex > -1 && key1.substr(0, nsLastIndex) === "xlink") { + element.setAttributeNS("http://www.w3.org/1999/xlink", key1.slice(nsLastIndex + 1), value2) + } + else if (key1[0] === "o" && key1[1] === "n" && typeof value2 === "function") updateEvent(vnode, key1, value2) + else if (key1 === "style") updateStyle(element, old, value2) + else if (key1 in element && !isAttribute(key1) && ns === undefined) { + //setting input[value2] to same value2 by typing on focused element moves cursor to end in Chrome + if (vnode.tag === "input" && key1 === "value" && vnode.dom.value === value2 && vnode.dom === $doc.activeElement) return + element[key1] = value2 + } + else { + if (typeof value2 === "boolean") { + if (value2) element.setAttribute(key1, "") + else element.removeAttribute(key1) + } + else element.setAttribute(key1 === "className" ? "class" : key1, value2) + } + } + 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 key1 in attrs2) { + setAttr(vnode, key1, old && old[key1], attrs2[key1], ns) + } + } + if (old != null) { + for (var key1 in old) { + if (attrs2 == null || !(key1 in attrs2)) { + if (key1 === "className") key1 = "class" + if (key1[0] === "o" && key1[1] === "n" && !isLifecycleMethod(key1)) updateEvent(vnode, key1, undefined) + else if (key1 !== "key") vnode.dom.removeAttribute(key1) + } + } + } + } + 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 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 key1 in style) { + element.style[key1] = style[key1] + } + if (old != null && typeof old !== "string") { + for (var key1 in old) { + if (!(key1 in style)) element.style[key1] = "" + } + } + } + } + //event + function updateEvent(vnode, key1, value2) { + var element = vnode.dom + var callback = function(e) { + var result = value2.call(element, e) + if (typeof onevent === "function") onevent.call(element, e) + return result + } + if (key1 in element) element[key1] = callback + else { + var eventName = key1.slice(2) + if (vnode.events === undefined) vnode.events = {} + if (vnode.events[key1] != null) element.removeEventListener(eventName, vnode.events[key1], false) + if (typeof value2 === "function") { + vnode.events[key1] = callback + element.addEventListener(eventName, vnode.events[key1], 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 assign(target, source) { + Object.keys(source).forEach(function(k){target[k] = source[k]}) + } + 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 active0 = $doc.activeElement + // First time rendering into a node clears it out + if (dom.vnodes == null) dom.textContent = "" + if (!(vnodes instanceof Array)) 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 !== active0) active0.focus() + } + return {render: render, setEventCallback: setEventCallback} } -requestService.setCompletionCallback(redrawService.publish) -var throttle = function(callback) { +var renderService = _15(window) +var throttle = function(callback1) { //60fps translates to 16.6ms, round it down since setTimeout requires int var time = 16 var last = 0, pending = null @@ -980,19 +947,19 @@ var throttle = function(callback) { var now = Date.now() if (synchronous === true || last === 0 || now - last >= time) { last = now - callback() + callback1() } else if (pending === null) { pending = timeout(function() { pending = null - callback() + callback1() last = Date.now() }, time - (now - last)) } } } -var autoredraw = function(root, renderer, pubsub, callback) { - var run = throttle(callback) +var autoredraw = function(root, renderer, pubsub, callback0) { + var run1 = throttle(callback0) if (renderer != null) { renderer.setEventCallback(function(e) { if (e.redraw !== false) pubsub.publish() @@ -1000,11 +967,11 @@ var autoredraw = function(root, renderer, pubsub, callback) { } if (pubsub != null) { if (root.redraw) pubsub.unsubscribe(root.redraw) - pubsub.subscribe(run) + pubsub.subscribe(run1) } - return root.redraw = run + return root.redraw = run1 } -m.mount = function(renderer, pubsub) { +var _19 = function(renderer, pubsub) { return function(root, component) { if (component === null) { renderer.render(root, []) @@ -1012,23 +979,62 @@ m.mount = function(renderer, pubsub) { delete root.redraw return } - var run = autoredraw(root, renderer, pubsub, function() { + var run0 = autoredraw(root, renderer, pubsub, function() { renderer.render( root, Vnode(component, undefined, undefined, undefined, undefined, undefined) ) }) - run() + run0() } -}(renderService, redrawService) +} +m.mount = _19(renderService, redrawService) +var mount = m.mount +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 key3 = decodeURIComponent(entry[0]) + var value4 = entry.length === 2 ? decodeURIComponent(entry[1]) : "" + //TODO refactor out + var number = Number(value4) + if (value4 !== "" && !isNaN(number) || value4 === "NaN") value4 = number + else if (value4 === "true") value4 = true + else if (value4 === "false") value4 = false + else if (value4.charAt(0) !== "/") { + var date = new Date(value4) + if (!isNaN(date.getTime())) value4 = date + } + var levels = key3.split(/\]\[?|\[/) + var cursor = data0 + if (key3.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 key3 = levels.slice(0, j).join() + if (counters[key3] == null) counters[key3] = 0 + level = counters[key3]++ + } + if (cursor[level] == null) { + cursor[level] = isValue ? value4 : isNumber ? [] : {} + } + cursor = cursor[level] + } + } + return data0 +} var coreRouter = function($window) { var supportsPushState = typeof $window.history.pushState === "function" var callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout - var prefix = "#!" - function setPrefix(value) {prefix = value} - function normalize(fragment) { - var data = $window.location[fragment].replace(/(?:%[a-f89][a-f0-9])+/gim, decodeURIComponent) - if (fragment === "pathname" && data[0] !== "/") data = "/" + data + var prefix1 = "#!" + function setPrefix(value3) {prefix1 = value3} + function normalize(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 @@ -1048,28 +1054,28 @@ var coreRouter = function($window) { if (queryIndex > -1) { var queryEnd = hashIndex > -1 ? hashIndex : path.length var queryParams = parseQueryString(path.slice(queryIndex + 1, queryEnd)) - for (var key in queryParams) queryData[key] = queryParams[key] + for (var key2 in queryParams) queryData[key2] = queryParams[key2] } if (hashIndex > -1) { var hashParams = parseQueryString(path.slice(hashIndex + 1)) - for (var key in hashParams) hashData[key] = hashParams[key] + for (var key2 in hashParams) hashData[key2] = hashParams[key2] } return path.slice(0, pathEnd) } function getPath() { - var type = prefix.charAt(0) - switch (type) { - case "#": return normalize("hash").slice(prefix.length) - case "?": return normalize("search").slice(prefix.length) + normalize("hash") - default: return normalize("pathname").slice(prefix.length) + normalize("search") + normalize("hash") + var type2 = prefix1.charAt(0) + switch (type2) { + case "#": return normalize("hash").slice(prefix1.length) + case "?": return normalize("search").slice(prefix1.length) + normalize("hash") + default: return normalize("pathname").slice(prefix1.length) + normalize("search") + normalize("hash") } } function setPath(path, data, options) { var queryData = {}, hashData = {} path = parsePath(path, queryData, hashData) if (data != null) { - for (var key in data) queryData[key] = data[key] - path = path.replace(/:([^\/]+)/g, function(match, token) { + for (var key2 in data) queryData[key2] = data[key2] + path = path.replace(/:([^\/]+)/g, function(match2, token) { delete queryData[token] return data[token] }) @@ -1079,15 +1085,15 @@ var coreRouter = function($window) { var hash = buildQueryString(hashData) if (hash) path += "#" + hash if (supportsPushState) { - if (options && options.replace) $window.history.replaceState(null, null, prefix + path) - else $window.history.pushState(null, null, prefix + path) + if (options && options.replace) $window.history.replaceState(null, null, prefix1 + path) + else $window.history.pushState(null, null, prefix1 + path) $window.onpopstate() } - else $window.location.href = prefix + path + else $window.location.href = prefix1 + path } - function defineRoutes(routes, resolve, reject) { + function defineRoutes(routes, resolve1, reject0) { if (supportsPushState) $window.onpopstate = debounceAsync(resolveRoute) - else if (prefix.charAt(0) === "#") $window.onhashchange = resolveRoute + else if (prefix1.charAt(0) === "#") $window.onhashchange = resolveRoute resolveRoute() function resolveRoute() { @@ -1095,69 +1101,69 @@ var coreRouter = function($window) { var params = {} var pathname = parsePath(path, params, params) - for (var route in routes) { - var matcher = new RegExp("^" + route.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$") + 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 = route.match(/:[^\/]+/g) || [] + 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[route], params, path, route) + resolve1(routes[route0], params, path, route0) }) return } } - reject(path, params) + reject0(path, params) } return resolveRoute } - function link(vnode) { - vnode.dom.setAttribute("href", prefix + vnode.attrs.href) - vnode.dom.onclick = function(e) { + function link(vnode2) { + vnode2.dom.setAttribute("href", prefix1 + vnode2.attrs.href) + vnode2.dom.onclick = function(e) { e.preventDefault() e.redraw = false - setPath(vnode.attrs.href, undefined, undefined) + setPath(vnode2.attrs.href, undefined, undefined) } } return {setPrefix: setPrefix, getPath: getPath, setPath: setPath, defineRoutes: defineRoutes, link: link} } -m.route = function($window, mount1) { +var _25 = function($window, mount0) { var router = coreRouter($window) var currentResolve, currentComponent, currentRender, currentArgs, currentPath var RouteComponent = {view: function() { return currentRender(Vnode(currentComponent, null, currentArgs, undefined, undefined, undefined)) }} - function defaultRender(vnode) { - return vnode + function defaultRender(vnode1) { + return vnode1 } var route = function(root, defaultRoute, routes) { currentComponent = "div" currentRender = defaultRender currentArgs = null - mount1(root, RouteComponent) - router.defineRoutes(routes, function(payload, args, path) { + mount0(root, RouteComponent) + router.defineRoutes(routes, function(payload, args0, path) { var isResolver = typeof payload.view !== "function" - var render = defaultRender - var resolve = currentResolve = function (component) { - if (resolve !== currentResolve) return + var render1 = defaultRender + var resolve0 = currentResolve = function (component) { + if (resolve0 !== currentResolve) return currentResolve = null currentComponent = component != null ? component : isResolver ? "div" : payload - currentRender = render - currentArgs = args + currentRender = render1 + currentArgs = args0 currentPath = path root.redraw(true) } var onmatch = function() { - resolve() + resolve0() } if (isResolver) { - if (typeof payload.render === "function") render = payload.render.bind(payload) + if (typeof payload.render === "function") render1 = payload.render.bind(payload) if (typeof payload.onmatch === "function") onmatch = payload.onmatch } - onmatch.call(payload, resolve, args, path) + onmatch.call(payload, resolve0, args0, path) }, function() { router.setPath(defaultRoute, null, {replace: true}) }) @@ -1167,10 +1173,11 @@ m.route = function($window, mount1) { route.set = router.setPath route.get = function() {return currentPath} return route -}(window, m.mount) -m.withAttr = function(attrName, callback, context) { +} +m.route = _25(window, mount) +m.withAttr = function(attrName, callback2, context) { return function(e) { - return callback.call(context || this, attrName in e.currentTarget ? e.currentTarget[attrName] : e.currentTarget.getAttribute(attrName)) + return callback2.call(context || this, attrName in e.currentTarget ? e.currentTarget[attrName] : e.currentTarget.getAttribute(attrName)) } } m.prop = Stream @@ -1183,5 +1190,4 @@ m.buildQueryString = buildQueryString m.version = "1.0.0" if (typeof module !== "undefined") module["exports"] = m else window.m = m - } \ No newline at end of file diff --git a/mithril.min.js b/mithril.min.js index a91c26ca..14df1588 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,42 +1,42 @@ -new function(){function w(b,f,p,h,k,l){return{tag:b,key:f,attrs:p,children:h,text:k,dom:l,domSize:void 0,state:{},events:void 0,instance:void 0,skip:!1}}function y(b){if(null==b||"string"!==typeof b&&null==b.view)throw Error("The selector must be either a string or a component.");if("string"===typeof b&&void 0===H[b]){for(var f,p,h=[],k={};f=O.exec(b);){var l=f[1],m=f[2];""===l&&""!==m?p=m:"#"===l?k.id=m:"."===l?h.push(m):"["===f[3][0]&&((l=f[6])&&(l=l.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")), -k[f[4]]=l||!0)}0=t&&z>=A;){var r=a[t],u=e[A];if(r===u)t++,A++;else if(null!=r&&null!=u&&r.key===u.key)t++,A++,l(c,r,u,b,v(a,t,d),k,h),k&&r.tag===u.tag&&q(c,m(r),d);else if(r=a[B],r===u)B--,A++;else if(null!=r&&null!=u&&r.key===u.key)l(c,r,u,b,v(a,B+1,d),k,h),A=t&&z>=A;){r=a[B];u=e[z];if(r===u)B--;else if(null!=r&&null!=u&&r.key===u.key)l(c,r,u,b,v(a,B+1,d),k,h),k&&r.tag===u.tag&&q(c,m(r),d),null!=r.dom&&(d=r.dom),B--;else{if(!n){n=a;var r=B,C={},x;for(x=0;xb.filter(I).length)throw Error("Ensure that each item passed to m.prop.combine/m.prop.merge is a stream");return r(f(),b,function(){var d=b.filter(E);if(0b.indexOf("?")?"?":"&";b+=h+f}return b}function k(b){try{return""!==b?JSON.parse(b):null}catch(d){throw Error(b);}}function l(b){return b.responseText}function m(b,d){if("function"===typeof b)if(d instanceof Array)for(var f=0;fn.status||304===n.status)d(m(g.type,b));else{var f=Error(n.responseText), -h;for(h in b)f[h]=b[h];d.error(f)}}catch(k){d.error(k)}"function"===typeof q&&q()}};z?n.send(g.data):n.send();return d},jsonp:function(g){var d=f();void 0!==g.initialValue&&d(g.initialValue);var k=g.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+v++,n=b.document.createElement("script");b[k]=function(f){n.parentNode.removeChild(n);d(m(g.type,f));"function"===typeof q&&q();delete b[k]};n.onerror=function(){n.parentNode.removeChild(n);d.error(Error("JSONP request failed"));"function"=== -typeof q&&q();delete b[k]};null==g.data&&(g.data={});g.url=p(g.url,g.data);g.data[g.callbackKey||"callback"]=k;n.src=h(g.url,g.data);b.document.documentElement.appendChild(n);return d},setCompletionCallback:function(b){q=b}}}(window,N),K=function(){var b=[];return{subscribe:b.push.bind(b),unsubscribe:function(f){f=b.indexOf(f);-1d.filter(E).length)throw Error("Ensure that each item passed to m.prop.combine/m.prop.merge is a stream");return x(e(),d,function(){var b= +d.filter(M);if(0b.indexOf("?")?"?":"&";b+=h+g}return b}function k(b){try{return""!==b?JSON.parse(b):null}catch(e){throw Error(b);}}function h(b){return b.responseText}function q(b,e){if("function"===typeof b)if(e instanceof Array)for(var g=0;gm.status||304=== +m.status)p(q(f.type,b));else{var e=Error(m.responseText),g;for(g in b)e[g]=b[g];p.error(e)}}catch(k){p.error(k)}"function"===typeof r&&r()}};A?m.send(f.data):m.send();return p},jsonp:function(f){var h=e();void 0!==f.initialValue&&h(f.initialValue);var k=f.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+t++,m=b.document.createElement("script");b[k]=function(e){m.parentNode.removeChild(m);h(q(f.type,e));"function"===typeof r&&r();delete b[k]};m.onerror=function(){m.parentNode.removeChild(m); +h.error(Error("JSONP request failed"));"function"===typeof r&&r();delete b[k]};null==f.data&&(f.data={});f.url=l(f.url,f.data);f.data[f.callbackKey||"callback"]=k;m.src=g(f.url,f.data);b.document.documentElement.appendChild(m);return h},setCompletionCallback:function(b){r=b}}}(window,N),J=function(){var b=[];return{subscribe:b.push.bind(b),unsubscribe:function(e){e=b.indexOf(e);-1=v&&A>=m;){var y=a[v],n=d[m];if(y===n)v++,m++;else if(null!=y&&null!=n&&y.key===n.key)v++,m++,h(c,y,n,b,t(a,v,g),p,k),p&&y.tag===n.tag&&r(c,q(y),g);else if(y=a[x],y===n)x--,m++;else if(null!=y&&null!=n&&y.key===n.key)h(c,y,n,b,t(a,x+1,g),p,k),m=v&&A>=m;){y=a[x];n=d[A];if(y===n)x--;else if(null!=y&&null!=n&&y.key===n.key)h(c,y,n,b,t(a,x+1,g),p,k),p&&y.tag===n.tag&&r(c,q(y),g),null!=y.dom&&(g=y.dom),x--;else{if(!B){B=a;var y=x,u={},w;for(w=0;w< +y;w++){var C=B[w];null!=C&&(C=C.key,null!=C&&(u[C]=w))}B=u}null!=n&&(y=B[n.key],null!=y?(u=a[y],h(c,u,n,b,t(a,x+1,g),p,k),r(c,q(u),g),a[y].skip=!0,null!=u.dom&&(g=u.dom)):(n=l(n,b,void 0),r(c,n,g),g=n))}A--;if(A