teth
Version:
Functional, reactive, pattern matching based, centralized state tree, open source JS library.
78 lines (72 loc) • 2.42 kB
JavaScript
/* Copyright 2017 Ronny Reichmann */
/* ROUTE Define route-change events. */
const Route = require('route-parser')
const pipe = require('./pipe')
const jsonic = require('jsonic')
const { context, circular, send } = require('./T')
const immutableLiteral = lit => Object.freeze(typeof lit === 'string' ? jsonic(lit) : lit)
const ctx = context()
function retrieveWindow () {
return pipe(resolve => {
send('type: teth-globals, retrieve: window-object')
.then(win => { resolve(win) })
.catch(() => { resolve(window) })
})
}
function route (description, ...args) {
if (args.length === 2) {
return composeStateMutatingRoute(description, args[0], args[1])
} else if (args.length === 1) {
return composeMessagingRoute(description, args[0])
} else {
throw new Error('Call route(...) either with (<description>, <pattern>) or (<description>, <middleware>, <routine>)')
}
}
route.change = (...routeComponents) => {
retrieveWindow()
.then(win => {
win.location.hash = routeComponents.join('')
})
.catch(console.error)
}
function composeRouteBase (description, hitCallback) {
retrieveWindow()
.then(win => {
const matcher = new Route(description)
function onChange () {
const routeString = win.location.href.slice(win.location.origin.length)
const params = matcher.match(routeString)
if (params) hitCallback(params)
}
win.addEventListener('load', onChange)
win.addEventListener('hashchange', onChange)
})
.catch(console.error)
const composit = {
route: (subDescription, ...args) => {
const fullSubDescription = description + subDescription
return route(fullSubDescription, ...args)
}
}
return Object.freeze(composit)
}
function composeStateMutatingRoute (description, middleware, routine) {
const pattern = { type: 'route', description }
ctx.define(pattern, middleware, routine)
return composeRouteBase(description, params => {
ctx.send(Object.assign({ params }, pattern))
.catch(error => {
console.error('Route error:', error)
})
})
}
function composeMessagingRoute (description, pattern) {
pattern = immutableLiteral(pattern)
return composeRouteBase(description, params => {
circular(Object.assign({ params }, pattern))
.catch(error => {
console.error('Route error:', error)
})
})
}
module.exports = route