Skip to content

Instantly share code, notes, and snippets.

@ishiduca
Last active June 5, 2018 03:12
Show Gist options
  • Save ishiduca/0de1ef507f4c40da0d1d00b3e9e2dda2 to your computer and use it in GitHub Desktop.
Save ishiduca/0de1ef507f4c40da0d1d00b3e9e2dda2 to your computer and use it in GitHub Desktop.
snoopy routing
const d = require('global/document')
const yo = require('yo-yo')
const router = require('./browser')
const {pipe, through} = require('mississippi')
const {start} = require('@ishiduca/snoopy')
const {views} = start(
router({
init () {
return {
model: {
user_id: 'Twiggy'
}
}
},
update (model, action) {
return {model}
},
routes: {
'/' (params, model, actionsUp) {
return yo`
<div>
<ul>
<li><a href="/test/${model.user_id}">${model.user_id}</a></li>
<li><a href="/test/${model.user_id}/favorites">${model.user_id}s favs</a></li>
<li><a href="/notfound">/notfound</a></li>
</ul>
</div>
`
},
'/test/:user_id(/:category)' (params, model, actionsUp) {
return yo`
<div>
<h1>${params.user_id}</h1>
<h2>${params.category || '---'}</h2>
</div>
`
},
'/404' (params, model, actionsUp) {
return yo`
<div>
<h1>not found</h1>
<a href='/'>/</a>
</div>
`
}
},
run (effect, sourcs) {}
})
)
const el = yo`<div></div>`
pipe(
views(),
through.obj((view, _, done) => {
yo.update(el, view)
done()
}),
err => (err ? console.error(err) : console.log('finished'))
)
d.body.appendChild(el)
const w = require('global/window')
const href = require('nanohref')
const xtend = require('xtend')
const defined = require('defined')
const routing = require('@ishiduca/routing')
const {through} = require('mississippi')
module.exports = function router (app) {
const r = routing()
Object.keys(app.routes).forEach(pattern => (
r.define(pattern, app.routes[pattern])
))
return {
init () {
const state = app.init()
const effect = {
type: 'routingInit'
}
return {
model: xtend(state.model, {uri: '/'}),
effect: [].concat(state.effect || []).concat(effect)
}
},
update (model, action) {
if (action.type === 'changeURL') {
return {model: xtend(model, action.payload)}
}
return defined(app.update(model, action), {model})
},
view (model, actionsUp) {
const m = r.match(model.uri) || r.match('/404')
return m.values[0](m.params, model, actionsUp)
},
run (effects, sources) {
if (!Array.isArray(effects)) {
return defined(routingInit(effects), app.run(effects, sources))
}
const s = through.obj()
var c = 0
effects.map(effect => (
defined(routingInit(effect), app.run(effect, sources))
))
.filter(Boolean)
.forEach(src => {
c += 1
src.once('end', onSrcEnd)
.on('error', onSrcEnd)
.pipe(s, {end: false})
function onSrcEnd (err) {
if (err) {
s.write({
type: 'error',
payload: err
})
console.error(err)
}
if ((c -= 1) === 0) s.end()
}
})
return s
}
}
function routingInit (effect) {
if (effect.type !== 'routingInit') return
const s = through.obj()
href(loc => {
w.history.pushState({}, '', loc.pathname)
s.write({
type: 'changeURL',
payload: {uri: loc.pathname}
})
})
w.onpopstate = e => {
s.write({
type: 'changeURL',
payload: {uri: w.location.pathname}
})
}
return s
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment