Skip to content

Commit

Permalink
feat: register callbacks on specific nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
troch committed Jun 30, 2015
1 parent 9734c8a commit 392a647
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 32 deletions.
15 changes: 12 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,18 @@
</head>

<body>
<button id="users">users</button>
<button id="users.view">users.view</button>
<button id="users.list">users.list</button>
<section>
<button id="users">users</button>
<button id="users.view">users.view</button>
<button id="users.list">users.list</button>
</section>

<section>
<button id="users">orders</button>
<button id="orders.view" params="{id: 'A0E23'}">orders.view</button>
<button id="orders.pending">orders.pending</button>
<button id="orders.completed">orders.completed</button>
</section>

<script src="jspm_packages/system.js"></script>
<script src="config.js"></script>
Expand Down
39 changes: 23 additions & 16 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,31 @@ let userRoutes = new RouteNode('users', '/users', [
new RouteNode('list', '/list')
])

let router = new Router5([
userRoutes
let ordersRoute = new RouteNode('orders', '/orders', [
new RouteNode('view', '/view/:id'),
new RouteNode('pending', '/pending'),
new RouteNode('completed', '/completed')
])

let listener = (newState, oldState) => console.log(newState, oldState)
router.addListener(listener)
let router = new Router5([
userRoutes,
ordersRoute
])

document.getElementById('users').addEventListener('click', evt => {
evt.preventDefault()
router.navigate('users')
}, false)
let listener = (newState, oldState) => {
console.log('From:', oldState)
console.log('To:', newState)
}

document.getElementById('users.view').addEventListener('click', evt => {
evt.preventDefault()
router.navigate('users.view', {id: 123})
}, false)
router.addListener(listener)
router.addNodeListener('users', function () {
console.log('node users to be re-rendered');
});

document.getElementById('users.list').addEventListener('click', evt => {
evt.preventDefault()
router.navigate('users.list')
}, false)
Array.prototype.slice.call(document.querySelectorAll('button')).forEach(button => {
button.addEventListener('click', evt => {
evt.preventDefault()
console.log(button.attributes, button.getAttribute('params'));
router.navigate(button.getAttribute('id'), JSON.parse(button.getAttribute('params') || '{}'))
}, false)
})
59 changes: 46 additions & 13 deletions modules/Router5.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,57 @@ let areStatesEqual = (state1, state2) => {
}

export default class Router5 {
constructor(routes) {
this.callbacks = []
constructor(routes, dft) {
this.callbacks = {}
this.lastStateAttempt = null
this.lastKnownState = null
this.rootNode = routes instanceof RouteNode ? routes : new RouteNode('', '', routes)
this.activeComponents = {}

window.addEventListener('popstate', evt => {
if (evt.state) return
this.lastStateAttempt = evt.state
this._invokeCallbacks(evt.state, this.lastKnownState)
this.lastKnownState = evt.state
})
}

_invokeCallbacks(newState, oldState) {
this.callbacks.forEach(cb => {
_invokeCallbacks(name, newState, oldState) {
if (!this.callbacks[name]) return
this.callbacks[name].forEach(cb => {
cb.call(this, newState, oldState)
})
}

registerComponent(name, component) {
if (this.activeComponents[name]) console.warn(`A component was alread registered for route node ${name}.`)
this.activeComponents[name] = component
}

deregisterComponent(name) {
delete this.activeComponents[name]
}

addNodeListener(name, cb) {
if (name) {
let segments = this.rootNode.getSegmentsByName(name)
if (!segments.length) console.warn(`No route found for ${name}, listener could be never called!`)
}
if (!this.callbacks[name]) this.callbacks[name] = []
this.callbacks[name].push(cb)
}

removeNodeListener(name, cb) {
if (!this.callbacks[name]) return
this.callbacks[name] = this.callbacks[name].filter(callback => callback !== cb)
}

addListener(cb) {
this.callbacks.push(cb)
this.addNodeListener('', cb)
}

removeListener(cb) {
this.callbacks = this.callbacks.filter(callback => callback !== cb)
this.removeNodeListener('', cb)
}

buildPath(route, params) {
Expand All @@ -59,6 +85,10 @@ export default class Router5 {
// Do not proceed further if states are the same and no reload
// (no desactivation and no callbacks)
if (sameStates && !opts.reload) return
// Push to history
if (!sameStates) {
window.history[opts.replace ? 'replaceState' : 'pushState'](this.lastStateAttempt, '', path)
}

if (this.lastKnownState && !sameStates) {
let i
Expand All @@ -70,15 +100,18 @@ export default class Router5 {
if (activeSegmentIds[i] !== segmentIds[i]) break
}
let segmentsToDeactivate = activeSegmentIds.slice(i)
console.log("to deactivate: ", segmentsToDeactivate)
}
// Push to history
if (!sameStates) {
window.history[opts.replace ? 'replaceState' : 'pushState'](this.lastStateAttempt, '', path)
console.info("to deactivate: ", segmentsToDeactivate)
// Invoke listeners on top node to rerender (if not root node)
if (i > 0) {
console.info("top rerender on: ", activeSegmentIds[i - 1])
this._invokeCallbacks(activeSegmentIds[i - 1], this.lastStateAttempt, this.lastKnownState)
} else {
console.info("top rerender on root")
}
}
// Update lastKnowState
this._invokeCallbacks(this.lastStateAttempt, this.lastKnownState)

this._invokeCallbacks('', this.lastStateAttempt, this.lastKnownState)
// Update lastKnowState
this.lastKnownState = this.lastStateAttempt
}
}

0 comments on commit 392a647

Please sign in to comment.