Files
buuh/index.js
T

144 lines
3.3 KiB
JavaScript
Raw Normal View History

2016-05-12 14:45:20 +07:00
const history = require('sheet-router/history')
2016-05-11 13:51:17 +07:00
const sheetRouter = require('sheet-router')
const document = require('global/document')
2016-05-12 14:45:20 +07:00
const href = require('sheet-router/href')
2016-05-11 13:51:17 +07:00
const sendAction = require('send-action')
const xtend = require('xtend')
const yo = require('yo-yo')
2016-05-10 23:23:33 +07:00
2016-05-11 13:51:17 +07:00
choo.view = yo
2016-05-10 23:23:33 +07:00
module.exports = choo
2016-05-11 13:51:17 +07:00
// A framework for creating sturdy web applications
// null -> fn
2016-05-12 14:45:20 +07:00
function choo (opts) {
opts = opts || {}
const name = opts.name || 'choo'
2016-05-11 13:51:17 +07:00
var _router = null
var _models = [ appInit() ]
start.router = router
start.model = model
start.start = start
return start
// start the application
2016-05-11 14:56:18 +07:00
// null -> DOMNode
function start () {
2016-05-11 13:51:17 +07:00
const events = bootstrap(_models)
const send = sendAction({
2016-05-12 14:45:20 +07:00
onaction: events.modifyState,
2016-05-11 13:51:17 +07:00
onchange: onchange,
state: events.state
})
2016-05-12 14:45:20 +07:00
if (opts.href !== false) {
href(function (href) {
send('location', { location: href })
})
}
if (opts.history !== false) {
history(function (href) {
send('location', { location: href })
})
}
const rootId = name + '-root'
2016-05-11 14:56:18 +07:00
const tree = _router(send.state().location, send.state(), send)
2016-05-12 14:45:20 +07:00
tree.setAttribute('id', rootId)
2016-05-11 14:56:18 +07:00
return tree
2016-05-11 13:51:17 +07:00
// update on every change
function onchange (action, state) {
2016-05-12 14:45:20 +07:00
const oldTree = document.querySelector('#' + rootId)
2016-05-11 14:56:18 +07:00
const newTree = _router(state.location, state, send)
2016-05-12 14:45:20 +07:00
newTree.setAttribute('id', rootId)
2016-05-11 14:56:18 +07:00
yo.update(oldTree, newTree)
2016-05-11 13:51:17 +07:00
}
}
// register all routes
// [obj|fn] -> null
function router (cb) {
_router = sheetRouter(cb)
}
// create a new model
// (str?, obj) -> null
function model (name, model) {
if (!model) model = name
if (typeof name === 'string') model.name = name
_models.push(model)
}
}
2016-05-12 14:45:20 +07:00
// initial application state model
// null -> obj
2016-05-11 13:51:17 +07:00
function appInit () {
return {
state: {
location: document.location.href
},
reducers: {
location: setLocation
}
}
// handle href links
function setLocation (action, state) {
const location = action.location.replace(/#.*/, '')
return xtend(state, { location: location })
}
}
function bootstrap (events) {
2016-05-12 14:45:20 +07:00
const initialState = {}
2016-05-11 13:51:17 +07:00
const reducers = {}
const effects = {}
2016-05-12 14:45:20 +07:00
events.forEach(function (model) {
if (model.state) apply(model.name, model.state, initialState)
if (model.reducers) apply(model.name, model.reducers, reducers)
if (model.effects) apply(model.name, model.effects, effects)
2016-05-11 13:51:17 +07:00
})
return {
2016-05-12 14:45:20 +07:00
modifyState: modifyState,
2016-05-11 13:51:17 +07:00
state: initialState
}
function modifyState (action, state, send) {
2016-05-11 14:56:18 +07:00
var _reducers = false
var _effects = false
var newState = null
2016-05-11 13:51:17 +07:00
if (reducers[action.type]) {
2016-05-11 14:56:18 +07:00
newState = xtend(state, reducers[action.type](action, state))
_reducers = true
}
if (effects[action.type]) {
2016-05-13 12:23:25 +07:00
effects[action.type](action, newState || state, send)
2016-05-11 14:56:18 +07:00
newState = newState || state
_effects = true
}
if (!_reducers && !_effects) {
2016-05-11 13:51:17 +07:00
throw new Error('Could not find action ' + action.type)
}
2016-05-11 14:56:18 +07:00
return newState
2016-05-11 13:51:17 +07:00
}
2016-05-10 23:23:33 +07:00
}
2016-05-12 14:45:20 +07:00
// compose an object conditionally
// (str, obj, obj) -> null
function apply (name, source, target) {
Object.keys(source).forEach(function (key) {
if (name) target[name + ':' + key] = source[key]
else target[key] = source[key]
})
}