Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peterellisjones/15106801239a4421ffc5 to your computer and use it in GitHub Desktop.
Save peterellisjones/15106801239a4421ffc5 to your computer and use it in GitHub Desktop.
@Router = React.createClass
mixins: [ReactMeteor.Mixin]
propTypes:
routes: React.PropTypes.arrayOf(
React.PropTypes.shape(
path: React.PropTypes.string.isRequired
render: React.PropTypes.func.isRequired
subscriptions: React.PropTypes.arrayOf(
React.PropTypes.shape(
name: React.PropTypes.string.isRequired
subscribe: React.PropTypes.func.isRequired
resubscribe: React.PropTypes.func
sticky: React.PropTypes.bool
)
).isRequired
)
).isRequired
path: new ReactiveVar(window.location.pathname)
componentWillMount: ->
console.debug('Mounting')
Session.set('history', [window.location.pathname])
if window.Go?
throw new Error('window.Go already defined, do you have two Routers?')
window.Go = (path) =>
try
check path, String
@updateSubscriptions(path)
@path.set(path)
history = Session.get('history')
history.push(path)
Session.set('history', history)
window.history.pushState {}, document.title, path
catch error
console.error(error)
alert(error.message)
window.addEventListener 'popstate', @pathchange, false
componentWillUnmount: ->
window.removeEventListener 'popstate'
pathchange: (event) ->
@path.set(window.location.pathname)
@updateSubscriptions(path)
updateSubscriptions: (newPath) ->
console.debug('Updating subscriptions')
[newRoute, newParams] = @getRouteForPath(newPath)
if newRoute == null
throw new Error("Route not found for path: #{newPath}")
newSubscriptionHandlers = []
# cancel or keep old subsciptions
for subHandler in @state.subscriptionHandlers
duplicateSubscription = _.find(newRoute.subscriptions, (newSub) -> newSub.name == subHandler.name)
if duplicateSubscription
if duplicateSubscription.resubscribe(newParams, subHandler.params)
console.info "Cancelling subscription #{subHandler.name} due to new params - \
new params: #{JSON.stringify(newParams)}, old params: #{JSON.stringify(subHandler.params)}"
subHandler.handler.stop()
else
console.info "Keeping subscription #{subHandler.name}"
newSubscriptionHandlers.push(subHandler)
else
if subHandler.sticky
console.info "Keeping subscription #{subHandler.name} (sticky)"
else
console.info "Cancelling subscription: #{subHandler.name}"
subHandler.handler.stop()
# add new subscriptions
for sub in newRoute.subscriptions
if _.every(newSubscriptionHandlers, (newSub) -> newSub.name != sub.name)
console.info "Subscribing to #{sub.name}"
newSubscriptionHandlers.push
name: sub.name
params: newParams
handler: sub.subscribe(newParams)
sticky: sub.sticky or false
@setState({subscriptionHandlers: newSubscriptionHandlers, ready: false})
getInitialState: ->
[route, params] = @getCurrentRoute()
if route
{
subscriptionHandlers: route.subscriptions.map (sub) =>
console.info "Subscribing to #{sub.name}"
name: sub.name
params: params
handler: sub.subscribe(params)
sticky: sub.sticky
}
else
{
subscriptionHandlers: []
}
getMeteorState: ->
[route, params] = @getCurrentRoute()
{
route: route
params: params
ready: _.all @state.subscriptionHandlers, (sub) -> sub.handler.ready()
}
getQueryParamsFromLocation: ->
params = {}
query = window.location.search.replace(/^\?/, '')
for queryPart in query.split("&")
[key, value] = queryPart.split('=')
params[key] = value
params
getRouteForPath: (path) ->
for route in @props.routes
groups = _.filter route.path.split('/'), (element) -> element.match(/:[^\/]+/)
regex = new RegExp('^' + route.path.replace(/\:[^\/]+/g, '([^\\/]+)') + '(\\?.+)?$')
matches = path.match(regex)
if matches
params = @getQueryParamsFromLocation()
for group, idx in groups
name = group.replace /^:/, ''
value = matches[idx + 1]
params[name] = value
return [route, params]
return [null, {}]
getCurrentRoute: ->
@getRouteForPath @path.get()
render: ->
return <p>Loading...</p> unless @state.ready
if this.state.route == null
return <h1>404 page not found</h1>
console.debug "Rendering path `#{this.state.route.path}` with params #{JSON.stringify(this.state.params)}"
<div>
<div className="container">
{this.state.route.render(this.state.params)}
</div>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment