fuel-ui/static/vendor/custom/backbone.routefilter.js

129 lines
4.7 KiB
JavaScript

/*! backbone.routefilter - v0.2.0 - 2014-05-06
* https://github.com/boazsender/backbone.routefilter
* Copyright (c) 2014 Boaz Sender; Licensed MIT */
(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['backbone', 'underscore'], factory);
} else if (typeof exports === 'object') {
module.exports = factory(require('backbone'), require('underscore'));
} else {
factory(window.Backbone, window._);
}
})(function(Backbone, _) {
// Save a reference to the original route method to be called
// after we pave it over.
var originalRoute = Backbone.Router.prototype.route;
// Create a reusable no operation func for the case where a before
// or after filter is not set. Backbone or Underscore should have
// a global one of these in my opinion.
var nop = function(){};
// Extend the router prototype with a default before function,
// a default after function, and a pave over of _bindRoutes.
_.extend(Backbone.Router.prototype, {
// Add default before filter.
before: nop,
// Add default after filter.
after: nop,
// Pave over Backbone.Router.prototype.route, the public method used
// for adding routes to a router instance on the fly, and the
// method which backbone uses internally for binding routes to handlers
// on the Backbone.history singleton once it's instantiated.
route: function(route, name, callback) {
// If there is no callback present for this route, then set it to
// be the name that was set in the routes property of the constructor,
// or the name arguement of the route method invocation. This is what
// Backbone.Router.route already does. We need to do it again,
// because we are about to wrap the callback in a function that calls
// the before and after filters as well as the original callback that
// was passed in.
if( !callback ){
callback = this[ name ];
}
// Create a new callback to replace the original callback that calls
// the before and after filters as well as the original callback
// internally.
var wrappedCallback = _.bind( function() {
// Call the before filter and if it returns false, run the
// route's original callback, and after filter. This allows
// the user to return false from within the before filter
// to prevent the original route callback and after
// filter from running.
var callbackArgs = [ route, _.toArray(arguments) ];
var beforeCallback;
if ( _.isFunction(this.before) ) {
// If the before filter is just a single function, then call
// it with the arguments.
beforeCallback = this.before;
} else if ( typeof this.before[route] !== "undefined" ) {
// otherwise, find the appropriate callback for the route name
// and call that.
beforeCallback = this.before[route];
} else {
// otherwise, if we have a hash of routes, but no before callback
// for this route, just use a nop function.
beforeCallback = nop;
}
// If the before callback fails during its execusion (by returning)
// false, then do not proceed with the route triggering.
if ( beforeCallback.apply(this, callbackArgs) === false ) {
return;
}
// If the callback exists, then call it. This means that the before
// and after filters will be called whether or not an actual
// callback function is supplied to handle a given route.
if( callback ) {
callback.apply( this, arguments );
}
var afterCallback;
if ( _.isFunction(this.after) ) {
// If the after filter is a single funciton, then call it with
// the proper arguments.
afterCallback = this.after;
} else if ( typeof this.after[route] !== "undefined" ) {
// otherwise if we have a hash of routes, call the appropriate
// callback based on the route name.
afterCallback = this.after[route];
} else {
// otherwise, if we have a has of routes but no after callback
// for this route, just use the nop function.
afterCallback = nop;
}
// Call the after filter.
afterCallback.apply( this, callbackArgs );
}, this);
// Call our original route, replacing the callback that was originally
// passed in when Backbone.Router.route was invoked with our wrapped
// callback that calls the before and after callbacks as well as the
// original callback.
return originalRoute.call( this, route, name, wrappedCallback );
}
});
});