bundler variable disambiguation

This commit is contained in:
Leo Horie 2016-05-20 22:38:10 -04:00
parent 2ca8fa6e66
commit e5391a1957
10 changed files with 75 additions and 542 deletions

View file

@ -4,6 +4,14 @@ Note: This branch is a sneak peek for the upcoming version 1.0. It's a rewrite f
This rewrite aims to fix longstanding API design issues, significantly improve performance, and clean up the codebase.
## Early Preview
You can install this via NPN using this command:
```
npm install lhorie/mithril.js#rewrite
```
## Status
Code still is in flux. Most notably, there's no promise polyfill yet and there are several use cases that still need to be polished. DO NOT USE IN PRODUCTION YET!

View file

@ -1,10 +1,10 @@
"use strict"
var createRenderer = require("../render/render")
var coreRenderer = require("../render/render")
var throttle = require("../api/throttle")
module.exports = function($window, redraw) {
var renderer = createRenderer($window)
var renderer = coreRenderer($window)
return function(root, component) {
var run = throttle(function() {
renderer.render(root, {tag: component})

View file

@ -1,12 +1,12 @@
"use strict"
var createRenderer = require("../render/render")
var createRouter = require("../router/router")
var coreRenderer = require("../render/render")
var coreRouter = require("../router/router")
var throttle = require("../api/throttle")
module.exports = function($window, redraw) {
var renderer = createRenderer($window)
var router = createRouter($window)
var renderer = coreRenderer($window)
var router = coreRouter($window)
var route = function(root, defaultRoute, routes) {
var replay = router.defineRoutes(routes, function(component, args) {
renderer.render(root, {tag: component, attrs: args})

View file

@ -4,7 +4,7 @@ var o = require("../../ospec/ospec")
var domMock = require("../../test-utils/domMock")
var m = require("../../render/hyperscript")
var createMounter = require("../mount")
var apiMounter = require("../../api/mount")
o.spec("m.mount", function() {
var FRAME_BUDGET = 1000 / 60

View file

@ -5,7 +5,7 @@ var pushStateMock = require("../../test-utils/pushStateMock")
var domMock = require("../../test-utils/domMock")
var m = require("../../render/hyperscript")
var router = require("../../api/router")
var apiRouter = require("../../api/router")
o.spec("m.route", function() {
var FRAME_BUDGET = 1000 / 60
@ -23,7 +23,7 @@ o.spec("m.route", function() {
root = $window.document.body
redraw = {}
route = router($window, redraw)
route = apiRouter($window, redraw)
})
o("updates redraw object", function() {

View file

@ -4,21 +4,23 @@ var fs = require("fs")
var path = require("path")
var modules = {}
var usedVariables = {}
function resolve(dir, data) {
var replacements = []
data = data.replace(/((?:var|let|const|)\s*)([\w_$]+)(\s*=\s*)require\(([^\)]+)\)/g, function(match, def, variable, eq, dep) {
data = data.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()
var pathname = path.dirname(path.resolve(dir, filename))
var normalized = path.normalize(dir + "/" + filename)
var normalized = path.resolve(dir, filename)
var pathname = path.dirname(normalized)
if (modules[normalized] === undefined) {
modules[normalized] = variable
return resolve(pathname,
fs.readFileSync(dir + "/" + filename + ".js", "utf8")
.replace(/"use strict"\s*/gm, "")
.replace(/module\.exports\s*=\s*/gm, def + variable + eq)
//.replace(/module\.exports(\.[\w_$]|\["[^\"]"\])/, def + variable + eq + "{}\n" + variable + "$1")
)
var exported = fixCollisions(fs.readFileSync(dir + "/" + filename + ".js", "utf8"))
.replace(/"use strict"\s*/gm, "") // remove extraneous "use strict"
.replace(/module\.exports\s*=\s*/gm, def + variable + eq)
//.replace(/module\.exports(\.[\w_$]|\["[^\"]"\])/, def + variable + eq + "{}\n" + variable + "$1")
return resolve(pathname, exported)
}
else {
if (modules[normalized] !== variable) {
@ -33,6 +35,25 @@ function resolve(dir, data) {
}
}
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$1") // remove multiple consecutive line breaks
}
fs.writeFileSync("mithril.js", resolve(".", fs.readFileSync("index.js", "utf8")), "utf8")
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)) {
var fixed = variable + usedVariables[variable]++
code = code.replace(collision, fixed)
}
}
return code
}
function bundle(input, output) {
var code = resolve(".", fs.readFileSync(input, "utf8"))
if (new Function(code)) fs.writeFileSync(output, code, "utf8")
}
bundle("index.js", "mithril.js")

View file

@ -2,19 +2,19 @@
var m = require("./render/hyperscript")
var trust = require("./render/trust")
var createRenderer = require("./render/render")
var createMounter = require("./api/mount")
var createRouterInstance = require("./api/router")
var createRequester = require("./request/request")
var coreRenderer = require("./render/render")
var apiMounter = require("./api/mount")
var apiRouter = require("./api/router")
var coreRequester = require("./request/request")
var redraw = {run: function() {}}
m.redraw = function() {
redraw.run()
}
m.trust = trust
m.render = createRenderer(window).render
m.mount = createMounter(window, redraw)
m.route = createRouterInstance(window, redraw)
m.request = createRequester(window, Promise).ajax
m.render = coreRenderer(window).render
m.mount = apiMounter(window, redraw)
m.route = apiRouter(window, redraw)
m.request = coreRequester(window, Promise).ajax
module.exports = m

View file

@ -15,8 +15,6 @@ Node.normalizeChildren = function normalizeChildren(children) {
return children
}
var Node = Node
var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, attrParser = /\[(.+?)(?:\s*=\s*("|'|)(.*?)\2)?\]/
var selectorCache = {}
function hyperscript(selector) {
@ -91,500 +89,11 @@ function changeNS(ns, vnode) {
var m = hyperscript
var trust = function(html) {
return Node("<", undefined, undefined, html, undefined, undefined)
}
var createRenderer = function($window) {
var $doc = $window.document
var onevent
function setEventCallback(callback) {return onevent = callback}
//create
function createNodes(parent, vnodes, start, end, hooks, nextSibling) {
for (var i = start; i < end; i++) {
var vnode = vnodes[i]
if (vnode != null) {
insertNode(parent, createNode(vnode, hooks), nextSibling)
}
}
}
function createNode(vnode, hooks) {
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)
default: return createElement(vnode, hooks)
}
}
else return createComponent(vnode, hooks)
}
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) {
var fragment = $doc.createDocumentFragment()
if (vnode.children != null) {
var children = vnode.children
createNodes(fragment, children, 0, children.length, hooks, null)
}
vnode.dom = fragment.firstChild
vnode.domSize = fragment.childNodes.length
return fragment
}
function createElement(vnode, hooks) {
var tag = vnode.tag
var ns = vnode.ns
var attrs = vnode.attrs
var is = attrs && attrs.is
var element = ns ?
is ? $doc.createElementNS(ns, tag, is) : $doc.createElementNS(ns, tag) :
is ? $doc.createElement(tag, is) : $doc.createElement(tag)
vnode.dom = element
if (attrs != null) {
setAttrs(vnode, attrs)
}
if (vnode.text != null) {
if (vnode.text !== "") element.textContent = vnode.text
else vnode.children = [Node("#", undefined, undefined, vnode.text, undefined, undefined)]
}
if (vnode.children != null) {
var children = vnode.children
createNodes(element, children, 0, children.length, hooks, null)
setLateAttrs(vnode)
}
return element
}
function createComponent(vnode, hooks) {
vnode.state = copy(vnode.tag)
initLifecycle(vnode.tag, vnode, hooks)
vnode.instance = Node.normalize(vnode.tag.view.call(vnode.state, vnode))
var element = createNode(vnode.instance, hooks)
vnode.dom = vnode.instance.dom
vnode.domSize = vnode.instance.domSize
return element
}
//update
function updateNodes(parent, old, vnodes, hooks, nextSibling) {
if (old == null && vnodes == null) return
else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling)
else if (vnodes == null) removeNodes(parent, old, 0, old.length, vnodes)
else {
var recycling = isRecyclable(old, vnodes)
if (recycling) old = old.concat(old.pool)
var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map
while (oldEnd >= oldStart && end >= start) {
var o = old[oldStart], v = vnodes[start]
if (o === v) oldStart++, start++
else if (o != null && v != null && o.key === v.key) {
oldStart++, start++
updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), recycling)
if (recycling) 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)
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)
if (recycling) insertNode(parent, toFragment(o), nextSibling)
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)
insertNode(parent, toFragment(movable), nextSibling)
old[oldIndex].skip = true
nextSibling = movable.dom
}
else {
var dom = createNode(v, hooks)
insertNode(parent, dom, nextSibling)
nextSibling = dom
}
}
end--
}
if (end < start) break
}
createNodes(parent, vnodes, start, end + 1, hooks, nextSibling)
removeNodes(parent, old, oldStart, oldEnd + 1, vnodes)
}
}
function updateNode(parent, old, vnode, hooks, nextSibling, recycling) {
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); break
default: updateElement(old, vnode, hooks)
}
}
else updateComponent(parent, old, vnode, hooks, nextSibling, recycling)
}
else {
removeNode(parent, old, null, false)
insertNode(parent, createNode(vnode, hooks), 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
}
function updateFragment(parent, old, vnode, hooks, nextSibling) {
updateNodes(parent, old.children, vnode.children, hooks, nextSibling)
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) {
if (vnode.dom == null) vnode.dom = child.dom
domSize += child.domSize || 1
}
}
if (domSize !== 1) vnode.domSize = domSize
}
}
function updateElement(old, vnode, hooks) {
var element = vnode.dom = old.dom
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)
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 = [Node("#", undefined, undefined, old.text, undefined, old.dom.firstChild)]
if (vnode.text != null) vnode.children = [Node("#", undefined, undefined, vnode.text, undefined, undefined)]
updateNodes(element, old.children, vnode.children, hooks, null)
}
}
function updateComponent(parent, old, vnode, hooks, nextSibling, recycling) {
vnode.instance = Node.normalize(vnode.tag.view.call(vnode.state, vnode))
updateLifecycle(vnode.tag, vnode, hooks, recycling)
updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, recycling)
vnode.dom = vnode.instance.dom
vnode.domSize = vnode.instance.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) {
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) 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 = undefined
else removeNode(parent, vnode, context, false)
}
}
}
function removeNode(parent, vnode, context, deferred) {
if (deferred === false) {
var expected = 0, called = 0
var callback = function() {
if (++called === expected) removeNode(parent, vnode, context, true)
}
if (vnode.attrs && vnode.attrs.onbeforeremove) {
expected++
vnode.attrs.onbeforeremove.call(vnode, vnode, callback)
}
if (typeof vnode.tag !== "string" && vnode.tag.onbeforeremove) {
expected++
vnode.tag.onbeforeremove.call(vnode, vnode, callback)
}
if (expected > 0) return
}
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)) { //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)
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) {
for (var key in attrs) {
setAttr(vnode, key, null, attrs[key])
}
}
function setAttr(vnode, key, old, value) {
var element = vnode.dom
if (key === "key" || (old === value && !isFormAttribute(vnode, key)) || 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) && vnode.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)
if ("selectedIndex" in attrs) setAttr(vnode, "selectedIndex", null, attrs.selectedIndex)
}
}
function updateAttrs(vnode, old, attrs) {
if (attrs != null) {
for (var key in attrs) {
setAttr(vnode, key, old && old[key], attrs[key])
}
}
if (old != null) {
for (var key in old) {
if (attrs == null || !(key in attrs)) {
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 === "shouldUpdate"
}
function isAttribute(attr) {
return attr === "href" || attr === "list" || attr === "form"// || attr === "type" || attr === "width" || attr === "height"
}
function hasIntegrationMethods(vnode) {
return vnode.attrs != null && (vnode.attrs.oncreate || vnode.attrs.onupdate || vnode.attrs.onbeforeremove || vnode.attrs.onremove)
}
//style
function updateStyle(element, old, style) {
if (style == null) element.style = ""
else if (typeof style === "string") element.style = style
else {
if (typeof old === "string") element.style = ""
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)
vnode.events[key] = callback
element.addEventListener(eventName, vnode.events[key], false)
}
}
//lifecycle
function initLifecycle(source, vnode, hooks) {
if (source.oninit != null) source.oninit.call(vnode.state, vnode)
if (source.oncreate != null) hooks.push(source.oncreate.bind(vnode.state, vnode))
}
function updateLifecycle(source, vnode, hooks, recycling) {
if (recycling) initLifecycle(source, vnode, hooks)
else if (source.onupdate != null) hooks.push(source.onupdate.bind(vnode.state, vnode))
}
function shouldUpdate(vnode, old) {
var forceVnodeUpdate, forceComponentUpdate
if (vnode.attrs != null && typeof vnode.attrs.shouldUpdate === "function") forceVnodeUpdate = vnode.attrs.shouldUpdate.call(vnode.state, vnode, old)
if (typeof vnode.tag !== "string" && typeof vnode.tag.shouldUpdate === "function") forceComponentUpdate = vnode.tag.shouldUpdate.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 copy(data) {
if (data instanceof Array) {
var output = []
for (var i = 0; i < data.length; i++) output[i] = copy(data[i])
return output
}
else if (typeof data === "object") {
var output = {}
for (var i in data) output[i] = copy(data[i])
return output
}
return data
}
function render(dom, vnodes) {
var hooks = []
var active = $doc.activeElement
if (dom.vnodes == null) dom.vnodes = []
if (!(vnodes instanceof Array)) vnodes = [vnodes]
updateNodes(dom, dom.vnodes, Node.normalizeChildren(vnodes), hooks, null)
for (var i = 0; i < hooks.length; i++) hooks[i]()
dom.vnodes = vnodes
if ($doc.activeElement !== active) active.focus()
}
return {render: render, setEventCallback: setEventCallback}
}
var createRenderer = function($window) {
var coreRenderer = function($window) {
var $doc = $window.document
var onevent
@ -1070,12 +579,11 @@ var createRenderer = function($window) {
var throttle = function(callback) {
//60fps translates to 16.6ms, round it down since setTimeout requires int
var time = 16
var time = 16
var last = 0, pending = null
var timeout = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout
return function(synchronous) {
var now = new Date().getTime()
var diff = now - last
if (synchronous === true || last === 0 || now - last >= time) {
last = now
callback()
@ -1090,9 +598,8 @@ var throttle = function(callback) {
}
}
var createMounter = function($window, redraw) {
var renderer = createRenderer($window)
var apiMounter = function($window, redraw) {
var renderer = coreRenderer($window)
return function(root, component) {
var run = throttle(function() {
renderer.render(root, {tag: component})
@ -1105,8 +612,7 @@ var createMounter = function($window, redraw) {
}
}
var buildQueryString = function buildQueryString(object) {
var buildQueryString = function(object) {
if (Object.prototype.toString.call(object) !== "[object Object]") return ""
var args = []
@ -1129,7 +635,7 @@ var buildQueryString = function buildQueryString(object) {
else args.push(encodeURIComponent(key) + (value != null && value !== "" ? "=" + encodeURIComponent(value) : ""))
}
}
var parseQueryString = function parseQueryString(string) {
var parseQueryString = function(string) {
if (string === "" || string == null) return {}
if (string.charAt(0) === "?") string = string.slice(1)
@ -1170,7 +676,7 @@ var parseQueryString = function parseQueryString(string) {
return data
}
var createRouter = function($window) {
var coreRouter = function($window) {
var supportsPushState = typeof $window.history.pushState === "function" && $window.location.protocol !== "file:"
var prefix = "#!"
@ -1274,10 +780,9 @@ var createRouter = function($window) {
return {setPrefix: setPrefix, getPath: getPath, setPath: setPath, defineRoutes: defineRoutes, link: link}
}
var createRouterInstance = function($window, redraw) {
var renderer = createRenderer($window)
var router = createRouter($window)
var apiRouter = function($window, redraw) {
var renderer = coreRenderer($window)
var router = coreRouter($window)
var route = function(root, defaultRoute, routes) {
var replay = router.defineRoutes(routes, function(component, args) {
renderer.render(root, {tag: component, attrs: args})
@ -1295,9 +800,7 @@ var createRouterInstance = function($window, redraw) {
return route
}
var createRequester = function($window, Promise) {
var coreRequester = function($window, Promise) {
var callbackCount = 0
function ajax(args) {
@ -1362,7 +865,7 @@ var createRequester = function($window, Promise) {
resolve(data)
$window[callbackKey] = undefined
}
script.onerror = function(e) {
script.onerror = function() {
script.parentNode.removeChild(script)
reject(new Error("JSONP request failed"))
$window[callbackKey] = undefined
@ -1407,15 +910,16 @@ var createRequester = function($window, Promise) {
return {ajax: ajax, jsonp: jsonp}
}
var redraw = {run: function() {}}
m.redraw = function() {
redraw.run()
}
m.trust = trust
m.render = createRenderer(window).render
m.mount = createMounter(window, redraw)
m.route = createRouterInstance(window, redraw)
m.request = createRequester(window, Promise).ajax
m.render = coreRenderer(window).render
m.mount = apiMounter(window, redraw)
m.route = apiRouter(window, redraw)
m.request = coreRequester(window, Promise).ajax
module.exports = m

View file

@ -1,6 +1,6 @@
"use strict"
module.exports = function buildQueryString(object) {
module.exports = function(object) {
if (Object.prototype.toString.call(object) !== "[object Object]") return ""
var args = []

View file

@ -1,6 +1,6 @@
"use strict"
module.exports = function parseQueryString(string) {
module.exports = function(string) {
if (string === "" || string == null) return {}
if (string.charAt(0) === "?") string = string.slice(1)