examples/http: update for ns
This commit is contained in:
@@ -3,13 +3,14 @@ const sheetRouter = require('sheet-router')
|
||||
const document = require('global/document')
|
||||
const href = require('sheet-router/href')
|
||||
const sendAction = require('send-action')
|
||||
const assert = require('assert')
|
||||
const xtend = require('xtend')
|
||||
const yo = require('yo-yo')
|
||||
|
||||
choo.view = yo
|
||||
module.exports = choo
|
||||
|
||||
// A framework for creating sturdy web applications
|
||||
// framework for creating sturdy web applications
|
||||
// null -> fn
|
||||
function choo () {
|
||||
const _models = []
|
||||
@@ -23,6 +24,7 @@ function choo () {
|
||||
return start
|
||||
|
||||
// render the application to a string
|
||||
// (str, obj) -> str
|
||||
function toString (route, state) {
|
||||
const initialState = {}
|
||||
|
||||
@@ -53,61 +55,79 @@ function choo () {
|
||||
if (model.effects) apply(model.namespace, model.effects, effects)
|
||||
})
|
||||
|
||||
// send() is used to trigger actions inside
|
||||
// views, effects and subscriptions
|
||||
const send = sendAction({
|
||||
onaction: handleAction,
|
||||
onchange: onchange,
|
||||
state: initialState
|
||||
})
|
||||
|
||||
// subscriptions are loaded after sendAction() is called
|
||||
// because they both need access to send() and can't
|
||||
// react to actions (read-only)
|
||||
_models.forEach(function (model) {
|
||||
if (model.subscriptions) {
|
||||
assert.ok(Array.isArray(model.subscriptions, 'subs must be an array'))
|
||||
model.subscriptions.forEach(function (sub) {
|
||||
sub(send)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// the rootId is determined to find the application root
|
||||
// on update. Since the DOM nodes change between updates,
|
||||
// we must call document.querySelector() to find the root.
|
||||
// Use different names when loading multiple choo applications
|
||||
// on the same page
|
||||
const rootId = name + '-root'
|
||||
const tree = _router(send.state().app.location, send.state(), send)
|
||||
tree.setAttribute('id', rootId)
|
||||
return tree
|
||||
|
||||
// handle an action by either reducers, effects
|
||||
// or both - return the new state when done
|
||||
// (obj, obj, fn) -> obj
|
||||
function handleAction (action, state, send) {
|
||||
var _reducers = false
|
||||
var _effects = false
|
||||
var newState = null
|
||||
var reducersCalled = false
|
||||
var effectsCalled = false
|
||||
|
||||
// validate if a namespace exists. Namespaces
|
||||
// are delimited by the first ':'. Perhaps
|
||||
// we'll allow recursive namespaces in the
|
||||
// future - who knows
|
||||
if (/:/.test(action.type)) {
|
||||
const arr = action.type.split(':')
|
||||
var ns = arr[0]
|
||||
action.type = arr[1]
|
||||
var ns = arr.shift()
|
||||
action.type = arr.join(':')
|
||||
}
|
||||
|
||||
const nsReducers = ns ? reducers[ns] : reducers
|
||||
if (nsReducers && nsReducers[action.type]) {
|
||||
const _reducers = ns ? reducers[ns] : reducers
|
||||
if (_reducers && _reducers[action.type]) {
|
||||
if (ns) {
|
||||
state[ns] = reducers[ns][action.type](action, state[ns])
|
||||
newState = state
|
||||
const newState = reducers[ns][action.type](action, state[ns])
|
||||
state[ns] = xtend(state[ns], newState)
|
||||
} else {
|
||||
newState = xtend(state, reducers[action.type](action, state))
|
||||
state = xtend(state, reducers[action.type](action, state))
|
||||
}
|
||||
_reducers = true
|
||||
reducersCalled = true
|
||||
}
|
||||
|
||||
const nsEffects = ns ? effects[ns] : effects
|
||||
if (nsEffects && nsEffects[action.type]) {
|
||||
nsEffects[action.type](action, newState || state)
|
||||
_effects = true
|
||||
const _effects = ns ? effects[ns] : effects
|
||||
if (_effects && _effects[action.type]) {
|
||||
_effects[action.type](action, state, send)
|
||||
effectsCalled = true
|
||||
}
|
||||
|
||||
if (!_reducers && !_effects) {
|
||||
if (!reducersCalled && !effectsCalled) {
|
||||
throw new Error('Could not find action ' + action.type)
|
||||
}
|
||||
|
||||
return newState || state
|
||||
return state
|
||||
}
|
||||
|
||||
// update on every change
|
||||
// update the DOM after every state mutation
|
||||
// (obj, obj) -> null
|
||||
function onchange (action, state) {
|
||||
const oldTree = document.querySelector('#' + rootId)
|
||||
const newTree = _router(state.app.location, state, send)
|
||||
@@ -116,7 +136,7 @@ function choo () {
|
||||
}
|
||||
}
|
||||
|
||||
// register all routes
|
||||
// register all routes on the router
|
||||
// [obj|fn] -> null
|
||||
function router (cb) {
|
||||
_router = sheetRouter(cb)
|
||||
@@ -136,42 +156,45 @@ function appInit (opts) {
|
||||
const model = {
|
||||
namespace: 'app',
|
||||
state: { location: document.location.href },
|
||||
reducers: { location: setLocation },
|
||||
subscriptions: []
|
||||
subscriptions: [],
|
||||
reducers: {
|
||||
// handle href links
|
||||
location: function setLocation (action, state) {
|
||||
return {
|
||||
location: action.location.replace(/#.*/, '')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.href !== false) {
|
||||
model.subscriptions.push(function (send) {
|
||||
href(function (href) {
|
||||
send('app:location', { location: href })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (opts.history !== false) {
|
||||
model.subscriptions.push(function (send) {
|
||||
history(function (href) {
|
||||
send('app:location', { location: href })
|
||||
})
|
||||
})
|
||||
}
|
||||
// enable catching <href a=""></href> links
|
||||
// enable HTML5 history API
|
||||
if (opts.history !== false) pushLocationSub(href)
|
||||
if (opts.history !== false) pushLocationSub(history)
|
||||
|
||||
return model
|
||||
|
||||
// handle href links
|
||||
function setLocation (action, state) {
|
||||
return { location: action.location.replace(/#.*/, '') }
|
||||
// create a new subscription that modifies
|
||||
// 'app:location' and push it to the subs
|
||||
// fn -> null
|
||||
function pushLocationSub (cb) {
|
||||
model.subscriptions.push(function (send) {
|
||||
cb(function (href) {
|
||||
send('app:location', { location: href })
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// compose an object conditionally
|
||||
// optionally contains a namespace
|
||||
// which is used to nest properties.
|
||||
// (str, obj, obj) -> null
|
||||
function apply (name, source, target) {
|
||||
function apply (ns, source, target) {
|
||||
Object.keys(source).forEach(function (key) {
|
||||
if (name) {
|
||||
if (!target[name]) target[name] = {}
|
||||
target[name][key] = source[key]
|
||||
target[name][key].namespace = name
|
||||
if (ns) {
|
||||
if (!target[ns]) target[ns] = {}
|
||||
target[ns][key] = source[key]
|
||||
} else target[key] = source[key]
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user