2017-03-30 12:20:57 +02:00
var documentReady = require ( 'document-ready' )
2017-04-14 17:10:21 +02:00
var nanohistory = require ( 'nanohistory' )
2017-03-21 03:00:45 +01:00
var nanorouter = require ( 'nanorouter' )
var nanomount = require ( 'nanomount' )
var nanomorph = require ( 'nanomorph' )
2017-04-14 17:10:21 +02:00
var nanohref = require ( 'nanohref' )
2017-03-21 03:00:45 +01:00
var nanoraf = require ( 'nanoraf' )
var nanobus = require ( 'nanobus' )
var assert = require ( 'assert' )
2016-05-10 23:23:33 +07:00
2017-04-02 01:19:59 +02:00
module . exports = Choo
2017-03-21 03:00:45 +01:00
2017-04-02 01:19:59 +02:00
function Choo ( opts ) {
2016-06-27 01:04:21 +02:00
opts = opts || {}
2017-03-21 03:00:45 +01:00
var routerOpts = {
default : opts . defaultRoute || '/404' ,
curry : true
2016-05-21 21:59:03 +09:00
}
2017-03-29 10:43:42 +02:00
var timingEnabled = opts . timing === undefined ? true : opts . timing
2017-03-31 22:01:58 +02:00
var hasWindow = typeof window !== 'undefined'
var hasPerformance = hasWindow && window . performance && window . performance . mark
2017-03-21 03:00:45 +01:00
var router = nanorouter ( routerOpts )
var bus = nanobus ()
var rerender = null
var tree = null
var state = {}
2016-05-11 13:51:17 +07:00
2016-06-27 01:04:21 +02:00
return {
2017-03-21 03:00:45 +01:00
toString : toString ,
use : register ,
mount : mount ,
2017-04-25 02:50:58 +02:00
router : router ,
2017-03-21 03:00:45 +01:00
route : route ,
start : start
2016-06-27 01:04:21 +02:00
}
2016-05-16 04:09:02 +07:00
2017-03-21 03:00:45 +01:00
function route ( route , handler ) {
router . on ( route , function ( params ) {
return function () {
state . params = params
return handler ( state , emit )
2016-12-11 19:35:29 +01:00
}
2017-03-21 03:00:45 +01:00
})
2016-12-11 19:35:29 +01:00
}
2017-03-21 03:00:45 +01:00
function register ( cb ) {
cb ( state , bus )
2016-12-11 19:35:29 +01:00
}
2017-03-21 03:00:45 +01:00
function start () {
2016-12-11 19:35:29 +01:00
if ( opts . history !== false ) {
2017-04-14 17:10:21 +02:00
nanohistory ( function ( href ) {
2017-03-22 20:42:53 +01:00
bus . emit ( 'pushState' )
})
2017-05-19 14:56:45 +02:00
bus . prependListener ( 'pushState' , updateHistory . bind ( null , 'push' ))
bus . prependListener ( 'replaceState' , updateHistory . bind ( null , 'replace' ))
2017-03-21 03:00:45 +01:00
if ( opts . href !== false ) {
2017-04-14 17:10:21 +02:00
nanohref ( function ( location ) {
2017-03-21 03:00:45 +01:00
var href = location . href
var currHref = window . location . href
if ( href === currHref ) return
2017-03-22 20:42:53 +01:00
bus . emit ( 'pushState' , href )
2016-12-11 19:35:29 +01:00
})
}
}
2017-05-24 13:02:33 +02:00
function updateHistory ( mode , href ) {
if ( href ) window . history [ mode + 'State' ]({}, null , href )
bus . emit ( 'render' )
setTimeout ( function () {
scrollIntoView ()
}, 0 )
}
2017-05-19 14:20:39 +02:00
rerender = nanoraf ( function () {
if ( hasPerformance && timingEnabled ) {
window . performance . mark ( 'choo:renderStart' )
}
var newTree = router ( createLocation ())
tree = nanomorph ( tree , newTree )
assert . notEqual ( tree , newTree , 'choo.start: a different node type was returned as the root node on a rerender. Make sure that the root node is always the same type to prevent the application from being unmounted.' )
if ( hasPerformance && timingEnabled ) {
window . performance . mark ( 'choo:renderEnd' )
window . performance . measure ( 'choo:render' , 'choo:renderStart' , 'choo:renderEnd' )
}
})
bus . prependListener ( 'render' , rerender )
2017-03-21 03:00:45 +01:00
documentReady ( function () {
bus . emit ( 'DOMContentLoaded' )
})
2016-12-11 19:35:29 +01:00
2017-05-19 14:20:39 +02:00
tree = router ( createLocation ())
2017-03-21 03:00:45 +01:00
return tree
}
function emit ( eventName , data ) {
bus . emit ( eventName , data )
}
function mount ( selector ) {
var newTree = start ()
documentReady ( function () {
var root = document . querySelector ( selector )
2017-04-14 17:10:21 +02:00
assert . ok ( root , 'choo.mount: could not query selector: ' + selector )
2017-03-21 03:00:45 +01:00
nanomount ( root , newTree )
tree = root
})
}
function toString ( location , _state ) {
state = _state || {}
var html = router ( location )
assert . equal ()
return html . toString ()
2016-05-11 13:51:17 +07:00
}
}
2017-03-21 03:00:45 +01:00
function scrollIntoView () {
var hash = window . location . hash
if ( hash ) {
try {
var el = document . querySelector ( hash )
if ( el ) el . scrollIntoView ( true )
} catch ( e ) {}
}
}
function createLocation () {
var pathname = window . location . pathname . replace ( /\/$/ , '' )
var hash = window . location . hash . replace ( /^#/ , '/' )
return pathname + hash
}