Last active
August 29, 2015 14:23
-
-
Save peterellisjones/15106801239a4421ffc5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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