Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 21 additions & 45 deletions api/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ var parsePathname = require("../pathname/parse")
var compileTemplate = require("../pathname/compileTemplate")
var censor = require("../util/censor")

var sentinel = {}

function decodeURIComponentSave(component) {
try {
return decodeURIComponent(component)
Expand All @@ -27,27 +25,19 @@ module.exports = function($window, mountRedraw) {

var scheduled = false

// state === 0: init
// state === 1: scheduled
// state === 2: done
var ready = false
var state = 0
var hasBeenResolved = false

var compiled, fallbackRoute

var currentResolver = sentinel, component, attrs, currentPath, lastUpdate
var currentResolver, component, attrs, currentPath, lastUpdate

var RouterRoot = {
onbeforeupdate: function() {
state = state ? 2 : 1
return !(!state || sentinel === currentResolver)
},
onremove: function() {
$window.removeEventListener("popstate", fireAsync, false)
$window.removeEventListener("hashchange", resolveRoute, false)
},
view: function() {
if (!state || sentinel === currentResolver) return
if (!hasBeenResolved) return
// Wrap in a fragment to preserve existing key semantics
var vnode = [Vnode(component, attrs.key, attrs)]
if (currentResolver) vnode = currentResolver.render(vnode[0])
Expand Down Expand Up @@ -81,14 +71,11 @@ module.exports = function($window, mountRedraw) {

function reject(e) {
console.error(e)
setPath(fallbackRoute, null, {replace: true})
route.set(fallbackRoute, null, {replace: true})
}

loop(0)
function loop(i) {
// state === 0: init
// state === 1: scheduled
// state === 2: done
for (; i < compiled.length; i++) {
if (compiled[i].check(data)) {
var payload = compiled[i].component
Expand All @@ -100,9 +87,9 @@ module.exports = function($window, mountRedraw) {
component = comp != null && (typeof comp.view === "function" || typeof comp === "function")? comp : "div"
attrs = data.params, currentPath = path, lastUpdate = null
currentResolver = payload.render ? payload : null
if (state === 2) mountRedraw.redraw()
if (hasBeenResolved) mountRedraw.redraw()
else {
state = 2
hasBeenResolved = true
mountRedraw.redraw.sync()
}
}
Expand All @@ -117,22 +104,18 @@ module.exports = function($window, mountRedraw) {
return payload.onmatch(data.params, path, matchedRoute)
}).then(update, path === fallbackRoute ? null : reject)
}
else update("div")
else update(/* "div" */)
return
}
}

if (path === fallbackRoute) {
throw new Error("Could not resolve default route " + fallbackRoute + ".")
}
setPath(fallbackRoute, null, {replace: true})
route.set(fallbackRoute, null, {replace: true})
}
}

// Set it unconditionally so `m.route.set` and `m.route.Link` both work,
// even if neither `pushState` nor `hashchange` are supported. It's
// cleared if `hashchange` is used, since that makes it automatically
// async.
function fireAsync() {
if (!scheduled) {
scheduled = true
Expand All @@ -143,20 +126,6 @@ module.exports = function($window, mountRedraw) {
}
}

function setPath(path, data, options) {
path = buildPathname(path, data)
if (ready) {
fireAsync()
var state = options ? options.state : null
var title = options ? options.title : null
if (options && options.replace) $window.history.replaceState(state, title, route.prefix + path)
else $window.history.pushState(state, title, route.prefix + path)
}
else {
$window.location.href = route.prefix + path
}
}

function route(root, defaultRoute, routes) {
if (!root) throw new TypeError("DOM element being rendered to does not exist.")

Expand All @@ -180,11 +149,7 @@ module.exports = function($window, mountRedraw) {
}
}

if (typeof $window.history.pushState === "function") {
$window.addEventListener("popstate", fireAsync, false)
} else if (route.prefix[0] === "#") {
$window.addEventListener("hashchange", resolveRoute, false)
}
$window.addEventListener("popstate", fireAsync, false)

ready = true
mountRedraw.mount(root, RouterRoot)
Expand All @@ -196,7 +161,18 @@ module.exports = function($window, mountRedraw) {
options.replace = true
}
lastUpdate = null
setPath(path, data, options)

path = buildPathname(path, data)
if (ready) {
fireAsync()
var state = options ? options.state : null
var title = options ? options.title : null
if (options && options.replace) $window.history.replaceState(state, title, route.prefix + path)
else $window.history.pushState(state, title, route.prefix + path)
}
else {
$window.location.href = route.prefix + path
}
}
route.get = function() {return currentPath}
route.prefix = "#!"
Expand Down