Skip to content

Commit 82b4540

Browse files
committed
router rewritten, old one was stupid & complicated. this one's simpler
1 parent aa06f9f commit 82b4540

File tree

1 file changed

+58
-91
lines changed

1 file changed

+58
-91
lines changed

plugins/router.js

Lines changed: 58 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,74 @@
1-
{ /* global rilti */
2-
const {directive, each, runAsync, $, isRenderable, isProxyNode, isFunc, isStr, on, render} = rilti
1+
{ /* global rilti location */
2+
const { directive, emitter, run, isRenderable, isFunc } = rilti
33

4-
const routes = new Map()
5-
routes.viewBinds = new Map()
6-
routes.activeBinds = new Map()
4+
const route = emitter((route, view) => {
5+
if (view == null) return
6+
if (route[0] !== '#') route = '#' + route
77

8-
const route = (name, consumer) => {
9-
if (name[0] !== '#') name = '#' + name
10-
11-
if (isRenderable(consumer)) {
12-
if (consumer.tagName === 'TEMPLATE') {
13-
const template = consumer
14-
consumer = Array.from(consumer.content.childNodes)
15-
template.remove()
16-
}
17-
if (routes.has(name)) {
18-
routes.get(name).view = consumer
19-
} else {
20-
routes.set(name, {name, view: consumer})
21-
}
22-
} else if (isFunc(consumer)) {
23-
if (!routes.has(name)) routes.set(name, {name, consumers: new Set()})
24-
routes.get(name).consumers.add(consumer)
25-
}
26-
runAsync(() => route.activate())
27-
}
28-
route.viewbind = (name, host) => {
29-
if (!isStr(name) && !host) [host, name] = [name, false]
30-
if (host.tagName === 'TEMPLATE') return
31-
if (!isProxyNode(host)) host = $(host)
32-
const viewbind = (route, active) => {
33-
host.textContent = ''
34-
if ('view' in route && active) render(route.view, host)
35-
}
36-
viewbind.revoke = () => {
37-
if (name) {
38-
routes.get(name).consumers.delete(viewbind)
39-
routes.viewBinds.delete(host)
40-
} else if (routes.activeBinds.has(host)) {
41-
routes.activeBinds.delete(host)
42-
}
43-
}
44-
if (name) {
45-
route(name, viewbind)
46-
routes.viewBinds.set(host, viewbind)
47-
} else {
48-
routes.activeBinds.set(host, viewbind)
8+
if (view.tagName === 'TEMPLATE') {
9+
view.remove()
10+
view = [...view.content.childNodes]
4911
}
50-
route.activate()
51-
return viewbind
52-
}
53-
route.revoke = route => {
54-
if ((route = routes.get(route))) {
55-
if (route.consumers && route.consumers.size) {
56-
each(route.consumers, consumer => {
57-
if (consumer.revoke) consumer.revoke()
58-
})
59-
route.consumers.clear()
60-
}
61-
routes.delete(route.name)
62-
}
63-
}
6412

65-
route.activate = (name = window.location.hash || '#') => {
66-
if (name[0] !== '#') name = '#' + name
67-
if (!routes.has(name) || name === routes.active) return
68-
if (name !== window.location.hash || '#') window.location.hash = name
69-
const route = routes.get(name)
70-
if (route && route.consumers && route.consumers.size) {
71-
each(route.consumers, consume => consume(route, true, name))
72-
}
73-
if (routes.activeBinds.size) {
74-
each(routes.activeBinds, bind => bind(route, true, name))
75-
}
76-
if (routes.active != null) {
77-
const oldroute = routes.get(routes.active)
78-
if (oldroute.consumers && oldroute.consumers.size) {
79-
each(oldroute.consumers, c => c(oldroute, false, routes.active))
80-
}
13+
if (isRenderable(view)) {
14+
views[route] = isFunc(view) ? view() : view
8115
}
82-
routes.active = name
83-
}
16+
})
17+
const views = route.views = Object.create(null)
18+
route.hash = () => location.hash.substr(1)
8419

85-
const removeVbindRoute = el => {
86-
const vbind = routes.viewBinds.get(el)
87-
if (vbind) vbind.revoke()
88-
}
20+
directive('route-link', {
21+
init (el, val) {
22+
el.routeLink = route.on.change(() => {
23+
el.class['active-route'] = location.hash === (el.href = '#' + el.attr['route-link'])
24+
})
25+
el.class['active-route'] = location.hash === (el.href = '#' + val)
26+
},
27+
remove: (el, val) => el.routeLink.off()
28+
})
8929

9030
directive('route', {
9131
init (el, val) {
92-
el.tagName === 'TEMPLATE' ? route(val, el) : route.viewbind(val, el)
93-
},
94-
update (el, val) {
95-
removeVbindRoute(el)
96-
route.viewbind(val, el)
32+
if (el.tagName === 'TEMPLATE') {
33+
route(val, el)
34+
} else {
35+
el.routeHandler = route.on.change((view, hash) => {
36+
if (hash === el.attr.route) el.html = view
37+
else el.textContent = ''
38+
})
39+
}
9740
},
98-
remove: removeVbindRoute
41+
remove (el, val) {
42+
if (el.routeHandler) {
43+
el.routeHandler.off()
44+
el.textContent = ''
45+
}
46+
}
9947
})
10048

10149
directive('route-active', {
102-
init: el => route.viewbind(el),
103-
remove: removeVbindRoute
50+
init (el, val) {
51+
el.routeHandler = route.on.change((view, hash) => {
52+
el.attr['route-active'] = hash
53+
el.html = view
54+
})
55+
},
56+
remove (el, val) {
57+
el.routeHandler.off()
58+
el.textContent = ''
59+
}
10460
})
10561

106-
on.hashchange(window, e => route.activate())
62+
rilti.route = route
63+
route.handle = () => {
64+
const view = route.views[location.hash]
65+
if (view == null) return
66+
route.active = view
67+
const hash = route.hash()
68+
route.emit.change(view, hash, route)
69+
route.emit[hash](view, route)
70+
}
71+
72+
window.onhashchange = route.handle
73+
run(() => route.handle())
10774
}

0 commit comments

Comments
 (0)