react-crossroads
Version:
Client side router for web applications built with React and utilizing the Flux architecture. The backing routing engine is CrossroadsJs.
152 lines (132 loc) • 5.05 kB
JavaScript
var React, Redirect, RouteDefinition, Routes, TYPE, factory, merge, _, _childrenValid, _hasDefault,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
__slice = [].slice;
React = require('react');
RouteDefinition = require('./RouteDefinition');
Redirect = require('./Redirect');
merge = require('react/lib/merge');
_ = require('lodash');
TYPE = 'Routes';
_childrenValid = (function() {
var VALID_TYPES, validate;
VALID_TYPES = ['Route', 'Routes', 'DefaultRoute', 'NotFoundRoute', 'Redirect'];
validate = function(props, propName, componentName) {
var child, defaultCount, err, validChild, _i, _len, _ref;
validChild = function(child) {
var _ref;
if (_ref = child.type, __indexOf.call(VALID_TYPES, _ref) < 0) {
return new Error("All children must be a proper type [Proper types: " + (JSON.stringify(VALID_TYPES)) + "]");
}
};
if (_.isArray(props[propName])) {
if (props[propName].length === 0) {
return new Error('Must provide at least one child');
}
defaultCount = 0;
_ref = props[propName];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
child = _ref[_i];
if (child == null) {
return new Error('All child elements must be defined');
}
if (child.type === 'DefaultRoute') {
defaultCount += 1;
}
err = validChild(child);
if (err != null) {
return err;
}
}
if (defaultCount > 1) {
return new Error('Only one <DefaultRoute /> is allowed per <Routes /> container');
}
} else {
err = validChild(props[propName]);
if (err != null) {
return err;
}
}
};
return RouteDefinition.PropTypes.createChainableTypeChecker(validate);
})();
_hasDefault = function(children) {
return _.any(children, function(child) {
return child.type === 'DefaultRoute';
});
};
Routes = (function(_super) {
__extends(Routes, _super);
Routes.prototype.type = TYPE;
function Routes(props, children) {
var defaultProps;
this.children = children;
defaultProps = {
handlerProps: {},
exclude: false,
children: this.children
};
this.props = merge(defaultProps, props);
this._hasDefault = _hasDefault(this.children);
this._hasPath = (this.props.path != null) || (this.props.name != null);
Routes.__super__.constructor.call(this);
}
Routes.prototype.propTypes = {
handler: RouteDefinition.PropTypes.componentClass,
path: React.PropTypes.string,
name: React.PropTypes.string,
handlerProps: React.PropTypes.object.isRequired,
children: _childrenValid.isRequired,
exclude: React.PropTypes.bool
};
Routes.prototype.register = function(parents, routePrefix, routeStore) {
var child, shouldRegister, _i, _len, _ref;
this.path = this.buildPath(this.props, routePrefix);
this.chain = __slice.call(parents).concat([this]);
_ref = this.children;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
child = _ref[_i];
child.register(this.chain, this.path, routeStore);
if (child.type === 'DefaultRoute') {
this.defaultRoute = child;
}
}
shouldRegister = !this._hasDefault;
shouldRegister = shouldRegister && this._hasPath;
shouldRegister = shouldRegister && (this.props.handler != null);
shouldRegister = shouldRegister && !this.props.exclude;
if (shouldRegister) {
return routeStore.register(this);
} else if (this._hasDefault && !routeStore.hasRoute(this.name)) {
if (this.defaultRoute.path !== this.path) {
this.redirect = new Redirect({
fromPath: this.path,
to: this.defaultRoute.name
});
this.redirect.name = this.name;
this.redirect.register(parents, routePrefix, routeStore);
return this.route = this.redirect.route;
} else {
return routeStore.registerAlias(this, this.defaultRoute);
}
}
};
Routes.prototype.makePath = function(params) {
if (this.route != null) {
return this.route.interpolate(params);
} else if (this.defaultRoute != null) {
return this.defaultRoute.makePath(params);
} else {
throw new Error('This routes container was not registered, therefore there is no path to be made from it');
}
};
return Routes;
})(RouteDefinition);
factory = function() {
var children, props;
props = arguments[0], children = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
return new Routes(props, _.flatten(children));
};
factory.type = 'Routes';
module.exports = factory;