From 021e209ce0fbfa5fa993ad43e8167a29a759d120 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 27 Nov 2014 01:37:36 +0100 Subject: web: update dependencies --- web/src/vendor/react-router/react-router.js | 3800 ++++++--------- web/src/vendor/react/JSXTransformer.js | 4735 +++++++++++++------ web/src/vendor/react/react-with-addons.js | 6606 +++++++++++++-------------- 3 files changed, 7737 insertions(+), 7404 deletions(-) (limited to 'web/src') diff --git a/web/src/vendor/react-router/react-router.js b/web/src/vendor/react-router/react-router.js index 942a2fc7..e2836135 100644 --- a/web/src/vendor/react-router/react-router.js +++ b/web/src/vendor/react-router/react-router.js @@ -1,65 +1,61 @@ !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.ReactRouter=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o component is a special kind of that @@ -67,25 +63,28 @@ var Route = _dereq_('./Route'); * Only one such route may be used at any given level in the * route hierarchy. */ -function DefaultRoute(props) { - return Route( - merge(props, { - path: null, - isDefault: true - }) - ); -} +var DefaultRoute = React.createClass({ + + displayName: 'DefaultRoute', + + mixins: [ FakeNode ], + + propTypes: { + name: React.PropTypes.string, + path: PropTypes.falsy, + handler: React.PropTypes.func.isRequired + } + +}); module.exports = DefaultRoute; -},{"./Route":6,"react/lib/merge":44}],3:[function(_dereq_,module,exports){ +},{"../mixins/FakeNode":13,"../utils/PropTypes":21}],4:[function(_dereq_,module,exports){ var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null); -var ActiveState = _dereq_('../mixins/ActiveState'); -var transitionTo = _dereq_('../actions/LocationActions').transitionTo; -var withoutProperties = _dereq_('../utils/withoutProperties'); -var hasOwnProperty = _dereq_('../utils/hasOwnProperty'); -var makeHref = _dereq_('../utils/makeHref'); -var warning = _dereq_('react/lib/warning'); +var classSet = _dereq_('react/lib/cx'); +var assign = _dereq_('react/lib/Object.assign'); +var Navigation = _dereq_('../mixins/Navigation'); +var State = _dereq_('../mixins/State'); function isLeftClickEvent(event) { return event.button === 0; @@ -95,21 +94,6 @@ function isModifiedEvent(event) { return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey); } -/** - * DEPRECATED: A map of component props that are reserved for use by the - * router and/or React. All other props are used as params that are - * interpolated into the link's path. - */ -var RESERVED_PROPS = { - to: true, - key: true, - className: true, - activeClassName: true, - query: true, - onClick:true, - children: true // ReactChildren -}; - /** * components are used to create an element that links to a route. * When that route is active, the link gets an "active" class name (or the @@ -117,48 +101,26 @@ var RESERVED_PROPS = { * * For example, assuming you have the following route: * - * + * * * You could use the following component to link to that route: * - * + * * * In addition to params, links may pass along query string parameters * using the `query` prop. * - * + * */ var Link = React.createClass({ displayName: 'Link', - mixins: [ ActiveState ], - - statics: { - - // TODO: Deprecate passing props as params in v1.0 - getUnreservedProps: function (props) { - var props = withoutProperties(props, RESERVED_PROPS); - warning( - Object.keys(props).length === 0, - 'Passing props for params on s is deprecated, '+ - 'please use the `params` property.' - ); - return props; - }, - - /** - * Returns a hash of URL parameters to use in this 's path. - */ - getParams: function (props) { - return props.params || Link.getUnreservedProps(props); - } - - }, + mixins: [ Navigation, State ], propTypes: { - to: React.PropTypes.string.isRequired, activeClassName: React.PropTypes.string.isRequired, + to: React.PropTypes.string.isRequired, params: React.PropTypes.object, query: React.PropTypes.object, onClick: React.PropTypes.func @@ -170,17 +132,30 @@ var Link = React.createClass({ }; }, - getInitialState: function () { - return { - isActive: false - }; + handleClick: function (event) { + var allowTransition = true; + var clickResult; + + if (this.props.onClick) + clickResult = this.props.onClick(event); + + if (isModifiedEvent(event) || !isLeftClickEvent(event)) + return; + + if (clickResult === false || event.defaultPrevented === true) + allowTransition = false; + + event.preventDefault(); + + if (allowTransition) + this.transitionTo(this.props.to, this.props.params, this.props.query); }, /** * Returns the value of the "href" attribute to use on the DOM element. */ getHref: function () { - return makeHref(this.props.to, Link.getParams(this.props), this.props.query); + return this.makeHref(this.props.to, this.props.params, this.props.query); }, /** @@ -188,59 +163,23 @@ var Link = React.createClass({ * the value of the activeClassName property when this is active. */ getClassName: function () { - var className = this.props.className || ''; - - if (this.state.isActive) - return className + ' ' + this.props.activeClassName; - - return className; - }, - - componentWillReceiveProps: function (nextProps) { - var params = Link.getParams(nextProps); - - this.setState({ - isActive: Link.isActive(nextProps.to, params, nextProps.query) - }); - }, - - updateActiveState: function () { - this.setState({ - isActive: Link.isActive(this.props.to, Link.getParams(this.props), this.props.query) - }); - }, - - handleClick: function (event) { - var allowTransition = true; - var ret; - - if (this.props.onClick) - ret = this.props.onClick(event); - - if (isModifiedEvent(event) || !isLeftClickEvent(event)) - return; + var classNames = {}; - if (ret === false || event.defaultPrevented === true) - allowTransition = false; + if (this.props.className) + classNames[this.props.className] = true; - event.preventDefault(); + if (this.isActive(this.props.to, this.props.params, this.props.query)) + classNames[this.props.activeClassName] = true; - if (allowTransition) - transitionTo(this.props.to, Link.getParams(this.props), this.props.query); + return classSet(classNames); }, render: function () { - var props = { + var props = assign({}, this.props, { href: this.getHref(), className: this.getClassName(), onClick: this.handleClick - }; - - // pull in props without overriding - for (var propName in this.props) { - if (hasOwnProperty(this.props, propName) && hasOwnProperty(props, propName) === false) - props[propName] = this.props[propName]; - } + }); return React.DOM.a(props, this.props.children); } @@ -249,9 +188,10 @@ var Link = React.createClass({ module.exports = Link; -},{"../actions/LocationActions":1,"../mixins/ActiveState":15,"../utils/hasOwnProperty":24,"../utils/makeHref":25,"../utils/withoutProperties":29,"react/lib/warning":48}],4:[function(_dereq_,module,exports){ -var merge = _dereq_('react/lib/merge'); -var Route = _dereq_('./Route'); +},{"../mixins/Navigation":14,"../mixins/State":17,"react/lib/Object.assign":36,"react/lib/cx":37}],5:[function(_dereq_,module,exports){ +var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null); +var FakeNode = _dereq_('../mixins/FakeNode'); +var PropTypes = _dereq_('../utils/PropTypes'); /** * A is a special kind of that @@ -260,65 +200,51 @@ var Route = _dereq_('./Route'); * Only one such route may be used at any given level in the * route hierarchy. */ -function NotFoundRoute(props) { - return Route( - merge(props, { - path: null, - catchAll: true - }) - ); -} +var NotFoundRoute = React.createClass({ -module.exports = NotFoundRoute; + displayName: 'NotFoundRoute', -},{"./Route":6,"react/lib/merge":44}],5:[function(_dereq_,module,exports){ -var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null); -var Route = _dereq_('./Route'); + mixins: [ FakeNode ], -function createRedirectHandler(to) { - return React.createClass({ - statics: { - willTransitionTo: function (transition, params, query) { - transition.redirect(to, params, query); - } - }, + propTypes: { + name: React.PropTypes.string, + path: PropTypes.falsy, + handler: React.PropTypes.func.isRequired + } - render: function () { - return null; - } - }); -} +}); + +module.exports = NotFoundRoute; + +},{"../mixins/FakeNode":13,"../utils/PropTypes":21}],6:[function(_dereq_,module,exports){ +var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null); +var FakeNode = _dereq_('../mixins/FakeNode'); +var PropTypes = _dereq_('../utils/PropTypes'); /** * A component is a special kind of that always * redirects to another route when it matches. */ -function Redirect(props) { - return Route({ - name: props.name, - path: props.from || props.path || '*', - handler: createRedirectHandler(props.to) - }); -} +var Redirect = React.createClass({ + + displayName: 'Redirect', + + mixins: [ FakeNode ], + + propTypes: { + path: React.PropTypes.string, + from: React.PropTypes.string, // Alias for path. + to: React.PropTypes.string, + handler: PropTypes.falsy + } + +}); module.exports = Redirect; -},{"./Route":6}],6:[function(_dereq_,module,exports){ +},{"../mixins/FakeNode":13,"../utils/PropTypes":21}],7:[function(_dereq_,module,exports){ var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null); -var withoutProperties = _dereq_('../utils/withoutProperties'); - -/** - * A map of component props that are reserved for use by the - * router and/or React. All other props are considered "static" and - * are passed through to the route handler. - */ -var RESERVED_PROPS = { - handler: true, - path: true, - defaultRoute: true, - paramNames: true, - children: true // ReactChildren -}; +var FakeNode = _dereq_('../mixins/FakeNode'); /** * components specify components that are rendered to the page when the @@ -330,40 +256,29 @@ var RESERVED_PROPS = { * "active" and their components are rendered into the DOM, nested in the same * order as they are in the tree. * - * Unlike Ember, a nested route's path does not build upon that of its parents. - * This may seem like it creates more work up front in specifying URLs, but it - * has the nice benefit of decoupling nested UI from "nested" URLs. - * * The preferred way to configure a router is using JSX. The XML-like syntax is * a great way to visualize how routes are laid out in an application. * - * React.renderComponent(( - * + * var routes = [ + * * * * - * - * ), document.body); - * - * If you don't use JSX, you can also assemble a Router programmatically using - * the standard React component JavaScript API. - * - * React.renderComponent(( - * Routes({ handler: App }, - * Route({ name: 'login', handler: Login }), - * Route({ name: 'logout', handler: Logout }), - * Route({ name: 'about', handler: About }) - * ) - * ), document.body); + * + * ]; + * + * Router.run(routes, function (Handler) { + * React.render(, document.body); + * }); * * Handlers for Route components that contain children can render their active - * child route using the activeRouteHandler prop. + * child route using a element. * * var App = React.createClass({ * render: function () { * return ( *
- * {this.props.activeRouteHandler()} + * *
* ); * } @@ -373,558 +288,154 @@ var Route = React.createClass({ displayName: 'Route', - statics: { - - getUnreservedProps: function (props) { - return withoutProperties(props, RESERVED_PROPS); - }, - - }, + mixins: [ FakeNode ], propTypes: { - preserveScrollPosition: React.PropTypes.bool.isRequired, - handler: React.PropTypes.any.isRequired, + name: React.PropTypes.string, path: React.PropTypes.string, - name: React.PropTypes.string - }, - - getDefaultProps: function () { - return { - preserveScrollPosition: false - }; - }, - - render: function () { - throw new Error( - 'The component should not be rendered directly. You may be ' + - 'missing a wrapper around your list of routes.' - ); + handler: React.PropTypes.func.isRequired, + ignoreScrollBehavior: React.PropTypes.bool } }); module.exports = Route; -},{"../utils/withoutProperties":29}],7:[function(_dereq_,module,exports){ +},{"../mixins/FakeNode":13}],8:[function(_dereq_,module,exports){ var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null); -var warning = _dereq_('react/lib/warning'); -var copyProperties = _dereq_('react/lib/copyProperties'); -var Promise = _dereq_('when/lib/Promise'); -var LocationActions = _dereq_('../actions/LocationActions'); -var Route = _dereq_('../components/Route'); -var Path = _dereq_('../utils/Path'); -var Redirect = _dereq_('../utils/Redirect'); -var Transition = _dereq_('../utils/Transition'); -var DefaultLocation = _dereq_('../locations/DefaultLocation'); -var HashLocation = _dereq_('../locations/HashLocation'); -var HistoryLocation = _dereq_('../locations/HistoryLocation'); -var RefreshLocation = _dereq_('../locations/RefreshLocation'); -var ActiveStore = _dereq_('../stores/ActiveStore'); -var PathStore = _dereq_('../stores/PathStore'); -var RouteStore = _dereq_('../stores/RouteStore'); - -/** - * The ref name that can be used to reference the active route component. - */ -var REF_NAME = '__activeRoute__'; - -/** - * A hash of { name, location } pairs of all locations. - */ -var NAMED_LOCATIONS = { - hash: HashLocation, - history: HistoryLocation, - refresh: RefreshLocation -}; - -/** - * The default handler for aborted transitions. Redirects replace - * the current URL and all others roll it back. - */ -function defaultAbortedTransitionHandler(transition) { - var reason = transition.abortReason; - - if (reason instanceof Redirect) { - LocationActions.replaceWith(reason.to, reason.params, reason.query); - } else { - LocationActions.goBack(); - } -} - -/** - * The default handler for active state updates. - */ -function defaultActiveStateChangeHandler(state) { - ActiveStore.updateState(state); -} - -/** - * The default handler for errors that were thrown asynchronously - * while transitioning. The default behavior is to re-throw the - * error so that it isn't silently swallowed. - */ -function defaultTransitionErrorHandler(error) { - throw error; // This error probably originated in a transition hook. -} - -function maybeUpdateScroll(routes, rootRoute) { - if (!routes.props.preserveScrollPosition && !rootRoute.props.preserveScrollPosition) - LocationActions.updateScroll(); -} /** - * The component configures the route hierarchy and renders the - * route matching the current location when rendered into a document. - * - * See the component for more details. + * A component renders the active child route handler + * when routes are nested. */ -var Routes = React.createClass({ - - displayName: 'Routes', +var RouteHandler = React.createClass({ - propTypes: { - onAbortedTransition: React.PropTypes.func.isRequired, - onActiveStateChange: React.PropTypes.func.isRequired, - onTransitionError: React.PropTypes.func.isRequired, - preserveScrollPosition: React.PropTypes.bool, - location: function (props, propName, componentName) { - var location = props[propName]; - - if (typeof location === 'string' && !(location in NAMED_LOCATIONS)) - return new Error('Unknown location "' + location + '", see ' + componentName); - } - }, + displayName: 'RouteHandler', getDefaultProps: function () { return { - onAbortedTransition: defaultAbortedTransitionHandler, - onActiveStateChange: defaultActiveStateChangeHandler, - onTransitionError: defaultTransitionErrorHandler, - preserveScrollPosition: false, - location: DefaultLocation - }; - }, - - getInitialState: function () { - return { - routes: RouteStore.registerChildren(this.props.children, this) + ref: '__routeHandler__' }; }, - getLocation: function () { - var location = this.props.location; - - if (typeof location === 'string') - return NAMED_LOCATIONS[location]; - - return location; + contextTypes: { + getRouteAtDepth: React.PropTypes.func.isRequired, + getRouteComponents: React.PropTypes.func.isRequired, + routeHandlers: React.PropTypes.array.isRequired }, - componentWillMount: function () { - PathStore.setup(this.getLocation()); - PathStore.addChangeListener(this.handlePathChange); + childContextTypes: { + routeHandlers: React.PropTypes.array.isRequired }, - componentDidMount: function () { - this.handlePathChange(); + getChildContext: function () { + return { + routeHandlers: this.context.routeHandlers.concat([ this ]) + }; }, - componentWillUnmount: function () { - PathStore.removeChangeListener(this.handlePathChange); + getRouteDepth: function () { + return this.context.routeHandlers.length - 1; }, - handlePathChange: function () { - this.dispatch(PathStore.getCurrentPath()); + componentDidMount: function () { + this._updateRouteComponent(); }, - /** - * Performs a depth-first search for the first route in the tree that matches - * on the given path. Returns an array of all routes in the tree leading to - * the one that matched in the format { route, params } where params is an - * object that contains the URL parameters relevant to that route. Returns - * null if no route in the tree matches the path. - * - * React.renderComponent( - * - * - * - * - * - * - * ).match('/posts/123'); => [ { route: , params: {} }, - * { route: , params: { id: '123' } } ] - */ - match: function (path) { - return findMatches(Path.withoutQuery(path), this.state.routes, this.props.defaultRoute, this.props.notFoundRoute); + componentDidUpdate: function () { + this._updateRouteComponent(); }, - /** - * Performs a transition to the given path and returns a promise for the - * Transition object that was used. - * - * In order to do this, the router first determines which routes are involved - * in the transition beginning with the current route, up the route tree to - * the first parent route that is shared with the destination route, and back - * down the tree to the destination route. The willTransitionFrom static - * method is invoked on all route handlers we're transitioning away from, in - * reverse nesting order. Likewise, the willTransitionTo static method - * is invoked on all route handlers we're transitioning to. - * - * Both willTransitionFrom and willTransitionTo hooks may either abort or - * redirect the transition. If they need to resolve asynchronously, they may - * return a promise. - * - * Any error that occurs asynchronously during the transition is re-thrown in - * the top-level scope unless returnRejectedPromise is true, in which case a - * rejected promise is returned so the caller may handle the error. - * - * Note: This function does not update the URL in a browser's location bar. - * If you want to keep the URL in sync with transitions, use Router.transitionTo, - * Router.replaceWith, or Router.goBack instead. - */ - dispatch: function (path, returnRejectedPromise) { - var transition = new Transition(path); - var routes = this; - - var promise = runTransitionHooks(routes, transition).then(function (nextState) { - if (transition.isAborted) { - routes.props.onAbortedTransition(transition); - } else if (nextState) { - routes.setState(nextState); - routes.props.onActiveStateChange(nextState); - - // TODO: add functional test - var rootMatch = getRootMatch(nextState.matches); - - if (rootMatch) - maybeUpdateScroll(routes, rootMatch.route); - } - - return transition; - }); - - if (!returnRejectedPromise) { - promise = promise.then(undefined, function (error) { - // Use setTimeout to break the promise chain. - setTimeout(function () { - routes.props.onTransitionError(error); - }); - }); - } - - return promise; + _updateRouteComponent: function () { + var depth = this.getRouteDepth(); + var components = this.context.getRouteComponents(); + components[depth] = this.refs[this.props.ref]; }, render: function () { - if (!this.state.path) - return null; - - var matches = this.state.matches; - if (matches.length) { - // matches[0] corresponds to the top-most match - return matches[0].route.props.handler(computeHandlerProps(matches, this.state.activeQuery)); - } else { - return null; - } + var route = this.context.getRouteAtDepth(this.getRouteDepth()); + return route ? React.createElement(route.handler, this.props) : null; } }); -function findMatches(path, routes, defaultRoute, notFoundRoute) { - var matches = null, route, params; +module.exports = RouteHandler; - for (var i = 0, len = routes.length; i < len; ++i) { - route = routes[i]; +},{}],9:[function(_dereq_,module,exports){ +exports.DefaultRoute = _dereq_('./components/DefaultRoute'); +exports.Link = _dereq_('./components/Link'); +exports.NotFoundRoute = _dereq_('./components/NotFoundRoute'); +exports.Redirect = _dereq_('./components/Redirect'); +exports.Route = _dereq_('./components/Route'); +exports.RouteHandler = _dereq_('./components/RouteHandler'); - // Check the subtree first to find the most deeply-nested match. - matches = findMatches(path, route.props.children, route.props.defaultRoute, route.props.notFoundRoute); +exports.HashLocation = _dereq_('./locations/HashLocation'); +exports.HistoryLocation = _dereq_('./locations/HistoryLocation'); +exports.RefreshLocation = _dereq_('./locations/RefreshLocation'); - if (matches != null) { - var rootParams = getRootMatch(matches).params; - - params = route.props.paramNames.reduce(function (params, paramName) { - params[paramName] = rootParams[paramName]; - return params; - }, {}); +exports.Navigation = _dereq_('./mixins/Navigation'); +exports.State = _dereq_('./mixins/State'); - matches.unshift(makeMatch(route, params)); +exports.create = _dereq_('./utils/createRouter'); +exports.run = _dereq_('./utils/runRouter'); - return matches; - } +},{"./components/DefaultRoute":3,"./components/Link":4,"./components/NotFoundRoute":5,"./components/Redirect":6,"./components/Route":7,"./components/RouteHandler":8,"./locations/HashLocation":10,"./locations/HistoryLocation":11,"./locations/RefreshLocation":12,"./mixins/Navigation":14,"./mixins/State":17,"./utils/createRouter":24,"./utils/runRouter":28}],10:[function(_dereq_,module,exports){ +var invariant = _dereq_('react/lib/invariant'); +var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM; +var LocationActions = _dereq_('../actions/LocationActions'); +var Path = _dereq_('../utils/Path'); - // No routes in the subtree matched, so check this route. - params = Path.extractParams(route.props.path, path); +/** + * Returns the current URL path from `window.location.hash`, including query string + */ +function getHashPath() { + invariant( + canUseDOM, + 'getHashPath needs a DOM' + ); - if (params) - return [ makeMatch(route, params) ]; - } + return Path.decode( + window.location.hash.substr(1) + ); +} - // No routes matched, so try the default route if there is one. - if (defaultRoute && (params = Path.extractParams(defaultRoute.props.path, path))) - return [ makeMatch(defaultRoute, params) ]; +var _actionType; - // Last attempt: does the "not found" route match? - if (notFoundRoute && (params = Path.extractParams(notFoundRoute.props.path, path))) - return [ makeMatch(notFoundRoute, params) ]; +function ensureSlash() { + var path = getHashPath(); - return matches; -} + if (path.charAt(0) === '/') + return true; -function makeMatch(route, params) { - return { route: route, params: params }; -} + HashLocation.replace('/' + path); -function hasMatch(matches, match) { - return matches.some(function (m) { - if (m.route !== match.route) - return false; - - for (var property in m.params) { - if (m.params[property] !== match.params[property]) - return false; - } - - return true; - }); -} - -function getRootMatch(matches) { - return matches[matches.length - 1]; -} - -function updateMatchComponents(matches, refs) { - var i = 0, component; - while (component = refs[REF_NAME]) { - matches[i++].component = component; - refs = component.refs; - } -} - -/** - * Runs all transition hooks that are required to get from the current state - * to the state specified by the given transition and updates the current state - * if they all pass successfully. Returns a promise that resolves to the new - * state if it needs to be updated, or undefined if not. - */ -function runTransitionHooks(routes, transition) { - if (routes.state.path === transition.path) - return Promise.resolve(); // Nothing to do! - - var currentMatches = routes.state.matches; - var nextMatches = routes.match(transition.path); - - warning( - nextMatches, - 'No route matches path "' + transition.path + '". Make sure you have ' + - ' somewhere in your routes' - ); - - if (!nextMatches) - nextMatches = []; - - var fromMatches, toMatches; - if (currentMatches) { - updateMatchComponents(currentMatches, routes.refs); - - fromMatches = currentMatches.filter(function (match) { - return !hasMatch(nextMatches, match); - }); - - toMatches = nextMatches.filter(function (match) { - return !hasMatch(currentMatches, match); - }); - } else { - fromMatches = []; - toMatches = nextMatches; - } - - var query = Path.extractQuery(transition.path) || {}; - - return runTransitionFromHooks(fromMatches, transition).then(function () { - if (transition.isAborted) - return; // No need to continue. - - return runTransitionToHooks(toMatches, transition, query).then(function () { - if (transition.isAborted) - return; // No need to continue. - - var rootMatch = getRootMatch(nextMatches); - var params = (rootMatch && rootMatch.params) || {}; - - return { - path: transition.path, - matches: nextMatches, - activeParams: params, - activeQuery: query, - activeRoutes: nextMatches.map(function (match) { - return match.route; - }) - }; - }); - }); -} - -/** - * Calls the willTransitionFrom hook of all handlers in the given matches - * serially in reverse with the transition object and the current instance of - * the route's handler, so that the deepest nested handlers are called first. - * Returns a promise that resolves after the last handler. - */ -function runTransitionFromHooks(matches, transition) { - var promise = Promise.resolve(); - - reversedArray(matches).forEach(function (match) { - promise = promise.then(function () { - var handler = match.route.props.handler; - - if (!transition.isAborted && handler.willTransitionFrom) - return handler.willTransitionFrom(transition, match.component); - }); - }); - - return promise; + return false; } -/** - * Calls the willTransitionTo hook of all handlers in the given matches serially - * with the transition object and any params that apply to that handler. Returns - * a promise that resolves after the last handler. - */ -function runTransitionToHooks(matches, transition, query) { - var promise = Promise.resolve(); - - matches.forEach(function (match) { - promise = promise.then(function () { - var handler = match.route.props.handler; - - if (!transition.isAborted && handler.willTransitionTo) - return handler.willTransitionTo(transition, match.params, query); - }); - }); - - return promise; -} +var _changeListeners = []; -/** - * Given an array of matches as returned by findMatches, return a descriptor for - * the handler hierarchy specified by the route. - */ -function computeHandlerProps(matches, query) { - var props = { - ref: null, - key: null, - params: null, - query: null, - activeRouteHandler: returnNull +function notifyChange(type) { + var change = { + path: getHashPath(), + type: type }; - var childHandler; - reversedArray(matches).forEach(function (match) { - var route = match.route; - - props = Route.getUnreservedProps(route.props); - - props.ref = REF_NAME; - props.params = match.params; - props.query = query; - - if (route.props.addHandlerKey) - props.key = Path.injectParams(route.props.path, match.params); - - if (childHandler) { - props.activeRouteHandler = childHandler; - } else { - props.activeRouteHandler = returnNull; - } - - childHandler = function (props, addedProps) { - if (arguments.length > 2 && typeof arguments[2] !== 'undefined') - throw new Error('Passing children to a route handler is not supported'); - - return route.props.handler(copyProperties(props, addedProps)); - }.bind(this, props); + _changeListeners.forEach(function (listener) { + listener(change); }); - - return props; -} - -function returnNull() { - return null; } -function reversedArray(array) { - return array.slice(0).reverse(); -} - -module.exports = Routes; - -},{"../actions/LocationActions":1,"../components/Route":6,"../locations/DefaultLocation":10,"../locations/HashLocation":11,"../locations/HistoryLocation":12,"../locations/RefreshLocation":14,"../stores/ActiveStore":17,"../stores/PathStore":18,"../stores/RouteStore":19,"../utils/Path":20,"../utils/Redirect":21,"../utils/Transition":22,"react/lib/copyProperties":40,"react/lib/warning":48,"when/lib/Promise":49}],8:[function(_dereq_,module,exports){ -var copyProperties = _dereq_('react/lib/copyProperties'); -var Dispatcher = _dereq_('flux').Dispatcher; - -/** - * Dispatches actions that modify the URL. - */ -var LocationDispatcher = copyProperties(new Dispatcher, { +var _isListening = false; - handleViewAction: function (action) { - this.dispatch({ - source: 'VIEW_ACTION', - action: action - }); +function onHashChange() { + if (ensureSlash()) { + // If we don't have an _actionType then all we know is the hash + // changed. It was probably caused by the user clicking the Back + // button, but may have also been the Forward button or manual + // manipulation. So just guess 'pop'. + notifyChange(_actionType || LocationActions.POP); + _actionType = null; } - -}); - -module.exports = LocationDispatcher; - -},{"flux":31,"react/lib/copyProperties":40}],9:[function(_dereq_,module,exports){ -exports.goBack = _dereq_('./actions/LocationActions').goBack; -exports.replaceWith = _dereq_('./actions/LocationActions').replaceWith; -exports.transitionTo = _dereq_('./actions/LocationActions').transitionTo; - -exports.DefaultRoute = _dereq_('./components/DefaultRoute'); -exports.Link = _dereq_('./components/Link'); -exports.NotFoundRoute = _dereq_('./components/NotFoundRoute'); -exports.Redirect = _dereq_('./components/Redirect'); -exports.Route = _dereq_('./components/Route'); -exports.Routes = _dereq_('./components/Routes'); - -exports.ActiveState = _dereq_('./mixins/ActiveState'); -exports.AsyncState = _dereq_('./mixins/AsyncState'); - -exports.makeHref = _dereq_('./utils/makeHref'); - -},{"./actions/LocationActions":1,"./components/DefaultRoute":2,"./components/Link":3,"./components/NotFoundRoute":4,"./components/Redirect":5,"./components/Route":6,"./components/Routes":7,"./mixins/ActiveState":15,"./mixins/AsyncState":16,"./utils/makeHref":25}],10:[function(_dereq_,module,exports){ -module.exports = "production" === 'test' - ? _dereq_('./MemoryLocation') - : _dereq_('./HashLocation'); - -},{"./HashLocation":11,"./MemoryLocation":13}],11:[function(_dereq_,module,exports){ -var invariant = _dereq_('react/lib/invariant'); -var ExecutionEnvironment = _dereq_('react/lib/ExecutionEnvironment'); -var getWindowPath = _dereq_('../utils/getWindowPath'); - -function getHashPath() { - return window.location.hash.substr(1); -} - -function ensureSlash() { - var path = getHashPath(); - - if (path.charAt(0) === '/') - return true; - - HashLocation.replace('/' + path); - - return false; -} - -var _onChange; - -function handleHashChange() { - if (ensureSlash()) - _onChange(); } /** @@ -932,40 +443,36 @@ function handleHashChange() { */ var HashLocation = { - setup: function (onChange) { - invariant( - ExecutionEnvironment.canUseDOM, - 'You cannot use HashLocation in an environment with no DOM' - ); - - _onChange = onChange; + addChangeListener: function (listener) { + _changeListeners.push(listener); + // Do this BEFORE listening for hashchange. ensureSlash(); + if (_isListening) + return; + if (window.addEventListener) { - window.addEventListener('hashchange', handleHashChange, false); + window.addEventListener('hashchange', onHashChange, false); } else { - window.attachEvent('onhashchange', handleHashChange); + window.attachEvent('onhashchange', onHashChange); } - }, - teardown: function () { - if (window.removeEventListener) { - window.removeEventListener('hashchange', handleHashChange, false); - } else { - window.detachEvent('onhashchange', handleHashChange); - } + _isListening = true; }, push: function (path) { - window.location.hash = path; + _actionType = LocationActions.PUSH; + window.location.hash = Path.encode(path); }, replace: function (path) { - window.location.replace(getWindowPath() + '#' + path); + _actionType = LocationActions.REPLACE; + window.location.replace(window.location.pathname + '#' + Path.encode(path)); }, pop: function () { + _actionType = LocationActions.POP; window.history.back(); }, @@ -979,49 +486,73 @@ var HashLocation = { module.exports = HashLocation; -},{"../utils/getWindowPath":23,"react/lib/ExecutionEnvironment":39,"react/lib/invariant":42}],12:[function(_dereq_,module,exports){ +},{"../actions/LocationActions":1,"../utils/Path":19,"react/lib/ExecutionEnvironment":35,"react/lib/invariant":39}],11:[function(_dereq_,module,exports){ var invariant = _dereq_('react/lib/invariant'); -var ExecutionEnvironment = _dereq_('react/lib/ExecutionEnvironment'); -var getWindowPath = _dereq_('../utils/getWindowPath'); +var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM; +var LocationActions = _dereq_('../actions/LocationActions'); +var Path = _dereq_('../utils/Path'); + +/** + * Returns the current URL path from `window.location`, including query string + */ +function getWindowPath() { + invariant( + canUseDOM, + 'getWindowPath needs a DOM' + ); + + return Path.decode( + window.location.pathname + window.location.search + ); +} + +var _changeListeners = []; + +function notifyChange(type) { + var change = { + path: getWindowPath(), + type: type + }; + + _changeListeners.forEach(function (listener) { + listener(change); + }); +} -var _onChange; +var _isListening = false; + +function onPopState() { + notifyChange(LocationActions.POP); +} /** * A Location that uses HTML5 history. */ var HistoryLocation = { - setup: function (onChange) { - invariant( - ExecutionEnvironment.canUseDOM, - 'You cannot use HistoryLocation in an environment with no DOM' - ); + addChangeListener: function (listener) { + _changeListeners.push(listener); - _onChange = onChange; + if (_isListening) + return; if (window.addEventListener) { - window.addEventListener('popstate', _onChange, false); + window.addEventListener('popstate', onPopState, false); } else { - window.attachEvent('popstate', _onChange); + window.attachEvent('popstate', onPopState); } - }, - teardown: function () { - if (window.removeEventListener) { - window.removeEventListener('popstate', _onChange, false); - } else { - window.detachEvent('popstate', _onChange); - } + _isListening = true; }, push: function (path) { - window.history.pushState({ path: path }, '', path); - _onChange(); + window.history.pushState({ path: path }, '', Path.encode(path)); + notifyChange(LocationActions.PUSH); }, replace: function (path) { - window.history.replaceState({ path: path }, '', path); - _onChange(); + window.history.replaceState({ path: path }, '', Path.encode(path)); + notifyChange(LocationActions.REPLACE); }, pop: function () { @@ -1038,670 +569,390 @@ var HistoryLocation = { module.exports = HistoryLocation; -},{"../utils/getWindowPath":23,"react/lib/ExecutionEnvironment":39,"react/lib/invariant":42}],13:[function(_dereq_,module,exports){ -var warning = _dereq_('react/lib/warning'); - -var _lastPath = null; -var _currentPath = null; -var _onChange; +},{"../actions/LocationActions":1,"../utils/Path":19,"react/lib/ExecutionEnvironment":35,"react/lib/invariant":39}],12:[function(_dereq_,module,exports){ +var HistoryLocation = _dereq_('./HistoryLocation'); +var Path = _dereq_('../utils/Path'); /** - * A Location that does not require a DOM. + * A Location that uses full page refreshes. This is used as + * the fallback for HistoryLocation in browsers that do not + * support the HTML5 history API. */ -var MemoryLocation = { - - setup: function (onChange) { - _onChange = onChange; - }, +var RefreshLocation = { push: function (path) { - _lastPath = _currentPath; - _currentPath = path; - _onChange(); + window.location = Path.encode(path); }, replace: function (path) { - _currentPath = path; - _onChange(); + window.location.replace(Path.encode(path)); }, pop: function () { - warning( - _lastPath != null, - 'You cannot use MemoryLocation to go back more than once' - ); - - _currentPath = _lastPath; - _lastPath = null; - _onChange(); + window.history.back(); }, - getCurrentPath: function () { - return _currentPath || '/'; - }, + getCurrentPath: HistoryLocation.getCurrentPath, toString: function () { - return ''; + return ''; } }; -module.exports = MemoryLocation; +module.exports = RefreshLocation; -},{"react/lib/warning":48}],14:[function(_dereq_,module,exports){ +},{"../utils/Path":19,"./HistoryLocation":11}],13:[function(_dereq_,module,exports){ var invariant = _dereq_('react/lib/invariant'); -var ExecutionEnvironment = _dereq_('react/lib/ExecutionEnvironment'); -var getWindowPath = _dereq_('../utils/getWindowPath'); -/** - * A Location that uses full page refreshes. This is used as - * the fallback for HistoryLocation in browsers that do not - * support the HTML5 history API. - */ -var RefreshLocation = { +var FakeNode = { - setup: function () { + render: function () { invariant( - ExecutionEnvironment.canUseDOM, - 'You cannot use RefreshLocation in an environment with no DOM' + false, + '%s elements should not be rendered', + this.constructor.displayName ); + } + +}; + +module.exports = FakeNode; + +},{"react/lib/invariant":39}],14:[function(_dereq_,module,exports){ +var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null); + +/** + * A mixin for components that modify the URL. + * + * Example: + * + * var MyLink = React.createClass({ + * mixins: [ Router.Navigation ], + * handleClick: function (event) { + * event.preventDefault(); + * this.transitionTo('aRoute', { the: 'params' }, { the: 'query' }); + * }, + * render: function () { + * return ( + *
Click me! + * ); + * } + * }); + */ +var Navigation = { + + contextTypes: { + makePath: React.PropTypes.func.isRequired, + makeHref: React.PropTypes.func.isRequired, + transitionTo: React.PropTypes.func.isRequired, + replaceWith: React.PropTypes.func.isRequired, + goBack: React.PropTypes.func.isRequired }, - push: function (path) { - window.location = path; + /** + * Returns an absolute URL path created from the given route + * name, URL parameters, and query values. + */ + makePath: function (to, params, query) { + return this.context.makePath(to, params, query); }, - replace: function (path) { - window.location.replace(path); + /** + * Returns a string that may safely be used as the href of a + * link to the route with the given name. + */ + makeHref: function (to, params, query) { + return this.context.makeHref(to, params, query); }, - pop: function () { - window.history.back(); + /** + * Transitions to the URL specified in the arguments by pushing + * a new URL onto the history stack. + */ + transitionTo: function (to, params, query) { + this.context.transitionTo(to, params, query); }, - getCurrentPath: getWindowPath, + /** + * Transitions to the URL specified in the arguments by replacing + * the current URL in the history stack. + */ + replaceWith: function (to, params, query) { + this.context.replaceWith(to, params, query); + }, - toString: function () { - return ''; + /** + * Transitions to the previous URL. + */ + goBack: function () { + this.context.goBack(); } }; -module.exports = RefreshLocation; +module.exports = Navigation; -},{"../utils/getWindowPath":23,"react/lib/ExecutionEnvironment":39,"react/lib/invariant":42}],15:[function(_dereq_,module,exports){ -var ActiveStore = _dereq_('../stores/ActiveStore'); +},{}],15:[function(_dereq_,module,exports){ +var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null); /** - * A mixin for components that need to know about the routes, params, - * and query that are currently active. Components that use it get two - * things: - * - * 1. An `isActive` static method they can use to check if a route, - * params, and query are active. - * 2. An `updateActiveState` instance method that is called when the - * active state changes. - * - * Example: - * - * var Tab = React.createClass({ - * - * mixins: [ Router.ActiveState ], - * - * getInitialState: function () { - * return { - * isActive: false - * }; - * }, - * - * updateActiveState: function () { - * this.setState({ - * isActive: Tab.isActive(routeName, params, query) - * }) - * } - * - * }); + * Provides the router with context for Router.Navigation. */ -var ActiveState = { +var NavigationContext = { - statics: { + childContextTypes: { + makePath: React.PropTypes.func.isRequired, + makeHref: React.PropTypes.func.isRequired, + transitionTo: React.PropTypes.func.isRequired, + replaceWith: React.PropTypes.func.isRequired, + goBack: React.PropTypes.func.isRequired + }, - /** - * Returns true if the route with the given name, URL parameters, and query - * are all currently active. - */ - isActive: ActiveStore.isActive + getChildContext: function () { + return { + makePath: this.constructor.makePath, + makeHref: this.constructor.makeHref, + transitionTo: this.constructor.transitionTo, + replaceWith: this.constructor.replaceWith, + goBack: this.constructor.goBack + }; + } - }, +}; + +module.exports = NavigationContext; + +},{}],16:[function(_dereq_,module,exports){ +var invariant = _dereq_('react/lib/invariant'); +var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM; +var getWindowScrollPosition = _dereq_('../utils/getWindowScrollPosition'); + +/** + * Provides the router with the ability to manage window scroll position + * according to its scroll behavior. + */ +var Scrolling = { componentWillMount: function () { - ActiveStore.addChangeListener(this.handleActiveStateChange); + invariant( + this.getScrollBehavior() == null || canUseDOM, + 'Cannot use scroll behavior without a DOM' + ); + + this._scrollHistory = {}; }, componentDidMount: function () { - if (this.updateActiveState) - this.updateActiveState(); + this._updateScroll(); + }, + + componentWillUpdate: function () { + this._scrollHistory[this.state.path] = getWindowScrollPosition(); + }, + + componentDidUpdate: function () { + this._updateScroll(); }, componentWillUnmount: function () { - ActiveStore.removeChangeListener(this.handleActiveStateChange); + delete this._scrollHistory; + }, + + /** + * Returns the last known scroll position for the given URL path. + */ + getScrollPosition: function (path) { + return this._scrollHistory[path] || null; }, - handleActiveStateChange: function () { - if (this.isMounted() && typeof this.updateActiveState === 'function') - this.updateActiveState(); + _updateScroll: function () { + var scrollBehavior = this.getScrollBehavior(); + + if (scrollBehavior) + scrollBehavior.updateScrollPosition( + this.getScrollPosition(this.state.path), + this.state.action + ); } }; -module.exports = ActiveState; +module.exports = Scrolling; -},{"../stores/ActiveStore":17}],16:[function(_dereq_,module,exports){ +},{"../utils/getWindowScrollPosition":26,"react/lib/ExecutionEnvironment":35,"react/lib/invariant":39}],17:[function(_dereq_,module,exports){ var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null); -var resolveAsyncState = _dereq_('../utils/resolveAsyncState'); /** - * A mixin for route handler component classes that fetch at least - * part of their state asynchronously. Classes that use it should - * declare a static `getInitialAsyncState` method that fetches state - * for a component after it mounts. This function is given three - * arguments: 1) the current route params, 2) the current query and - * 3) a function that can be used to set state as it is received. - * - * Much like the familiar `getInitialState` method, `getInitialAsyncState` - * should return a hash of key/value pairs to use in the component's - * state. The difference is that the values may be promises. As these - * values resolve, the component's state is updated. You should only - * ever need to use the setState function for doing things like - * streaming data and/or updating progress. + * A mixin for components that need to know the path, routes, URL + * params and query that are currently active. * * Example: * - * var User = React.createClass({ - * - * statics: { + * var AboutLink = React.createClass({ + * mixins: [ Router.State ], + * render: function () { + * var className = this.props.className; * - * getInitialAsyncState: function (params, query, setState) { - * // Return a hash with keys named after the state variables - * // you want to set, as you normally do in getInitialState, - * // except the values may be immediate values or promises. - * // The state is automatically updated as promises resolve. - * return { - * user: getUserByID(params.userID) // may be a promise - * }; + * if (this.isActive('about')) + * className += ' is-active'; * - * // Or, use the setState function to stream data! - * var buffer = ''; - * - * return { - * - * // Same as above, the stream state variable is set to the - * // value returned by this promise when it resolves. - * stream: getStreamingData(params.userID, function (chunk) { - * buffer += chunk; - * - * // Notify of progress. - * setState({ - * streamBuffer: buffer - * }); - * }) - * - * }; - * } - * - * }, - * - * getInitialState: function () { - * return { - * user: null, // Receives a value when getUserByID resolves. - * stream: null, // Receives a value when getStreamingData resolves. - * streamBuffer: '' // Used to track data as it loads. - * }; - * }, - * - * render: function () { - * if (!this.state.user) - * return ; - * - * return ( - *
- *

Welcome {this.state.user.name}!

- *

So far, you've received {this.state.streamBuffer.length} data!

- *
- * ); + * return React.DOM.a({ className: className }, this.props.children); * } - * * }); - * - * When testing, use the `initialAsyncState` prop to simulate asynchronous - * data fetching. When this prop is present, no attempt is made to retrieve - * additional state via `getInitialAsyncState`. */ -var AsyncState = { +var State = { - propTypes: { - initialAsyncState: React.PropTypes.object - }, - - getInitialState: function () { - return this.props.initialAsyncState || null; + contextTypes: { + getCurrentPath: React.PropTypes.func.isRequired, + getCurrentRoutes: React.PropTypes.func.isRequired, + getCurrentParams: React.PropTypes.func.isRequired, + getCurrentQuery: React.PropTypes.func.isRequired, + isActive: React.PropTypes.func.isRequired }, - updateAsyncState: function (state) { - if (this.isMounted()) - this.setState(state); + /** + * Returns the current URL path. + */ + getPath: function () { + return this.context.getCurrentPath(); }, - componentDidMount: function () { - if (this.props.initialAsyncState || typeof this.constructor.getInitialAsyncState !== 'function') - return; - - resolveAsyncState( - this.constructor.getInitialAsyncState(this.props.params, this.props.query, this.updateAsyncState), - this.updateAsyncState - ); - } - -}; - -module.exports = AsyncState; - -},{"../utils/resolveAsyncState":27}],17:[function(_dereq_,module,exports){ -var EventEmitter = _dereq_('events').EventEmitter; - -var CHANGE_EVENT = 'change'; -var _events = new EventEmitter; - -_events.setMaxListeners(0); - -function notifyChange() { - _events.emit(CHANGE_EVENT); -} - -var _activeRoutes = []; -var _activeParams = {}; -var _activeQuery = {}; - -function routeIsActive(routeName) { - return _activeRoutes.some(function (route) { - return route.props.name === routeName; - }); -} - -function paramsAreActive(params) { - for (var property in params) { - if (_activeParams[property] !== String(params[property])) - return false; - } - - return true; -} - -function queryIsActive(query) { - for (var property in query) { - if (_activeQuery[property] !== String(query[property])) - return false; - } - - return true; -} - -/** - * The ActiveStore keeps track of which routes, URL and query parameters are - * currently active on a page. s subscribe to the ActiveStore to know - * whether or not they are active. - */ -var ActiveStore = { - - addChangeListener: function (listener) { - _events.on(CHANGE_EVENT, listener); + /** + * Returns an array of the routes that are currently active. + */ + getRoutes: function () { + return this.context.getCurrentRoutes(); }, - removeChangeListener: function (listener) { - _events.removeListener(CHANGE_EVENT, listener); + /** + * Returns an object of the URL params that are currently active. + */ + getParams: function () { + return this.context.getCurrentParams(); }, /** - * Updates the currently active state and notifies all listeners. - * This is automatically called by routes as they become active. + * Returns an object of the query params that are currently active. */ - updateState: function (state) { - state = state || {}; - - _activeRoutes = state.activeRoutes || []; - _activeParams = state.activeParams || {}; - _activeQuery = state.activeQuery || {}; - - notifyChange(); + getQuery: function () { + return this.context.getCurrentQuery(); }, /** - * Returns true if the route with the given name, URL parameters, and query - * are all currently active. + * A helper method to determine if a given route, params, and query + * are active. */ - isActive: function (routeName, params, query) { - var isActive = routeIsActive(routeName) && paramsAreActive(params); - - if (query) - return isActive && queryIsActive(query); - - return isActive; + isActive: function (to, params, query) { + return this.context.isActive(to, params, query); } }; -module.exports = ActiveStore; - -},{"events":30}],18:[function(_dereq_,module,exports){ -var warning = _dereq_('react/lib/warning'); -var EventEmitter = _dereq_('events').EventEmitter; -var LocationActions = _dereq_('../actions/LocationActions'); -var LocationDispatcher = _dereq_('../dispatchers/LocationDispatcher'); -var supportsHistory = _dereq_('../utils/supportsHistory'); -var HistoryLocation = _dereq_('../locations/HistoryLocation'); -var RefreshLocation = _dereq_('../locations/RefreshLocation'); +module.exports = State; -var CHANGE_EVENT = 'change'; -var _events = new EventEmitter; +},{}],18:[function(_dereq_,module,exports){ +var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null); +var assign = _dereq_('react/lib/Object.assign'); +var Path = _dereq_('../utils/Path'); -function notifyChange() { - _events.emit(CHANGE_EVENT); +function routeIsActive(activeRoutes, routeName) { + return activeRoutes.some(function (route) { + return route.name === routeName; + }); } -var _scrollPositions = {}; +function paramsAreActive(activeParams, params) { + for (var property in params) + if (String(activeParams[property]) !== String(params[property])) + return false; -function recordScrollPosition(path) { - _scrollPositions[path] = { - x: window.scrollX, - y: window.scrollY - }; + return true; } -function updateScrollPosition(path) { - var p = PathStore.getScrollPosition(path); - window.scrollTo(p.x, p.y); -} +function queryIsActive(activeQuery, query) { + for (var property in query) + if (String(activeQuery[property]) !== String(query[property])) + return false; -var _location; + return true; +} /** - * The PathStore keeps track of the current URL path and manages - * the location strategy that is used to update the URL. + * Provides the router with context for Router.State. */ -var PathStore = { - - addChangeListener: function (listener) { - _events.on(CHANGE_EVENT, listener); - }, - - removeChangeListener: function (listener) { - _events.removeListener(CHANGE_EVENT, listener); - - // Automatically teardown when the last listener is removed. - if (EventEmitter.listenerCount(_events, CHANGE_EVENT) === 0) - PathStore.teardown(); - }, - - setup: function (location) { - // When using HistoryLocation, automatically fallback - // to RefreshLocation in browsers that do not support - // the HTML5 history API. - if (location === HistoryLocation && !supportsHistory()) - location = RefreshLocation; - - if (_location == null) { - _location = location; - - if (_location && typeof _location.setup === 'function') - _location.setup(notifyChange); - } else { - warning( - _location === location, - 'Cannot use location %s, already using %s', location, _location - ); - } - }, - - teardown: function () { - _events.removeAllListeners(CHANGE_EVENT); - - if (_location && typeof _location.teardown === 'function') - _location.teardown(); - - _location = null; - }, - - /** - * Returns the location object currently in use. - */ - getLocation: function () { - return _location; - }, +var StateContext = { /** - * Returns the current URL path. + * Returns the current URL path + query string. */ getCurrentPath: function () { - return _location.getCurrentPath(); + return this.state.path; }, /** - * Returns the last known scroll position for the given path. + * Returns a read-only array of the currently active routes. */ - getScrollPosition: function (path) { - return _scrollPositions[path] || { x: 0, y: 0 }; + getCurrentRoutes: function () { + return this.state.routes.slice(0); }, - dispatchToken: LocationDispatcher.register(function (payload) { - var action = payload.action; - var currentPath = _location.getCurrentPath(); - - switch (action.type) { - case LocationActions.PUSH: - if (currentPath !== action.path) { - recordScrollPosition(currentPath); - _location.push(action.path); - } - break; - - case LocationActions.REPLACE: - if (currentPath !== action.path) { - recordScrollPosition(currentPath); - _location.replace(action.path); - } - break; - - case LocationActions.POP: - recordScrollPosition(currentPath); - _location.pop(); - break; - - case LocationActions.UPDATE_SCROLL: - updateScrollPosition(currentPath); - break; - } - }) - -}; - -module.exports = PathStore; - -},{"../actions/LocationActions":1,"../dispatchers/LocationDispatcher":8,"../locations/HistoryLocation":12,"../locations/RefreshLocation":14,"../utils/supportsHistory":28,"events":30,"react/lib/warning":48}],19:[function(_dereq_,module,exports){ -var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null); -var invariant = _dereq_('react/lib/invariant'); -var warning = _dereq_('react/lib/warning'); -var Path = _dereq_('../utils/Path'); - -var _namedRoutes = {}; - -/** - * The RouteStore contains a directory of all s in the system. It is - * used primarily for looking up routes by name so that s can use a - * route name in the "to" prop and users can use route names in `Router.transitionTo` - * and other high-level utility methods. - */ -var RouteStore = { - /** - * Removes all references to s from the store. Should only ever - * really be used in tests to clear the store between test runs. + * Returns a read-only object of the currently active URL parameters. */ - unregisterAllRoutes: function () { - _namedRoutes = {}; + getCurrentParams: function () { + return assign({}, this.state.params); }, /** - * Removes the reference to the given and all of its children - * from the store. + * Returns a read-only object of the currently active query parameters. */ - unregisterRoute: function (route) { - var props = route.props; - - if (props.name) - delete _namedRoutes[props.name]; - - React.Children.forEach(props.children, RouteStore.unregisterRoute); + getCurrentQuery: function () { + return assign({}, this.state.query); }, /** - * Registers a and all of its children with the store. Also, - * does some normalization and validation on route props. + * Returns true if the given route, params, and query are active. */ - registerRoute: function (route, parentRoute) { - // Note: parentRoute may be a _or_ a . - var props = route.props; - - invariant( - React.isValidClass(props.handler), - 'The handler for the "%s" route must be a valid React class', - props.name || props.path - ); - - var parentPath = (parentRoute && parentRoute.props.path) || '/'; - - if ((props.path || props.name) && !props.isDefault && !props.catchAll) { - var path = props.path || props.name; - - // Relative paths extend their parent. - if (!Path.isAbsolute(path)) - path = Path.join(parentPath, path); - - props.path = Path.normalize(path); - } else { - props.path = parentPath; - - if (props.catchAll) - props.path += '*'; - } - - props.paramNames = Path.extractParamNames(props.path); - - // Make sure the route's path has all params its parent needs. - if (parentRoute && Array.isArray(parentRoute.props.paramNames)) { - parentRoute.props.paramNames.forEach(function (paramName) { - invariant( - props.paramNames.indexOf(paramName) !== -1, - 'The nested route path "%s" is missing the "%s" parameter of its parent path "%s"', - props.path, paramName, parentRoute.props.path - ); - }); - } - - // Make sure the route can be looked up by s. - if (props.name) { - var existingRoute = _namedRoutes[props.name]; - - invariant( - !existingRoute || route === existingRoute, - 'You cannot use the name "%s" for more than one route', - props.name - ); - - _namedRoutes[props.name] = route; - } - - if (props.catchAll) { - invariant( - parentRoute, - ' must have a parent ' - ); - - invariant( - parentRoute.props.notFoundRoute == null, - 'You may not have more than one per ' - ); - - parentRoute.props.notFoundRoute = route; - - return null; - } - - if (props.isDefault) { - invariant( - parentRoute, - ' must have a parent ' - ); - - invariant( - parentRoute.props.defaultRoute == null, - 'You may not have more than one per ' - ); - - parentRoute.props.defaultRoute = route; - - return null; - } + isActive: function (to, params, query) { + if (Path.isAbsolute(to)) + return to === this.state.path; - // Make sure children is an array. - props.children = RouteStore.registerChildren(props.children, route); - - return route; + return routeIsActive(this.state.routes, to) && + paramsAreActive(this.state.params, params) && + (query == null || queryIsActive(this.state.query, query)); }, - /** - * Registers many children routes at once, always returning an array. - */ - registerChildren: function (children, parentRoute) { - var routes = []; - - React.Children.forEach(children, function (child) { - // Exclude s. - if (child = RouteStore.registerRoute(child, parentRoute)) - routes.push(child); - }); - - return routes; + childContextTypes: { + getCurrentPath: React.PropTypes.func.isRequired, + getCurrentRoutes: React.PropTypes.func.isRequired, + getCurrentParams: React.PropTypes.func.isRequired, + getCurrentQuery: React.PropTypes.func.isRequired, + isActive: React.PropTypes.func.isRequired }, - /** - * Returns the Route object with the given name, if one exists. - */ - getRouteByName: function (routeName) { - return _namedRoutes[routeName] || null; + getChildContext: function () { + return { + getCurrentPath: this.getCurrentPath, + getCurrentRoutes: this.getCurrentRoutes, + getCurrentParams: this.getCurrentParams, + getCurrentQuery: this.getCurrentQuery, + isActive: this.isActive + }; } }; -module.exports = RouteStore; +module.exports = StateContext; -},{"../utils/Path":20,"react/lib/invariant":42,"react/lib/warning":48}],20:[function(_dereq_,module,exports){ +},{"../utils/Path":19,"react/lib/Object.assign":36}],19:[function(_dereq_,module,exports){ var invariant = _dereq_('react/lib/invariant'); var merge = _dereq_('qs/lib/utils').merge; var qs = _dereq_('qs'); -function encodeURL(url) { - return encodeURIComponent(url).replace(/%20/g, '+'); -} - -function decodeURL(url) { - return decodeURIComponent(url.replace(/\+/g, ' ')); -} - -function encodeURLPath(path) { - return String(path).split('/').map(encodeURL).join('/'); -} - -var paramMatcher = /:([a-zA-Z_$][a-zA-Z0-9_$]*)|[*.()\[\]\\+|{}^$]/g; +var paramCompileMatcher = /:([a-zA-Z_$][a-zA-Z0-9_$]*)|[*.()\[\]\\+|{}^$]/g; +var paramInjectMatcher = /:([a-zA-Z_$][a-zA-Z0-9_$?]*[?]?)|[*]/g; +var paramInjectTrailingSlashMatcher = /\/\/\?|\/\?/g; var queryMatcher = /\?(.+)/; var _compiledPatterns = {}; @@ -1709,10 +960,10 @@ var _compiledPatterns = {}; function compilePattern(pattern) { if (!(pattern in _compiledPatterns)) { var paramNames = []; - var source = pattern.replace(paramMatcher, function (match, paramName) { + var source = pattern.replace(paramCompileMatcher, function (match, paramName) { if (paramName) { paramNames.push(paramName); - return '([^./?#]+)'; + return '([^/?#]+)'; } else if (match === '*') { paramNames.push('splat'); return '(.*?)'; @@ -1732,6 +983,20 @@ function compilePattern(pattern) { var Path = { + /** + * Safely decodes special characters in the given URL path. + */ + decode: function (path) { + return decodeURI(path.replace(/\+/g, ' ')); + }, + + /** + * Safely encodes special characters in the given URL path. + */ + encode: function (path) { + return encodeURI(path).replace(/%20/g, '+'); + }, + /** * Returns an array of the names of all parameters in the given pattern. */ @@ -1746,7 +1011,7 @@ var Path = { */ extractParams: function (pattern, path) { var object = compilePattern(pattern); - var match = decodeURL(path).match(object.matcher); + var match = path.match(object.matcher); if (!match) return null; @@ -1769,13 +1034,21 @@ var Path = { var splatIndex = 0; - return pattern.replace(paramMatcher, function (match, paramName) { + return pattern.replace(paramInjectMatcher, function (match, paramName) { paramName = paramName || 'splat'; - invariant( - params[paramName] != null, - 'Missing "' + paramName + '" parameter for path "' + pattern + '"' - ); + // If param is optional don't check for existence + if (paramName.slice(-1) !== '?') { + invariant( + params[paramName] != null, + 'Missing "' + paramName + '" parameter for path "' + pattern + '"' + ); + } else { + paramName = paramName.slice(0, -1); + + if (params[paramName] == null) + return ''; + } var segment; if (paramName === 'splat' && Array.isArray(params[paramName])) { @@ -1789,8 +1062,8 @@ var Path = { segment = params[paramName]; } - return encodeURLPath(segment); - }); + return segment; + }).replace(paramInjectTrailingSlashMatcher, '/'); }, /** @@ -1798,7 +1071,7 @@ var Path = { * in the given path, null if the path contains no query string. */ extractQuery: function (path) { - var match = decodeURL(path).match(queryMatcher); + var match = path.match(queryMatcher); return match && qs.parse(match[1]); }, @@ -1852,7 +1125,30 @@ var Path = { module.exports = Path; -},{"qs":34,"qs/lib/utils":38,"react/lib/invariant":42}],21:[function(_dereq_,module,exports){ +},{"qs":30,"qs/lib/utils":34,"react/lib/invariant":39}],20:[function(_dereq_,module,exports){ +var Promise = _dereq_('when/lib/Promise'); + +// TODO: Use process.env.NODE_ENV check + envify to enable +// when's promise monitor here when in dev. + +module.exports = Promise; + +},{"when/lib/Promise":41}],21:[function(_dereq_,module,exports){ +var PropTypes = { + + /** + * Requires that the value of a prop be falsy. + */ + falsy: function (props, propName, elementName) { + if (props[propName]) + return new Error('<' + elementName + '> may not have a "' + propName + '" prop'); + } + +}; + +module.exports = PropTypes; + +},{}],22:[function(_dereq_,module,exports){ /** * Encapsulates a redirect to the given route. */ @@ -1864,791 +1160,824 @@ function Redirect(to, params, query) { module.exports = Redirect; -},{}],22:[function(_dereq_,module,exports){ -var mixInto = _dereq_('react/lib/mixInto'); -var transitionTo = _dereq_('../actions/LocationActions').transitionTo; +},{}],23:[function(_dereq_,module,exports){ +var assign = _dereq_('react/lib/Object.assign'); +var reversedArray = _dereq_('./reversedArray'); var Redirect = _dereq_('./Redirect'); +var Promise = _dereq_('./Promise'); /** - * Encapsulates a transition to a given path. - * - * The willTransitionTo and willTransitionFrom handlers receive - * an instance of this class as their first argument. + * Runs all hook functions serially and calls callback(error) when finished. + * A hook may return a promise if it needs to execute asynchronously. */ -function Transition(path) { - this.path = path; - this.abortReason = null; - this.isAborted = false; +function runHooks(hooks, callback) { + try { + var promise = hooks.reduce(function (promise, hook) { + // The first hook to use transition.wait makes the rest + // of the transition async from that point forward. + return promise ? promise.then(hook) : hook(); + }, null); + } catch (error) { + return callback(error); // Sync error. + } + + if (promise) { + // Use setTimeout to break the promise chain. + promise.then(function () { + setTimeout(callback); + }, function (error) { + setTimeout(function () { + callback(error); + }); + }); + } else { + callback(); + } } -mixInto(Transition, { +/** + * Calls the willTransitionFrom hook of all handlers in the given matches + * serially in reverse with the transition object and the current instance of + * the route's handler, so that the deepest nested handlers are called first. + * Calls callback(error) when finished. + */ +function runTransitionFromHooks(transition, routes, components, callback) { + components = reversedArray(components); - abort: function (reason) { - this.abortReason = reason; - this.isAborted = true; - }, + var hooks = reversedArray(routes).map(function (route, index) { + return function () { + var handler = route.handler; - redirect: function (to, params, query) { - this.abort(new Redirect(to, params, query)); - }, + if (!transition.isAborted && handler.willTransitionFrom) + return handler.willTransitionFrom(transition, components[index]); - retry: function () { - transitionTo(this.path); - } + var promise = transition._promise; + transition._promise = null; -}); + return promise; + }; + }); -module.exports = Transition; + runHooks(hooks, callback); +} -},{"../actions/LocationActions":1,"./Redirect":21,"react/lib/mixInto":47}],23:[function(_dereq_,module,exports){ /** - * Returns the current URL path from `window.location`, including query string + * Calls the willTransitionTo hook of all handlers in the given matches + * serially with the transition object and any params that apply to that + * handler. Calls callback(error) when finished. */ -function getWindowPath() { - return window.location.pathname + window.location.search; -} +function runTransitionToHooks(transition, routes, params, query, callback) { + var hooks = routes.map(function (route) { + return function () { + var handler = route.handler; -module.exports = getWindowPath; + if (!transition.isAborted && handler.willTransitionTo) + handler.willTransitionTo(transition, params, query); + var promise = transition._promise; + transition._promise = null; -},{}],24:[function(_dereq_,module,exports){ -module.exports = Function.prototype.call.bind(Object.prototype.hasOwnProperty); + return promise; + }; + }); -},{}],25:[function(_dereq_,module,exports){ -var HashLocation = _dereq_('../locations/HashLocation'); -var PathStore = _dereq_('../stores/PathStore'); -var makePath = _dereq_('./makePath'); + runHooks(hooks, callback); +} /** - * Returns a string that may safely be used as the href of a - * link to the route with the given name. + * Encapsulates a transition to a given path. + * + * The willTransitionTo and willTransitionFrom handlers receive + * an instance of this class as their first argument. */ -function makeHref(to, params, query) { - var path = makePath(to, params, query); +function Transition(path, retry) { + this.path = path; + this.abortReason = null; + this.isAborted = false; + this.retry = retry.bind(this); + this._promise = null; +} - if (PathStore.getLocation() === HashLocation) - return '#' + path; +assign(Transition.prototype, { - return path; -} + abort: function (reason) { + this.abortReason = reason; + this.isAborted = true; + }, -module.exports = makeHref; + redirect: function (to, params, query) { + this.abort(new Redirect(to, params, query)); + }, + + wait: function (value) { + this._promise = Promise.resolve(value); + }, + + from: function (routes, components, callback) { + return runTransitionFromHooks(this, routes, components, callback); + }, + + to: function (routes, params, query, callback) { + return runTransitionToHooks(this, routes, params, query, callback); + } + +}); + +module.exports = Transition; -},{"../locations/HashLocation":11,"../stores/PathStore":18,"./makePath":26}],26:[function(_dereq_,module,exports){ +},{"./Promise":20,"./Redirect":22,"./reversedArray":27,"react/lib/Object.assign":36}],24:[function(_dereq_,module,exports){ +var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null); +var warning = _dereq_('react/lib/warning'); var invariant = _dereq_('react/lib/invariant'); -var RouteStore = _dereq_('../stores/RouteStore'); +var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM; +var ImitateBrowserBehavior = _dereq_('../behaviors/ImitateBrowserBehavior'); +var RouteHandler = _dereq_('../components/RouteHandler'); +var HashLocation = _dereq_('../locations/HashLocation'); +var HistoryLocation = _dereq_('../locations/HistoryLocation'); +var RefreshLocation = _dereq_('../locations/RefreshLocation'); +var NavigationContext = _dereq_('../mixins/NavigationContext'); +var StateContext = _dereq_('../mixins/StateContext'); +var Scrolling = _dereq_('../mixins/Scrolling'); +var createRoutesFromChildren = _dereq_('./createRoutesFromChildren'); +var supportsHistory = _dereq_('./supportsHistory'); +var Transition = _dereq_('./Transition'); +var PropTypes = _dereq_('./PropTypes'); +var Redirect = _dereq_('./Redirect'); var Path = _dereq_('./Path'); /** - * Returns an absolute URL path created from the given route name, URL - * parameters, and query values. + * The default location for new routers. + */ +var DEFAULT_LOCATION = canUseDOM ? HashLocation : '/'; + +/** + * The default scroll behavior for new routers. */ -function makePath(to, params, query) { - var path; - if (Path.isAbsolute(to)) { - path = Path.normalize(to); +var DEFAULT_SCROLL_BEHAVIOR = canUseDOM ? ImitateBrowserBehavior : null; + +/** + * The default error handler for new routers. + */ +function defaultErrorHandler(error) { + // Throw so we don't silently swallow async errors. + throw error; // This error probably originated in a transition hook. +} + +/** + * The default aborted transition handler for new routers. + */ +function defaultAbortHandler(abortReason, location) { + if (typeof location === 'string') + throw new Error('Unhandled aborted transition! Reason: ' + abortReason); + + if (abortReason instanceof Redirect) { + location.replace(this.makePath(abortReason.to, abortReason.params, abortReason.query)); } else { - var route = RouteStore.getRouteByName(to); + location.pop(); + } +} - invariant( - route, - 'Unable to find a route named "' + to + '". Make sure you have ' + - 'a defined somewhere in your routes' - ); +function findMatch(pathname, routes, defaultRoute, notFoundRoute) { + var match, route, params; + + for (var i = 0, len = routes.length; i < len; ++i) { + route = routes[i]; - path = route.props.path; + // Check the subtree first to find the most deeply-nested match. + match = findMatch(pathname, route.childRoutes, route.defaultRoute, route.notFoundRoute); + + if (match != null) { + match.routes.unshift(route); + return match; + } + + // No routes in the subtree matched, so check this route. + params = Path.extractParams(route.path, pathname); + + if (params) + return createMatch(route, params); } - return Path.withQuery(Path.injectParams(path, params), query); + // No routes matched, so try the default route if there is one. + if (defaultRoute && (params = Path.extractParams(defaultRoute.path, pathname))) + return createMatch(defaultRoute, params); + + // Last attempt: does the "not found" route match? + if (notFoundRoute && (params = Path.extractParams(notFoundRoute.path, pathname))) + return createMatch(notFoundRoute, params); + + return match; } -module.exports = makePath; +function createMatch(route, params) { + return { routes: [ route ], params: params }; +} -},{"../stores/RouteStore":19,"./Path":20,"react/lib/invariant":42}],27:[function(_dereq_,module,exports){ -var Promise = _dereq_('when/lib/Promise'); +function hasMatch(routes, route, prevParams, nextParams) { + return routes.some(function (r) { + if (r !== route) + return false; + + var paramNames = route.paramNames; + var paramName; + + for (var i = 0, len = paramNames.length; i < len; ++i) { + paramName = paramNames[i]; + + if (nextParams[paramName] !== prevParams[paramName]) + return false; + } + + return true; + }); +} /** - * Resolves all values in asyncState and calls the setState - * function with new state as they resolve. Returns a promise - * that resolves after all values are resolved. + * Creates and returns a new router using the given options. A router + * is a ReactComponent class that knows how to react to changes in the + * URL and keep the contents of the page in sync. + * + * Options may be any of the following: + * + * - routes (required) The route config + * - location The location to use. Defaults to HashLocation when + * the DOM is available, "/" otherwise + * - scrollBehavior The scroll behavior to use. Defaults to ImitateBrowserBehavior + * when the DOM is available, null otherwise + * - onError A function that is used to handle errors + * - onAbort A function that is used to handle aborted transitions + * + * When rendering in a server-side environment, the location should simply + * be the URL path that was used in the request, including the query string. */ -function resolveAsyncState(asyncState, setState) { - if (asyncState == null) - return Promise.resolve(); - - var keys = Object.keys(asyncState); - - return Promise.all( - keys.map(function (key) { - return Promise.resolve(asyncState[key]).then(function (value) { - var newState = {}; - newState[key] = value; - setState(newState); - }); - }) - ); -} +function createRouter(options) { + options = options || {}; -module.exports = resolveAsyncState; + if (typeof options === 'function') { + options = { routes: options }; // Router.create() + } else if (Array.isArray(options)) { + options = { routes: options }; // Router.create([ , ]) + } -},{"when/lib/Promise":49}],28:[function(_dereq_,module,exports){ -function supportsHistory() { - /*! taken from modernizr - * https://github.com/Modernizr/Modernizr/blob/master/LICENSE - * https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js - */ - var ua = navigator.userAgent; - if ((ua.indexOf('Android 2.') !== -1 || - (ua.indexOf('Android 4.0') !== -1)) && - ua.indexOf('Mobile Safari') !== -1 && - ua.indexOf('Chrome') === -1) { - return false; + var routes = []; + var namedRoutes = {}; + var components = []; + var location = options.location || DEFAULT_LOCATION; + var scrollBehavior = options.scrollBehavior || DEFAULT_SCROLL_BEHAVIOR; + var onError = options.onError || defaultErrorHandler; + var onAbort = options.onAbort || defaultAbortHandler; + var state = {}; + var nextState = {}; + + function updateState() { + state = nextState; + nextState = {}; } - return (window.history && 'pushState' in window.history); -} -module.exports = supportsHistory; + // Automatically fall back to full page refreshes in + // browsers that don't support the HTML history API. + if (location === HistoryLocation && !supportsHistory()) + location = RefreshLocation; -},{}],29:[function(_dereq_,module,exports){ -function withoutProperties(object, properties) { - var result = {}; + var router = React.createClass({ - for (var property in object) { - if (object.hasOwnProperty(property) && !properties[property]) - result[property] = object[property]; - } + displayName: 'Router', - return result; -} + mixins: [ NavigationContext, StateContext, Scrolling ], -module.exports = withoutProperties; + statics: { -},{}],30:[function(_dereq_,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; + defaultRoute: null, + notFoundRoute: null, + + /** + * Adds routes to this router from the given children object (see ReactChildren). + */ + addRoutes: function (children) { + routes.push.apply(routes, createRoutesFromChildren(children, this, namedRoutes)); + }, + + /** + * Returns an absolute URL path created from the given route + * name, URL parameters, and query. + */ + makePath: function (to, params, query) { + var path; + if (Path.isAbsolute(to)) { + path = Path.normalize(to); + } else { + var route = namedRoutes[to]; + + invariant( + route, + 'Unable to find ', + to + ); + + path = route.path; + } -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; + return Path.withQuery(Path.injectParams(path, params), query); + }, + + /** + * Returns a string that may safely be used as the href of a link + * to the route with the given name, URL parameters, and query. + */ + makeHref: function (to, params, query) { + var path = this.makePath(to, params, query); + return (location === HashLocation) ? '#' + path : path; + }, + + /** + * Transitions to the URL specified in the arguments by pushing + * a new URL onto the history stack. + */ + transitionTo: function (to, params, query) { + invariant( + typeof location !== 'string', + 'You cannot use transitionTo with a static location' + ); -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; + location.push(this.makePath(to, params, query)); + }, -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; + /** + * Transitions to the URL specified in the arguments by replacing + * the current URL in the history stack. + */ + replaceWith: function (to, params, query) { + invariant( + typeof location !== 'string', + 'You cannot use replaceWith with a static location' + ); -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; -}; + location.replace(this.makePath(to, params, query)); + }, -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; + /** + * Transitions to the previous URL. + */ + goBack: function () { + invariant( + typeof location !== 'string', + 'You cannot use goBack with a static location' + ); - if (!this._events) - this._events = {}; + location.pop(); + }, + + /** + * Performs a match of the given path against this router and returns an object with + * the { path, routes, params, query } that match. Returns null if no match can be made. + */ + match: function (path) { + return findMatch(Path.withoutQuery(path), routes, this.defaultRoute, this.notFoundRoute) || null; + }, + + /** + * Performs a transition to the given path and calls callback(error, abortReason) + * when the transition is finished. If both arguments are null the router's state + * was updated. Otherwise the transition did not complete. + * + * In a transition, a router first determines which routes are involved by beginning + * with the current route, up the route tree to the first parent route that is shared + * with the destination route, and back down the tree to the destination route. The + * willTransitionFrom hook is invoked on all route handlers we're transitioning away + * from, in reverse nesting order. Likewise, the willTransitionTo hook is invoked on + * all route handlers we're transitioning to. + * + * Both willTransitionFrom and willTransitionTo hooks may either abort or redirect the + * transition. To resolve asynchronously, they may use transition.wait(promise). If no + * hooks wait, the transition is fully synchronous. + */ + dispatch: function (path, action, callback) { + if (state.path === path) + return; // Nothing to do! + + var match = this.match(path); + + warning( + match != null, + 'No route matches path "%s". Make sure you have somewhere in your routes', + path, path + ); - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } else { - throw TypeError('Uncaught, unspecified "error" event.'); - } - return false; - } - } + if (match == null) + match = {}; - handler = this._events[type]; + var prevRoutes = state.routes || []; + var prevParams = state.params || {}; - if (isUndefined(handler)) - return false; + var nextRoutes = match.routes || []; + var nextParams = match.params || {}; + var nextQuery = Path.extractQuery(path) || {}; - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - handler.apply(this, args); - } - } else if (isObject(handler)) { - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } + var fromRoutes, toRoutes; + if (prevRoutes.length) { + fromRoutes = prevRoutes.filter(function (route) { + return !hasMatch(nextRoutes, route, prevParams, nextParams); + }); - return true; -}; + toRoutes = nextRoutes.filter(function (route) { + return !hasMatch(prevRoutes, route, prevParams, nextParams); + }); + } else { + fromRoutes = []; + toRoutes = nextRoutes; + } -EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events) - this._events = {}; - - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); - - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - var m; - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } + var transition = new Transition(path, this.replaceWith.bind(this, path)); - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } + transition.from(fromRoutes, components, function (error) { + if (error || transition.isAborted) + return callback.call(router, error, transition); - return this; -}; + transition.to(toRoutes, nextParams, nextQuery, function (error) { + if (error || transition.isAborted) + return callback.call(router, error, transition); -EventEmitter.prototype.on = EventEmitter.prototype.addListener; + nextState.path = path; + nextState.action = action; + nextState.routes = nextRoutes; + nextState.params = nextParams; + nextState.query = nextQuery; -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); + callback.call(router, null, transition); + }); + }); + }, + + /** + * Starts this router and calls callback(router, state) when the route changes. + * + * If the router's location is static (i.e. a URL path in a server environment) + * the callback is called only once. Otherwise, the location should be one of the + * Router.*Location objects (e.g. Router.HashLocation or Router.HistoryLocation). + */ + run: function (callback) { + function dispatchHandler(error, transition) { + if (error) { + onError.call(router, error); + } else if (transition.isAborted) { + onAbort.call(router, transition.abortReason, location); + } else { + callback.call(router, router, nextState); + } + } - var fired = false; + if (typeof location === 'string') { + warning( + !canUseDOM || "production" === 'test', + 'You should not use a static location in a DOM environment because ' + + 'the router will not be kept in sync with the current URL' + ); + + // Dispatch the location. + router.dispatch(location, null, dispatchHandler); + } else { + invariant( + canUseDOM, + 'You cannot use %s in a non-DOM environment', + location + ); + + // Listen for changes to the location. + function changeListener(change) { + router.dispatch(change.path, change.type, dispatchHandler); + } + + if (location.addChangeListener) + location.addChangeListener(changeListener); + + // Bootstrap using the current path. + router.dispatch(location.getCurrentPath(), null, dispatchHandler); + } + } - function g() { - this.removeListener(type, g); + }, - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } + propTypes: { + children: PropTypes.falsy + }, - g.listener = listener; - this.on(type, g); + getLocation: function () { + return location; + }, - return this; -}; + getScrollBehavior: function () { + return scrollBehavior; + }, -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; + getRouteAtDepth: function (depth) { + var routes = this.state.routes; + return routes && routes[depth]; + }, - if (!isFunction(listener)) - throw TypeError('listener must be a function'); + getRouteComponents: function () { + return components; + }, - if (!this._events || !this._events[type]) - return this; + getInitialState: function () { + updateState(); + return state; + }, - list = this._events[type]; - length = list.length; - position = -1; + componentWillReceiveProps: function () { + updateState(); + this.setState(state); + }, - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); + render: function () { + return this.getRouteAtDepth(0) ? React.createElement(RouteHandler, this.props) : null; + }, - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } + childContextTypes: { + getRouteAtDepth: React.PropTypes.func.isRequired, + getRouteComponents: React.PropTypes.func.isRequired, + routeHandlers: React.PropTypes.array.isRequired + }, + + getChildContext: function () { + return { + getRouteComponents: this.getRouteComponents, + getRouteAtDepth: this.getRouteAtDepth, + routeHandlers: [ this ] + }; } - if (position < 0) - return this; + }); - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } + if (options.routes) + router.addRoutes(options.routes); - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } + return router; +} - return this; -}; +module.exports = createRouter; -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; +},{"../behaviors/ImitateBrowserBehavior":2,"../components/RouteHandler":8,"../locations/HashLocation":10,"../locations/HistoryLocation":11,"../locations/RefreshLocation":12,"../mixins/NavigationContext":15,"../mixins/Scrolling":16,"../mixins/StateContext":18,"./Path":19,"./PropTypes":21,"./Redirect":22,"./Transition":23,"./createRoutesFromChildren":25,"./supportsHistory":29,"react/lib/ExecutionEnvironment":35,"react/lib/invariant":39,"react/lib/warning":40}],25:[function(_dereq_,module,exports){ +var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null); +var warning = _dereq_('react/lib/warning'); +var invariant = _dereq_('react/lib/invariant'); +var DefaultRoute = _dereq_('../components/DefaultRoute'); +var NotFoundRoute = _dereq_('../components/NotFoundRoute'); +var Redirect = _dereq_('../components/Redirect'); +var Route = _dereq_('../components/Route'); +var Path = _dereq_('./Path'); - if (!this._events) - return this; +var CONFIG_ELEMENT_TYPES = [ + DefaultRoute.type, + NotFoundRoute.type, + Redirect.type, + Route.type +]; - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } +function createRedirectHandler(to, _params, _query) { + return React.createClass({ + statics: { + willTransitionTo: function (transition, params, query) { + transition.redirect(to, _params || params, _query || query); + } + }, - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); + render: function () { + return null; } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } + }); +} - listeners = this._events[type]; +function checkPropTypes(componentName, propTypes, props) { + for (var propName in propTypes) { + if (propTypes.hasOwnProperty(propName)) { + var error = propTypes[propName](props, propName, componentName); - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); + if (error instanceof Error) + warning(false, error.message); + } } - delete this._events[type]; +} - return this; -}; +function createRoute(element, parentRoute, namedRoutes) { + var type = element.type; + var props = element.props; + var componentName = (type && type.displayName) || 'UnknownComponent'; -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; + invariant( + CONFIG_ELEMENT_TYPES.indexOf(type) !== -1, + 'Unrecognized route configuration element "<%s>"', + componentName + ); -EventEmitter.listenerCount = function(emitter, type) { - var ret; - if (!emitter._events || !emitter._events[type]) - ret = 0; - else if (isFunction(emitter._events[type])) - ret = 1; - else - ret = emitter._events[type].length; - return ret; -}; + if (type.propTypes) + checkPropTypes(componentName, type.propTypes, props); -function isFunction(arg) { - return typeof arg === 'function'; -} + var route = { name: props.name }; -function isNumber(arg) { - return typeof arg === 'number'; -} + if (type === Redirect.type) { + route.handler = createRedirectHandler(props.to, props.params, props.query); + props.path = props.path || props.from || '*'; + } else { + route.handler = props.handler; + } -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} + var parentPath = (parentRoute && parentRoute.path) || '/'; -function isUndefined(arg) { - return arg === void 0; -} + if ((props.path || props.name) && type !== DefaultRoute.type && type !== NotFoundRoute.type) { + var path = props.path || props.name; -},{}],31:[function(_dereq_,module,exports){ -/** - * Copyright (c) 2014, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ + // Relative paths extend their parent. + if (!Path.isAbsolute(path)) + path = Path.join(parentPath, path); -module.exports.Dispatcher = _dereq_('./lib/Dispatcher') + route.path = Path.normalize(path); + } else { + route.path = parentPath; -},{"./lib/Dispatcher":32}],32:[function(_dereq_,module,exports){ -/* - * Copyright (c) 2014, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @providesModule Dispatcher - * @typechecks - */ + if (type === NotFoundRoute.type) + route.path += '*'; + } -var invariant = _dereq_('./invariant'); + route.paramNames = Path.extractParamNames(route.path); -var _lastID = 1; -var _prefix = 'ID_'; + // Make sure the route's path has all params its parent needs. + if (parentRoute && Array.isArray(parentRoute.paramNames)) { + parentRoute.paramNames.forEach(function (paramName) { + invariant( + route.paramNames.indexOf(paramName) !== -1, + 'The nested route path "%s" is missing the "%s" parameter of its parent path "%s"', + route.path, paramName, parentRoute.path + ); + }); + } -/** - * Dispatcher is used to broadcast payloads to registered callbacks. This is - * different from generic pub-sub systems in two ways: - * - * 1) Callbacks are not subscribed to particular events. Every payload is - * dispatched to every registered callback. - * 2) Callbacks can be deferred in whole or part until other callbacks have - * been executed. - * - * For example, consider this hypothetical flight destination form, which - * selects a default city when a country is selected: - * - * var flightDispatcher = new Dispatcher(); - * - * // Keeps track of which country is selected - * var CountryStore = {country: null}; - * - * // Keeps track of which city is selected - * var CityStore = {city: null}; - * - * // Keeps track of the base flight price of the selected city - * var FlightPriceStore = {price: null} - * - * When a user changes the selected city, we dispatch the payload: - * - * flightDispatcher.dispatch({ - * actionType: 'city-update', - * selectedCity: 'paris' - * }); - * - * This payload is digested by `CityStore`: - * - * flightDispatcher.register(function(payload) { - * if (payload.actionType === 'city-update') { - * CityStore.city = payload.selectedCity; - * } - * }); - * - * When the user selects a country, we dispatch the payload: - * - * flightDispatcher.dispatch({ - * actionType: 'country-update', - * selectedCountry: 'australia' - * }); - * - * This payload is digested by both stores: - * - * CountryStore.dispatchToken = flightDispatcher.register(function(payload) { - * if (payload.actionType === 'country-update') { - * CountryStore.country = payload.selectedCountry; - * } - * }); - * - * When the callback to update `CountryStore` is registered, we save a reference - * to the returned token. Using this token with `waitFor()`, we can guarantee - * that `CountryStore` is updated before the callback that updates `CityStore` - * needs to query its data. - * - * CityStore.dispatchToken = flightDispatcher.register(function(payload) { - * if (payload.actionType === 'country-update') { - * // `CountryStore.country` may not be updated. - * flightDispatcher.waitFor([CountryStore.dispatchToken]); - * // `CountryStore.country` is now guaranteed to be updated. - * - * // Select the default city for the new country - * CityStore.city = getDefaultCityForCountry(CountryStore.country); - * } - * }); - * - * The usage of `waitFor()` can be chained, for example: - * - * FlightPriceStore.dispatchToken = - * flightDispatcher.register(function(payload) { - * switch (payload.actionType) { - * case 'country-update': - * flightDispatcher.waitFor([CityStore.dispatchToken]); - * FlightPriceStore.price = - * getFlightPriceStore(CountryStore.country, CityStore.city); - * break; - * - * case 'city-update': - * FlightPriceStore.price = - * FlightPriceStore(CountryStore.country, CityStore.city); - * break; - * } - * }); - * - * The `country-update` payload will be guaranteed to invoke the stores' - * registered callbacks in order: `CountryStore`, `CityStore`, then - * `FlightPriceStore`. - */ + // Make sure the route can be looked up by s. + if (props.name) { + invariant( + namedRoutes[props.name] == null, + 'You cannot use the name "%s" for more than one route', + props.name + ); - function Dispatcher() {"use strict"; - this.$Dispatcher_callbacks = {}; - this.$Dispatcher_isPending = {}; - this.$Dispatcher_isHandled = {}; - this.$Dispatcher_isDispatching = false; - this.$Dispatcher_pendingPayload = null; + namedRoutes[props.name] = route; } - /** - * Registers a callback to be invoked with every dispatched payload. Returns - * a token that can be used with `waitFor()`. - * - * @param {function} callback - * @return {string} - */ - Dispatcher.prototype.register=function(callback) {"use strict"; - var id = _prefix + _lastID++; - this.$Dispatcher_callbacks[id] = callback; - return id; - }; + // Handle . + if (type === NotFoundRoute.type) { + invariant( + parentRoute, + ' must have a parent ' + ); - /** - * Removes a callback based on its token. - * - * @param {string} id - */ - Dispatcher.prototype.unregister=function(id) {"use strict"; invariant( - this.$Dispatcher_callbacks[id], - 'Dispatcher.unregister(...): `%s` does not map to a registered callback.', - id + parentRoute.notFoundRoute == null, + 'You may not have more than one per ' ); - delete this.$Dispatcher_callbacks[id]; - }; - /** - * Waits for the callbacks specified to be invoked before continuing execution - * of the current callback. This method should only be used by a callback in - * response to a dispatched payload. - * - * @param {array} ids - */ - Dispatcher.prototype.waitFor=function(ids) {"use strict"; + parentRoute.notFoundRoute = route; + + return null; + } + + // Handle . + if (type === DefaultRoute.type) { invariant( - this.$Dispatcher_isDispatching, - 'Dispatcher.waitFor(...): Must be invoked while dispatching.' + parentRoute, + ' must have a parent ' ); - for (var ii = 0; ii < ids.length; ii++) { - var id = ids[ii]; - if (this.$Dispatcher_isPending[id]) { - invariant( - this.$Dispatcher_isHandled[id], - 'Dispatcher.waitFor(...): Circular dependency detected while ' + - 'waiting for `%s`.', - id - ); - continue; - } - invariant( - this.$Dispatcher_callbacks[id], - 'Dispatcher.waitFor(...): `%s` does not map to a registered callback.', - id - ); - this.$Dispatcher_invokeCallback(id); - } - }; - /** - * Dispatches a payload to all registered callbacks. - * - * @param {object} payload - */ - Dispatcher.prototype.dispatch=function(payload) {"use strict"; invariant( - !this.$Dispatcher_isDispatching, - 'Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.' + parentRoute.defaultRoute == null, + 'You may not have more than one per ' ); - this.$Dispatcher_startDispatching(payload); - try { - for (var id in this.$Dispatcher_callbacks) { - if (this.$Dispatcher_isPending[id]) { - continue; - } - this.$Dispatcher_invokeCallback(id); - } - } finally { - this.$Dispatcher_stopDispatching(); - } - }; - /** - * Is this Dispatcher currently dispatching. - * - * @return {boolean} - */ - Dispatcher.prototype.isDispatching=function() {"use strict"; - return this.$Dispatcher_isDispatching; - }; + parentRoute.defaultRoute = route; - /** - * Call the callback stored with the given id. Also do some internal - * bookkeeping. - * - * @param {string} id - * @internal - */ - Dispatcher.prototype.$Dispatcher_invokeCallback=function(id) {"use strict"; - this.$Dispatcher_isPending[id] = true; - this.$Dispatcher_callbacks[id](this.$Dispatcher_pendingPayload); - this.$Dispatcher_isHandled[id] = true; - }; + return null; + } - /** - * Set up bookkeeping needed when dispatching. - * - * @param {object} payload - * @internal - */ - Dispatcher.prototype.$Dispatcher_startDispatching=function(payload) {"use strict"; - for (var id in this.$Dispatcher_callbacks) { - this.$Dispatcher_isPending[id] = false; - this.$Dispatcher_isHandled[id] = false; - } - this.$Dispatcher_pendingPayload = payload; - this.$Dispatcher_isDispatching = true; - }; + route.childRoutes = createRoutesFromChildren(props.children, route, namedRoutes); - /** - * Clear bookkeeping used for dispatching. - * - * @internal - */ - Dispatcher.prototype.$Dispatcher_stopDispatching=function() {"use strict"; - this.$Dispatcher_pendingPayload = null; - this.$Dispatcher_isDispatching = false; - }; + return route; +} + +/** + * Creates and returns an array of route objects from the given ReactChildren. + */ +function createRoutesFromChildren(children, parentRoute, namedRoutes) { + var routes = []; + React.Children.forEach(children, function (child) { + // Exclude s and s. + if (child = createRoute(child, parentRoute, namedRoutes)) + routes.push(child); + }); + + return routes; +} -module.exports = Dispatcher; +module.exports = createRoutesFromChildren; + +},{"../components/DefaultRoute":3,"../components/NotFoundRoute":5,"../components/Redirect":6,"../components/Route":7,"./Path":19,"react/lib/invariant":39,"react/lib/warning":40}],26:[function(_dereq_,module,exports){ +var invariant = _dereq_('react/lib/invariant'); +var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM; -},{"./invariant":33}],33:[function(_dereq_,module,exports){ /** - * Copyright (c) 2014, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @providesModule invariant + * Returns the current scroll position of the window as { x, y }. */ +function getWindowScrollPosition() { + invariant( + canUseDOM, + 'Cannot get current scroll position without a DOM' + ); -"use strict"; + return { + x: window.scrollX, + y: window.scrollY + }; +} + +module.exports = getWindowScrollPosition; + +},{"react/lib/ExecutionEnvironment":35,"react/lib/invariant":39}],27:[function(_dereq_,module,exports){ +function reversedArray(array) { + return array.slice(0).reverse(); +} + +module.exports = reversedArray; + +},{}],28:[function(_dereq_,module,exports){ +var createRouter = _dereq_('./createRouter'); /** - * Use invariant() to assert state which your program assumes to be true. + * A high-level convenience method that creates, configures, and + * runs a router in one shot. The method signature is: * - * Provide sprintf-style format (only %s is supported) and arguments - * to provide information about what broke and what you were - * expecting. + * Router.run(routes[, location ], callback); + * + * Using `window.location.hash` to manage the URL, you could do: + * + * Router.run(routes, function (Handler) { + * React.render(, document.body); + * }); + * + * Using HTML5 history and a custom "cursor" prop: + * + * Router.run(routes, Router.HistoryLocation, function (Handler) { + * React.render(, document.body); + * }); + * + * Returns the newly created router. + * + * Note: If you need to specify further options for your router such + * as error/abort handling or custom scroll behavior, use Router.create + * instead. * - * The invariant message will be stripped in production, but the invariant - * will remain to ensure logic does not differ in production. + * var router = Router.create(options); + * router.run(function (Handler) { + * // ... + * }); */ - -var invariant = function(condition, format, a, b, c, d, e, f) { - if (false) { - if (format === undefined) { - throw new Error('invariant requires an error message argument'); - } +function runRouter(routes, location, callback) { + if (typeof location === 'function') { + callback = location; + location = null; } - if (!condition) { - var error; - if (format === undefined) { - error = new Error( - 'Minified exception occurred; use the non-minified dev environment ' + - 'for the full error message and additional helpful warnings.' - ); - } else { - var args = [a, b, c, d, e, f]; - var argIndex = 0; - error = new Error( - 'Invariant Violation: ' + - format.replace(/%s/g, function() { return args[argIndex++]; }) - ); - } + var router = createRouter({ + routes: routes, + location: location + }); - error.framesToPop = 1; // we don't care about invariant's own frame - throw error; + router.run(callback); + + return router; +} + +module.exports = runRouter; + +},{"./createRouter":24}],29:[function(_dereq_,module,exports){ +function supportsHistory() { + /*! taken from modernizr + * https://github.com/Modernizr/Modernizr/blob/master/LICENSE + * https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js + */ + var ua = navigator.userAgent; + if ((ua.indexOf('Android 2.') !== -1 || + (ua.indexOf('Android 4.0') !== -1)) && + ua.indexOf('Mobile Safari') !== -1 && + ua.indexOf('Chrome') === -1) { + return false; } -}; + return (window.history && 'pushState' in window.history); +} -module.exports = invariant; +module.exports = supportsHistory; -},{}],34:[function(_dereq_,module,exports){ +},{}],30:[function(_dereq_,module,exports){ module.exports = _dereq_('./lib'); -},{"./lib":35}],35:[function(_dereq_,module,exports){ +},{"./lib":31}],31:[function(_dereq_,module,exports){ // Load modules var Stringify = _dereq_('./stringify'); @@ -2665,7 +1994,7 @@ module.exports = { parse: Parse }; -},{"./parse":36,"./stringify":37}],36:[function(_dereq_,module,exports){ +},{"./parse":32,"./stringify":33}],32:[function(_dereq_,module,exports){ // Load modules var Utils = _dereq_('./utils'); @@ -2821,7 +2150,7 @@ module.exports = function (str, options) { return Utils.compact(obj); }; -},{"./utils":38}],37:[function(_dereq_,module,exports){ +},{"./utils":34}],33:[function(_dereq_,module,exports){ // Load modules var Utils = _dereq_('./utils'); @@ -2881,7 +2210,7 @@ module.exports = function (obj, options) { return keys.join(delimiter); }; -},{"./utils":38}],38:[function(_dereq_,module,exports){ +},{"./utils":34}],34:[function(_dereq_,module,exports){ // Load modules @@ -3022,21 +2351,14 @@ exports.isBuffer = function (obj) { } }; -},{}],39:[function(_dereq_,module,exports){ +},{}],35:[function(_dereq_,module,exports){ /** - * Copyright 2013-2014 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 + * Copyright 2013-2014, Facebook, Inc. + * All rights reserved. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule ExecutionEnvironment */ @@ -3074,83 +2396,104 @@ var ExecutionEnvironment = { module.exports = ExecutionEnvironment; -},{}],40:[function(_dereq_,module,exports){ +},{}],36:[function(_dereq_,module,exports){ /** - * Copyright 2013-2014 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 + * Copyright 2014, Facebook, Inc. + * All rights reserved. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. * - * @providesModule copyProperties + * @providesModule Object.assign */ -/** - * Copy properties from one or more objects (up to 5) into the first object. - * This is a shallow copy. It mutates the first object and also returns it. - * - * NOTE: `arguments` has a very significant performance penalty, which is why - * we don't support unlimited arguments. - */ -function copyProperties(obj, a, b, c, d, e, f) { - obj = obj || {}; +// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign - if ("production" !== "production") { - if (f) { - throw new Error('Too many arguments passed to copyProperties'); - } +function assign(target, sources) { + if (target == null) { + throw new TypeError('Object.assign target cannot be null or undefined'); } - var args = [a, b, c, d, e]; - var ii = 0, v; - while (args[ii]) { - v = args[ii++]; - for (var k in v) { - obj[k] = v[k]; + var to = Object(target); + var hasOwnProperty = Object.prototype.hasOwnProperty; + + for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) { + var nextSource = arguments[nextIndex]; + if (nextSource == null) { + continue; } - // IE ignores toString in object iteration.. See: - // webreflection.blogspot.com/2007/07/quick-fix-internet-explorer-and.html - if (v.hasOwnProperty && v.hasOwnProperty('toString') && - (typeof v.toString != 'undefined') && (obj.toString !== v.toString)) { - obj.toString = v.toString; + var from = Object(nextSource); + + // We don't currently support accessors nor proxies. Therefore this + // copy cannot throw. If we ever supported this then we must handle + // exceptions and side-effects. We don't support symbols so they won't + // be transferred. + + for (var key in from) { + if (hasOwnProperty.call(from, key)) { + to[key] = from[key]; + } } } - return obj; -} + return to; +}; -module.exports = copyProperties; +module.exports = assign; -},{}],41:[function(_dereq_,module,exports){ +},{}],37:[function(_dereq_,module,exports){ /** - * Copyright 2013-2014 Facebook, Inc. + * Copyright 2013-2014, Facebook, Inc. + * All rights reserved. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. * - * http://www.apache.org/licenses/LICENSE-2.0 + * @providesModule cx + */ + +/** + * This function is used to mark string literals representing CSS class names + * so that they can be transformed statically. This allows for modularization + * and minification of CSS class names. + * + * In static_upstream, this function is actually implemented, but it should + * eventually be replaced with something more descriptive, and the transform + * that is used in the main stack should be ported for use elsewhere. + * + * @param string|object className to modularize, or an object of key/values. + * In the object case, the values are conditions that + * determine if the className keys should be included. + * @param [string ...] Variable list of classNames in the string case. + * @return string Renderable space-separated CSS className. + */ +function cx(classNames) { + if (typeof classNames == 'object') { + return Object.keys(classNames).filter(function(className) { + return classNames[className]; + }).join(' '); + } else { + return Array.prototype.join.call(arguments, ' '); + } +} + +module.exports = cx; + +},{}],38:[function(_dereq_,module,exports){ +/** + * Copyright 2013-2014, Facebook, Inc. + * All rights reserved. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule emptyFunction */ -var copyProperties = _dereq_("./copyProperties"); - function makeEmptyFunction(arg) { return function() { return arg; @@ -3164,32 +2507,23 @@ function makeEmptyFunction(arg) { */ function emptyFunction() {} -copyProperties(emptyFunction, { - thatReturns: makeEmptyFunction, - thatReturnsFalse: makeEmptyFunction(false), - thatReturnsTrue: makeEmptyFunction(true), - thatReturnsNull: makeEmptyFunction(null), - thatReturnsThis: function() { return this; }, - thatReturnsArgument: function(arg) { return arg; } -}); +emptyFunction.thatReturns = makeEmptyFunction; +emptyFunction.thatReturnsFalse = makeEmptyFunction(false); +emptyFunction.thatReturnsTrue = makeEmptyFunction(true); +emptyFunction.thatReturnsNull = makeEmptyFunction(null); +emptyFunction.thatReturnsThis = function() { return this; }; +emptyFunction.thatReturnsArgument = function(arg) { return arg; }; module.exports = emptyFunction; -},{"./copyProperties":40}],42:[function(_dereq_,module,exports){ +},{}],39:[function(_dereq_,module,exports){ /** - * Copyright 2013-2014 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 + * Copyright 2013-2014, Facebook, Inc. + * All rights reserved. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule invariant */ @@ -3237,353 +2571,14 @@ var invariant = function(condition, format, a, b, c, d, e, f) { module.exports = invariant; -},{}],43:[function(_dereq_,module,exports){ -/** - * Copyright 2013-2014 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * @providesModule keyMirror - * @typechecks static-only - */ - -"use strict"; - -var invariant = _dereq_("./invariant"); - -/** - * Constructs an enumeration with keys equal to their value. - * - * For example: - * - * var COLORS = keyMirror({blue: null, red: null}); - * var myColor = COLORS.blue; - * var isColorValid = !!COLORS[myColor]; - * - * The last line could not be performed if the values of the generated enum were - * not equal to their keys. - * - * Input: {key1: val1, key2: val2} - * Output: {key1: key1, key2: key2} - * - * @param {object} obj - * @return {object} - */ -var keyMirror = function(obj) { - var ret = {}; - var key; - ("production" !== "production" ? invariant( - obj instanceof Object && !Array.isArray(obj), - 'keyMirror(...): Argument must be an object.' - ) : invariant(obj instanceof Object && !Array.isArray(obj))); - for (key in obj) { - if (!obj.hasOwnProperty(key)) { - continue; - } - ret[key] = key; - } - return ret; -}; - -module.exports = keyMirror; - -},{"./invariant":42}],44:[function(_dereq_,module,exports){ -/** - * Copyright 2013-2014 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * @providesModule merge - */ - -"use strict"; - -var mergeInto = _dereq_("./mergeInto"); - -/** - * Shallow merges two structures into a return value, without mutating either. - * - * @param {?object} one Optional object with properties to merge from. - * @param {?object} two Optional object with properties to merge from. - * @return {object} The shallow extension of one by two. - */ -var merge = function(one, two) { - var result = {}; - mergeInto(result, one); - mergeInto(result, two); - return result; -}; - -module.exports = merge; - -},{"./mergeInto":46}],45:[function(_dereq_,module,exports){ -/** - * Copyright 2013-2014 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * @providesModule mergeHelpers - * - * requiresPolyfills: Array.isArray - */ - -"use strict"; - -var invariant = _dereq_("./invariant"); -var keyMirror = _dereq_("./keyMirror"); - -/** - * Maximum number of levels to traverse. Will catch circular structures. - * @const - */ -var MAX_MERGE_DEPTH = 36; - -/** - * We won't worry about edge cases like new String('x') or new Boolean(true). - * Functions are considered terminals, and arrays are not. - * @param {*} o The item/object/value to test. - * @return {boolean} true iff the argument is a terminal. - */ -var isTerminal = function(o) { - return typeof o !== 'object' || o === null; -}; - -var mergeHelpers = { - - MAX_MERGE_DEPTH: MAX_MERGE_DEPTH, - - isTerminal: isTerminal, - - /** - * Converts null/undefined values into empty object. - * - * @param {?Object=} arg Argument to be normalized (nullable optional) - * @return {!Object} - */ - normalizeMergeArg: function(arg) { - return arg === undefined || arg === null ? {} : arg; - }, - - /** - * If merging Arrays, a merge strategy *must* be supplied. If not, it is - * likely the caller's fault. If this function is ever called with anything - * but `one` and `two` being `Array`s, it is the fault of the merge utilities. - * - * @param {*} one Array to merge into. - * @param {*} two Array to merge from. - */ - checkMergeArrayArgs: function(one, two) { - ("production" !== "production" ? invariant( - Array.isArray(one) && Array.isArray(two), - 'Tried to merge arrays, instead got %s and %s.', - one, - two - ) : invariant(Array.isArray(one) && Array.isArray(two))); - }, - - /** - * @param {*} one Object to merge into. - * @param {*} two Object to merge from. - */ - checkMergeObjectArgs: function(one, two) { - mergeHelpers.checkMergeObjectArg(one); - mergeHelpers.checkMergeObjectArg(two); - }, - - /** - * @param {*} arg - */ - checkMergeObjectArg: function(arg) { - ("production" !== "production" ? invariant( - !isTerminal(arg) && !Array.isArray(arg), - 'Tried to merge an object, instead got %s.', - arg - ) : invariant(!isTerminal(arg) && !Array.isArray(arg))); - }, - - /** - * @param {*} arg - */ - checkMergeIntoObjectArg: function(arg) { - ("production" !== "production" ? invariant( - (!isTerminal(arg) || typeof arg === 'function') && !Array.isArray(arg), - 'Tried to merge into an object, instead got %s.', - arg - ) : invariant((!isTerminal(arg) || typeof arg === 'function') && !Array.isArray(arg))); - }, - - /** - * Checks that a merge was not given a circular object or an object that had - * too great of depth. - * - * @param {number} Level of recursion to validate against maximum. - */ - checkMergeLevel: function(level) { - ("production" !== "production" ? invariant( - level < MAX_MERGE_DEPTH, - 'Maximum deep merge depth exceeded. You may be attempting to merge ' + - 'circular structures in an unsupported way.' - ) : invariant(level < MAX_MERGE_DEPTH)); - }, - - /** - * Checks that the supplied merge strategy is valid. - * - * @param {string} Array merge strategy. - */ - checkArrayStrategy: function(strategy) { - ("production" !== "production" ? invariant( - strategy === undefined || strategy in mergeHelpers.ArrayStrategies, - 'You must provide an array strategy to deep merge functions to ' + - 'instruct the deep merge how to resolve merging two arrays.' - ) : invariant(strategy === undefined || strategy in mergeHelpers.ArrayStrategies)); - }, - - /** - * Set of possible behaviors of merge algorithms when encountering two Arrays - * that must be merged together. - * - `clobber`: The left `Array` is ignored. - * - `indexByIndex`: The result is achieved by recursively deep merging at - * each index. (not yet supported.) - */ - ArrayStrategies: keyMirror({ - Clobber: true, - IndexByIndex: true - }) - -}; - -module.exports = mergeHelpers; - -},{"./invariant":42,"./keyMirror":43}],46:[function(_dereq_,module,exports){ -/** - * Copyright 2013-2014 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * @providesModule mergeInto - * @typechecks static-only - */ - -"use strict"; - -var mergeHelpers = _dereq_("./mergeHelpers"); - -var checkMergeObjectArg = mergeHelpers.checkMergeObjectArg; -var checkMergeIntoObjectArg = mergeHelpers.checkMergeIntoObjectArg; - -/** - * Shallow merges two structures by mutating the first parameter. - * - * @param {object|function} one Object to be merged into. - * @param {?object} two Optional object with properties to merge from. - */ -function mergeInto(one, two) { - checkMergeIntoObjectArg(one); - if (two != null) { - checkMergeObjectArg(two); - for (var key in two) { - if (!two.hasOwnProperty(key)) { - continue; - } - one[key] = two[key]; - } - } -} - -module.exports = mergeInto; - -},{"./mergeHelpers":45}],47:[function(_dereq_,module,exports){ -/** - * Copyright 2013-2014 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * @providesModule mixInto - */ - -"use strict"; - -/** - * Simply copies properties to the prototype. - */ -var mixInto = function(constructor, methodBag) { - var methodName; - for (methodName in methodBag) { - if (!methodBag.hasOwnProperty(methodName)) { - continue; - } - constructor.prototype[methodName] = methodBag[methodName]; - } -}; - -module.exports = mixInto; - -},{}],48:[function(_dereq_,module,exports){ +},{}],40:[function(_dereq_,module,exports){ /** - * Copyright 2014 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 + * Copyright 2014, Facebook, Inc. + * All rights reserved. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule warning */ @@ -3619,7 +2614,7 @@ if ("production" !== "production") { module.exports = warning; -},{"./emptyFunction":41}],49:[function(_dereq_,module,exports){ +},{"./emptyFunction":38}],41:[function(_dereq_,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ @@ -3638,7 +2633,7 @@ define(function (_dereq_) { }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(_dereq_); }); -},{"./Scheduler":51,"./async":52,"./makePromise":53}],50:[function(_dereq_,module,exports){ +},{"./Scheduler":43,"./async":44,"./makePromise":45}],42:[function(_dereq_,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ @@ -3710,7 +2705,7 @@ define(function() { }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); -},{}],51:[function(_dereq_,module,exports){ +},{}],43:[function(_dereq_,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ @@ -3794,7 +2789,7 @@ define(function(_dereq_) { }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(_dereq_); })); -},{"./Queue":50}],52:[function(_dereq_,module,exports){ +},{"./Queue":42}],44:[function(_dereq_,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ @@ -3839,11 +2834,21 @@ define(function(_dereq_) { } else { nextTick = (function(cjsRequire) { + var vertx; try { // vert.x 1.x || 2.x - return cjsRequire('vertx').runOnLoop || cjsRequire('vertx').runOnContext; + vertx = cjsRequire('vertx'); } catch (ignore) {} + if (vertx) { + if (typeof vertx.runOnLoop === 'function') { + return vertx.runOnLoop; + } + if (typeof vertx.runOnContext === 'function') { + return vertx.runOnContext; + } + } + // capture setTimeout to avoid being caught by fake timers // used in time based tests var capturedSetTimeout = setTimeout; @@ -3857,7 +2862,7 @@ define(function(_dereq_) { }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(_dereq_); })); -},{}],53:[function(_dereq_,module,exports){ +},{}],45:[function(_dereq_,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ @@ -3988,10 +2993,12 @@ define(function() { */ Promise.prototype.then = function(onFulfilled, onRejected) { var parent = this._handler; + var state = parent.join().state(); - if (typeof onFulfilled !== 'function' && parent.join().state() > 0) { + if ((typeof onFulfilled !== 'function' && state > 0) || + (typeof onRejected !== 'function' && state < 0)) { // Short circuit: value will not change, simply share handler - return new Promise(Handler, parent); + return new this.constructor(Handler, parent); } var p = this._beget(); @@ -4052,9 +3059,7 @@ define(function() { } if (maybeThenable(x)) { - h = isPromise(x) - ? x._handler.join() - : getHandlerUntrusted(x); + h = getHandlerMaybeThenable(x); s = h.state(); if (s === 0) { @@ -4063,6 +3068,7 @@ define(function() { results[i] = h.value; --pending; } else { + unreportRemaining(promises, i+1, h); resolver.become(h); break; } @@ -4088,6 +3094,20 @@ define(function() { } } + function unreportRemaining(promises, start, rejectedHandler) { + var i, h, x; + for(i=start; i 1) { + source += ' (' + inlineScriptCount + ')'; + } + } else if (dummyAnchor) { + // Firefox has problems when the sourcemap source is a proper URL with a + // protocol and hostname, so use the pathname. We could use just the + // filename, but hopefully using the full path will prevent potential + // issues where the same filename exists in multiple directories. + dummyAnchor.href = url; + source = dummyAnchor.pathname.substr(1); + } + map.sources = [source]; + map.sourcesContent = [code]; + + return ( + transformed.code + + '\n//# sourceMappingURL=data:application/json;base64,' + + buffer.Buffer(JSON.stringify(map)).toString('base64') + ); +} + + +/** + * Appends a script element at the end of the with the content of code, + * after transforming it. + * + * @param {string} code The original source code + * @param {string?} url Where the code came from. null if inline + * @param {object?} options Options to pass to jstransform + * @internal + */ +function run(code, url, options) { + var scriptEl = document.createElement('script'); + scriptEl.text = transformCode(code, url, options); + headEl.appendChild(scriptEl); +} + +/** + * Load script from the provided url and pass the content to the callback. + * + * @param {string} url The location of the script src + * @param {function} callback Function to call with the content of url + * @internal + */ +function load(url, successCallback, errorCallback) { + var xhr; + xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') + : new XMLHttpRequest(); + + // async, however scripts will be executed in the order they are in the + // DOM to mirror normal script loading. + xhr.open('GET', url, true); + if ('overrideMimeType' in xhr) { + xhr.overrideMimeType('text/plain'); + } + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + if (xhr.status === 0 || xhr.status === 200) { + successCallback(xhr.responseText); + } else { + errorCallback(); + throw new Error("Could not load " + url); + } + } + }; + return xhr.send(null); +} + +/** + * Loop over provided script tags and get the content, via innerHTML if an + * inline script, or by using XHR. Transforms are applied if needed. The scripts + * are executed in the order they are found on the page. + * + * @param {array} scripts The