-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
94 lines (81 loc) · 3.3 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
const client = require('utilise/client')
, keys = require('utilise/keys')
, key = require('utilise/key')
, is = require('utilise/is')
const log = require('utilise/log')('[router]')
, go = url => {
if (window.event) window.event.preventDefault()
history.pushState({}, '', url)
window.dispatchEvent(new CustomEvent('change'))
return url
}
const router = routes => {
return !client ? route : route({ url: location.pathname })
function route(req, res, next) {
const from = req.url
, resolved = resolve(routes)(req)
, finish = ({ url, params }) => {
if (from !== url) log('router redirecting', from, url)
if (client) location.params = params
return client && from !== url ? (go(url), { url, params })
: !client && from !== url ? res.redirect(url)
: !client ? next()
: { url, params }
}
return is.promise(resolved) ? resolved.then(finish) : finish(resolved)
}
}
const resolve = routes => (req, url = req.url) => {
const params = {}
, to = next(req, params, url, routes)
, finish = to =>
to == '../' || to == '..' ? resolve(routes)(req, '/' + url.split('/').filter(Boolean).slice(0, -1).join('/'))
: !to ? false
: to !== true ? resolve(routes)(req, to)
: { url, params }
return is.promise(to) ? to.then(finish) : finish(to)
}
const next = (req, params = {}, url, value, variable) => {
const { cur, remainder } = segment(url)
return is.promise(value) ? value.then(v => next(req, params, url, v, variable))
: is.str(value) || is.bol(value) ? value
: is.fn(value) && !is.def(variable) ? next(req, params, url, value(req))
: is.fn(value) ? next(req, params, url, value(variable, req))
: cur in value ? next(req, params, remainder, value[cur])
: !cur && value[':'] ? next(req, params, remainder, value[':'])
: variables(
params
, (route) => next(req, params, remainder, value[route.key], cur || false)
, (route, result) => result === true && route.name && (params[route.name] = cur)
, keys(value)
.filter(([f]) => f == ':')
.map(k => ({ key: k, name: k.slice(1) }))
)
}
const variables = (params, match, success, routes, route = routes.shift()) =>
!route ? false : Promise.resolve(match(route))
.then(result => result
? (success(route, result), result)
: variables(params, match, success, routes)
)
function segment(url) {
const segments = url.split('/').filter(Boolean)
return { cur: segments.shift(), remainder: '/' + segments.join('/') }
}
if (client) {
window.go = go
window.router = router
window.router.resolve = resolve
window.addEventListener('popstate', e => window.dispatchEvent(new CustomEvent('change')))
window.addEventListener('change', e => {
e.target == window && window.app && app.render()
})
document.addEventListener('click', e => {
const a = e.path ? e.path.shift() : e.target
if (!a.matches('a[href]:not([href^=javascript]):not([bypass])') || a.matches('[bypass] *')) return
if (is.def(a.origin) && a.origin != location.origin) return
e.preventDefault()
go(a.href)
})
}
module.exports = { router, resolve }