-
Notifications
You must be signed in to change notification settings - Fork 10
/
browser.js
106 lines (93 loc) · 3.2 KB
/
browser.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
95
96
97
98
99
100
101
102
103
104
105
106
require('core-js/stable')
require('regenerator-runtime/runtime')
const debug = require('debug')('demspace:app')
window.name = 'democracy.space'
const cookies = require('browser-cookies')
const lighterhtml = require('lighterhtml-plus')
const { runtime } = require('raj')
const { combineEffects, loadPage } = require('./helpers')
const App = require('./app')
let starting = true
// Use state sent from server, if available.
const initState = window.__app_state || { ...App.init[0] }
const node = document.getElementById('application')
// Initialize listeners for browser history events
const listeners = (dispatch) => ({
popstate: () => {
loadPage(window.location.pathname + window.location.search, 200, dispatch, false)
},
redirect: (event) => {
const status = event.detail.code || event.detail.status || 302
if (status === 303) {
window.history.pushState({}, null, event.detail.url)
} else {
window.history.replaceState({}, null, event.detail.url)
}
loadPage(event.detail.url, status, dispatch)
},
click: (event) => {
const url = window.location.pathname + window.location.search
const node = event.target
const parent = node.parentNode
const anchor = node.tagName === 'A' ? node : (parent && parent.tagName === 'A' && parent)
const href = anchor && anchor.getAttribute('href')
if (!event.metaKey && href && href[0] === '/' && href.split('#')[0] !== url) {
event.preventDefault()
window.history.pushState({}, null, href)
loadPage(href, 200, dispatch)
}
},
})
// Register browser history listeners
const watchHistory = (status) => (dispatch) => {
loadPage(window.location.pathname + window.location.search, status || 404, dispatch)
const { click, popstate, redirect } = window.__listeners || {}
window.removeEventListener('popstate', popstate)
window.removeEventListener('redirect', redirect)
window.removeEventListener('click', click)
const l = window.__listeners = listeners(dispatch)
window.addEventListener('popstate', l.popstate)
window.addEventListener('redirect', l.redirect)
window.addEventListener('click', l.click)
}
let prevState = null
runtime({
...App,
init: [{
...initState,
browser: true,
firstPageLoad: true,
cookies: cookies.all(),
}, combineEffects([watchHistory(initState.location.status), App.init[1]])],
update: (event, state) => {
debug(event, state)
switch (event.type) {
case 'cookieSet':
return [{
...state,
cookies: { ...state.cookies, [event.key]: event.value }
}, () => {
cookies.set(event.key, event.value || '', event.opts)
}]
case 'cookieUnset':
return [{ ...state, cookies: { ...state.cookies, [event.key]: null } }, () => {
cookies.erase(event.key)
}]
default:
return App.update(event, state)
}
},
view: (state, dispatch) => {
// Wait for route view to load (async chunked JS) before rendering.
if (starting && !state.loading.page && state.view) {
starting = false
}
if (!starting && state !== prevState) {
prevState = state
lighterhtml.render(node, () => App.view(state, dispatch))
}
},
})
if (module.hot) {
module.hot.accept()
}