Created
February 17, 2015 06:21
-
-
Save lazd/fcb94fa63f3d67ca2a48 to your computer and use it in GitHub Desktop.
A super-charged Backbone router
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
| Backbone.SuperRouter = Backbone.Router.extend({ | |
| // The name of the application (used when setting title) | |
| appName: 'MyApp', | |
| // The default route | |
| homeRoute: '/', | |
| // List of URLs to avoid tracking | |
| noTrack: [], | |
| // Handle starting of backbone history | |
| start: function() { | |
| if (!this._started) { | |
| Backbone.history.start(); | |
| this._started = true; | |
| } | |
| }, | |
| stop: function() { | |
| Backbone.history.stop(); | |
| this._started = false; | |
| }, | |
| initialize: function() { | |
| // Build reverse map | |
| this.map = {}; | |
| for (var route in this.routes) { | |
| this.map[this.routes[route]] = route.replace(/\/:id/, '').replace(/:/, ''); | |
| } | |
| // Default page | |
| this.url = '/' + this.homeRoute; | |
| this.bind('all', this._handleEvent); | |
| }, | |
| /** | |
| Set the title of the page | |
| */ | |
| setTitle: function() { | |
| var newTitle = ''; | |
| // Add each part, passed as separate argument | |
| for (var i = 0; i <= arguments.length; i++) { // Iterate one past arguments length to get the last dash | |
| if (newTitle) { | |
| newTitle += ' - '; | |
| } | |
| if (arguments[i]) { | |
| newTitle += arguments[i]; | |
| } | |
| } | |
| // Throw app name on the end | |
| newTitle += this.appName; | |
| // Set the title | |
| document.title = newTitle; | |
| }, | |
| /** | |
| Overridden routing method | |
| Triggers a navigation event, can call event.preventDefault() to prevent routing | |
| */ | |
| route: function (route, name, callback) { | |
| // Reset current component | |
| vs.currentComponent = null; | |
| if (!_.isRegExp(route)) route = this._routeToRegExp(route); | |
| if (!callback) callback = this[name]; | |
| Backbone.history.route(route, _.bind(function(fragment) { | |
| // Continue to navigate | |
| var next = _.bind(function() { | |
| var args = this._extractParameters(route, fragment); | |
| if (callback) callback.apply(this, args); | |
| this.trigger.apply(this, ['route:' + name].concat(args)); | |
| Backbone.history.trigger('route', this, name, args); | |
| }, this); | |
| var canNavigate = true; | |
| var navigatingTo = window.location.hash; | |
| // Trigger an event | |
| this.trigger('navigation', { | |
| // Provide a preventDefault function to stop navigation | |
| preventDefault: function() { | |
| canNavigate = false; | |
| }, | |
| // Provide a next function to continue navigation | |
| next: _.bind(function() { | |
| // Change the hash back | |
| this.navigate(navigatingTo); | |
| // Continue to navigate | |
| next(); | |
| }, this) | |
| }); | |
| // Check if we're allowed to navigate away | |
| if (canNavigate) { | |
| // Continue to navigate | |
| next(); | |
| } | |
| else { | |
| // Navigate without trigger, changing the hash back | |
| this.navigate(this.previousHash); | |
| } | |
| }, this)); | |
| return this; | |
| }, | |
| _handleEvent: function(route) { | |
| // Only allow route events to be tracked | |
| if (route.slice(0, 5) !== 'route') | |
| return; | |
| // Get the route function name | |
| var url = route.slice(6); | |
| // Get out immediately, homepage is a redirect | |
| if (url === 'homepage') { | |
| return; | |
| } | |
| // Get the actual route | |
| url = this.map[url]; | |
| // Store previous URL | |
| this.previousHash = window.location.hash; | |
| this._storeLastPage(); | |
| this._trackPageview(url); | |
| }, | |
| redirect: function(routeHash) { | |
| // Remove the part of the history referencing the current page | |
| // Keep the same state, and just pass an empty string for title (does nothing) | |
| // This allows users to hit back and end up where they were before | |
| window.history.replaceState(window.history.state, '', routeHash); | |
| // Tell the router to navigate to the new route | |
| this.navigate(routeHash, { trigger: true }); | |
| }, | |
| navigate: function(fragment, options) { | |
| Backbone.history.navigate(fragment, options); | |
| // Manually track navigation if specified and if it's done without a trigger | |
| if (options && !options.trigger && options.track) { | |
| // Remove IDs from the end of the fragment | |
| var url = Backbone.history.fragment.replace(/\/[0-9a-f]{24}$/, ''); | |
| // Don't track the same URL twice in a row, due to a navigate call within the app | |
| if (this.url === '/' + url) { | |
| return; | |
| } | |
| this._trackPageview(url); | |
| } | |
| }, | |
| /** | |
| Load the last route viewed | |
| */ | |
| startAtLastPage: function() { | |
| if (Modernizr.localstorage && window.localStorage['lastHash']) { | |
| window.location.hash = window.localStorage['lastHash']; | |
| } | |
| }, | |
| /** | |
| Store the hash of the last route viewed | |
| */ | |
| _storeLastPage: function(url) { | |
| if (Modernizr.localstorage) { | |
| window.localStorage['lastHash'] = url || window.location.hash; | |
| } | |
| }, | |
| /** | |
| Track page views for the given URL with Google Analytics | |
| */ | |
| _trackPageview: function(url) { | |
| // Store current URL | |
| this.url = '/' + url; | |
| // Stop certain URLs from being tracked | |
| if (this.noTrack.indexOf(url) !== -1) { | |
| return; | |
| } | |
| if (url) { | |
| // Track page views with Google Analytics | |
| ga('send', 'pageview', { | |
| page: this.url, | |
| title: document.title // Capture immediately, in case this fires later and catches a customer's scene/photo name | |
| }); | |
| } | |
| }, | |
| routes: { | |
| '': 'root', | |
| 'dashboard': 'dashboard' | |
| }, | |
| root: function() { | |
| // Navigate to the home route | |
| this.navigate(this.homeRoute, { trigger: true }); | |
| }, | |
| dashboard: function() { | |
| // Do stuff | |
| } | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment