react-router
Advanced tools
Comparing version 0.11.6 to 0.12.0
@@ -0,1 +1,27 @@ | ||
v0.12.0 - Tue, 10 Feb 2015 20:12:42 GMT | ||
--------------------------------------- | ||
- [cd2087d](../../commit/cd2087d) [added] default handler to routes | ||
- [848361e](../../commit/848361e) [fixed] Clean up mounted route component on unmount so we don't leak references | ||
- [5bcf653](../../commit/5bcf653) [fixed] Double slash in href when parent route has optional trailing slash | ||
- [26cb7d1](../../commit/26cb7d1) [added] node_modules to gitignore | ||
- [e280efd](../../commit/e280efd) [changed] Don't restore scroll position on Forward | ||
- [20c2c9b](../../commit/20c2c9b) [fixed] Do not decode + in pathname | ||
- [fe5ec39](../../commit/fe5ec39) [fixed] Double-encoding of query strings | ||
- [df38294](../../commit/df38294) [fixed] Allow comments in JSX config | ||
- [84056ba](../../commit/84056ba) [fixed] Ignore falsy routes | ||
- [81c7a57](../../commit/81c7a57) [changed] Removed "modules" directory | ||
- [4a770e8](../../commit/4a770e8) [fixed] Using TestLocation without DOM | ||
- [e24cf0f](../../commit/e24cf0f) Revert "[fixed] Path.withQuery strips query if query is empty" | ||
- [2ac2510](../../commit/2ac2510) [added] router.replaceRoutes(children) | ||
- [1f81286](../../commit/1f81286) [fixed] Ignore stale transitions | ||
- [c6ed6fa](../../commit/c6ed6fa) [removed] transition.wait, use callbacks instead | ||
- [75c6206](../../commit/75c6206) [added] router.stop() | ||
- [4e96256](../../commit/4e96256) [fixed] Preserve original query with HashLocation | ||
- [2f19e63](../../commit/2f19e63) [changed] Bump qs dependency version | ||
- [b98f5a1](../../commit/b98f5a1) [changed] Use webpack instead of Browserify | ||
- [94dc231](../../commit/94dc231) [changed] Run the examples with `npm run examples` | ||
- [0862ea2](../../commit/0862ea2) [fixed] Path.withQuery strips query if query is empty | ||
v0.11.6 - Wed, 17 Dec 2014 19:29:53 GMT | ||
@@ -2,0 +28,0 @@ --------------------------------------- |
@@ -22,3 +22,3 @@ var expect = require('expect'); | ||
AbortAsync | ||
} = require('./TestHandlers'); | ||
} = require('../utils/TestHandlers'); | ||
@@ -39,4 +39,4 @@ describe('Router', function () { | ||
describe('transition.wait', function () { | ||
it('waits asynchronously in willTransitionTo', function (done) { | ||
describe('asynchronous willTransitionTo', function () { | ||
it('waits', function (done) { | ||
TestLocation.history = [ '/bar' ]; | ||
@@ -75,3 +75,3 @@ | ||
it('stops waiting asynchronously in willTransitionTo on location.pop', function (done) { | ||
it('stops waiting on location.pop', function (done) { | ||
TestLocation.history = [ '/bar' ]; | ||
@@ -112,3 +112,3 @@ | ||
it('stops waiting asynchronously in willTransitionTo on router.transitionTo', function (done) { | ||
it('stops waiting on router.transitionTo', function (done) { | ||
TestLocation.history = [ '/bar' ]; | ||
@@ -156,3 +156,3 @@ | ||
it('stops waiting asynchronously in willTransitionTo on router.replaceWith', function (done) { | ||
it('stops waiting on router.replaceWith', function (done) { | ||
TestLocation.history = [ '/bar' ]; | ||
@@ -194,2 +194,62 @@ | ||
}); | ||
it('stops waiting on router.transitionTo after another asynchronous transition ended ', function (done) { | ||
var LongAsync = React.createClass({ | ||
statics: { | ||
delay: Async.delay * 2, | ||
willTransitionTo: function (transition, params, query, callback) { | ||
setTimeout(callback, this.delay); | ||
} | ||
}, | ||
render: function () { | ||
return <div className="Async2">Async2</div>; | ||
} | ||
}); | ||
TestLocation.history = [ '/foo' ]; | ||
var routes = [ | ||
<Route handler={Foo} path='/foo' />, | ||
<Route handler={Bar} path='/bar' />, | ||
<Route handler={Async} path='/async1' />, | ||
<Route handler={LongAsync} path='/async2' /> | ||
]; | ||
var div = document.createElement('div'); | ||
var steps = []; | ||
var router = Router.create({ | ||
routes: routes, | ||
location: TestLocation | ||
}); | ||
steps.push(function () { | ||
router.transitionTo('/async1'); | ||
setTimeout(function () { | ||
router.transitionTo('/async2'); | ||
expect(div.innerHTML).toMatch(/Foo/); | ||
setTimeout(function () { | ||
expect(div.innerHTML).toMatch(/Foo/); | ||
router.transitionTo('/bar'); | ||
expect(div.innerHTML).toMatch(/Bar/); | ||
}, Async.delay); | ||
}, Async.delay / 2); | ||
}); | ||
steps.push(function () { | ||
setTimeout(function () { | ||
expect(div.innerHTML).toMatch(/Bar/); | ||
done(); | ||
}, Async.delay); | ||
}); | ||
steps.push(function () { | ||
}); | ||
router.run(function (Handler, state) { | ||
React.render(<Handler />, div, function () { | ||
steps.shift()(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -530,2 +590,56 @@ | ||
}); | ||
it('ignores aborting asynchronously in willTransitionTo when aborted before router.transitionTo', function (done) { | ||
var AbortAsync2 = React.createClass({ | ||
statics: { | ||
willTransitionTo: function (transition, params, query, callback) { | ||
transition.abort(); | ||
setTimeout(callback, Async.delay); | ||
} | ||
}, | ||
render: function () { | ||
return <div>Abort</div>; | ||
} | ||
}); | ||
TestLocation.history = [ '/foo' ]; | ||
var routes = [ | ||
<Route handler={Foo} path='/foo' />, | ||
<Route handler={Bar} path='/bar' />, | ||
<Route handler={AbortAsync2} path='/abort' /> | ||
]; | ||
var div = document.createElement('div'); | ||
var steps = []; | ||
var router = Router.create({ | ||
routes: routes, | ||
location: TestLocation | ||
}); | ||
steps.push(function () { | ||
router.transitionTo('/abort'); | ||
expect(div.innerHTML).toMatch(/Foo/); | ||
router.transitionTo('/bar'); | ||
expect(div.innerHTML).toMatch(/Bar/); | ||
}); | ||
steps.push(function () { | ||
setTimeout(function () { | ||
expect(div.innerHTML).toMatch(/Bar/); | ||
expect(TestLocation.history).toEqual(['/foo', '/bar']); | ||
done(); | ||
}, Async.delay + 10); | ||
}); | ||
steps.push(function () { | ||
}); | ||
router.run(function (Handler, state) { | ||
React.render(<Handler />, div, function () { | ||
steps.shift()(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -563,7 +677,7 @@ }); | ||
willTransitionTo: function (transition, params, query) { | ||
if (query['filter'] === 'first') { | ||
if (query.filter === 'first') { | ||
return; // skip first transition | ||
} | ||
expect(query['filter']).toEqual('second'); | ||
expect(query.filter).toEqual('second'); | ||
expect(fromKnifeCalled).toBe(true); | ||
@@ -608,3 +722,3 @@ expect(fromSpoonCalled).toBe(true); | ||
willTransitionFrom: function (transition, component) { | ||
expect(div.querySelector('#bar')).toEqual(component.getDOMNode()); | ||
expect(div.querySelector('#bar')).toBe(component.getDOMNode()); | ||
done(); | ||
@@ -634,2 +748,69 @@ } | ||
}); | ||
it('should be called when Handler is rendered multiple times on same route', function (done) { | ||
var div = document.createElement('div'); | ||
var counter = 0; | ||
var Foo = React.createClass({ | ||
statics: { | ||
willTransitionFrom: function (transition, component) { | ||
counter++; | ||
} | ||
}, | ||
render: function () { | ||
return <div id="foo">Foo</div>; | ||
} | ||
}); | ||
var Bar = React.createClass({ | ||
statics: { | ||
willTransitionFrom: function (transition, component) { | ||
counter++; | ||
} | ||
}, | ||
render: function () { | ||
return <div id="bar">Bar</div>; | ||
} | ||
}); | ||
var routes = ( | ||
<Route handler={Nested} path='/'> | ||
<Route name="foo" handler={Foo}/> | ||
<Route name="bar" handler={Bar}/> | ||
</Route> | ||
); | ||
TestLocation.history = [ '/bar' ]; | ||
var steps = []; | ||
steps.push(function () { | ||
TestLocation.push('/foo'); | ||
}); | ||
steps.push(function () { | ||
TestLocation.push('/bar'); | ||
}); | ||
steps.push(function () { | ||
expect(counter).toEqual(2); | ||
done(); | ||
}); | ||
Router.run(routes, TestLocation, function (Handler, state) { | ||
// Calling render on the handler twice should be allowed | ||
React.render(<Handler data={{FooBar: 1}}/>, div); | ||
React.render(<Handler data={{FooBar: 1}}/>, div, function () { | ||
setTimeout(function() { | ||
steps.shift()(); | ||
}, 1); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -644,4 +825,2 @@ | ||
Router.run(routes, '/', function (Handler, state) { | ||
// TODO: figure out why we're getting this warning here | ||
// WARN: 'Warning: You cannot pass children to a RouteHandler' | ||
var html = React.renderToString(<Handler foo="bar"/>); | ||
@@ -1040,3 +1219,3 @@ expect(html).toMatch(/bar/); | ||
describe('unmounting', function () { | ||
describe.skip('unmounting', function () { | ||
afterEach(function () { | ||
@@ -1043,0 +1222,0 @@ window.location.hash = ''; |
@@ -6,3 +6,3 @@ var expect = require('expect'); | ||
var Route = require('../Route'); | ||
var { Foo, Bar, Nested } = require('../../__tests__/TestHandlers'); | ||
var { Foo, Bar, Nested } = require('../../utils/TestHandlers'); | ||
@@ -9,0 +9,0 @@ describe('DefaultRoute', function () { |
@@ -9,3 +9,3 @@ var assert = require('assert'); | ||
var TestLocation = require('../../locations/TestLocation'); | ||
var { Foo, Bar } = require('../../__tests__/TestHandlers'); | ||
var { Foo, Bar } = require('../../utils/TestHandlers'); | ||
var { click } = React.addons.TestUtils.Simulate; | ||
@@ -28,3 +28,3 @@ | ||
var div = document.createElement('div'); | ||
TestLocation.history = ['/link']; | ||
TestLocation.history = [ '/link' ]; | ||
@@ -119,3 +119,3 @@ Router.run(routes, TestLocation, function (Handler) { | ||
var div = document.createElement('div'); | ||
TestLocation.history = ['/link']; | ||
TestLocation.history = [ '/link' ]; | ||
@@ -131,3 +131,3 @@ Router.run(routes, TestLocation, function (Handler) { | ||
var div = document.createElement('div'); | ||
TestLocation.history = ['/link']; | ||
TestLocation.history = [ '/link' ]; | ||
@@ -134,0 +134,0 @@ var LinkHandler = React.createClass({ |
@@ -6,3 +6,3 @@ var expect = require('expect'); | ||
var Route = require('../Route'); | ||
var { Nested, Foo, Bar } = require('../../__tests__/TestHandlers'); | ||
var { Nested, Foo, Bar } = require('../../utils/TestHandlers'); | ||
@@ -9,0 +9,0 @@ describe('NotFoundRoute', function () { |
@@ -5,3 +5,3 @@ var expect = require('expect'); | ||
var TestLocation = require('../../locations/TestLocation'); | ||
var { Nested, Bar } = require('../../__tests__/TestHandlers'); | ||
var { Nested, Bar } = require('../../utils/TestHandlers'); | ||
var Redirect = require('../Redirect'); | ||
@@ -8,0 +8,0 @@ var Route = require('../Route'); |
@@ -7,3 +7,3 @@ var expect = require('expect'); | ||
var TestLocation = require('../../locations/TestLocation'); | ||
var { Bar, Foo } = require('../../__tests__/TestHandlers'); | ||
var { Bar, Foo } = require('../../utils/TestHandlers'); | ||
@@ -10,0 +10,0 @@ describe('RouteHandler', function () { |
var React = require('react'); | ||
var FakeNode = require('../mixins/FakeNode'); | ||
var PropTypes = require('../utils/PropTypes'); | ||
var Configuration = require('../Configuration'); | ||
var PropTypes = require('../PropTypes'); | ||
@@ -15,8 +15,9 @@ /** | ||
mixins: [ FakeNode ], | ||
mixins: [ Configuration ], | ||
propTypes: { | ||
name: React.PropTypes.string, | ||
name: PropTypes.string, | ||
path: PropTypes.falsy, | ||
handler: React.PropTypes.func.isRequired | ||
children: PropTypes.falsy, | ||
handler: PropTypes.func.isRequired | ||
} | ||
@@ -23,0 +24,0 @@ |
var React = require('react'); | ||
var classSet = require('react/lib/cx'); | ||
var assign = require('react/lib/Object.assign'); | ||
var Navigation = require('../mixins/Navigation'); | ||
var State = require('../mixins/State'); | ||
var Navigation = require('../Navigation'); | ||
var State = require('../State'); | ||
var PropTypes = require('../PropTypes'); | ||
@@ -40,7 +41,7 @@ function isLeftClickEvent(event) { | ||
propTypes: { | ||
activeClassName: React.PropTypes.string.isRequired, | ||
to: React.PropTypes.string.isRequired, | ||
params: React.PropTypes.object, | ||
query: React.PropTypes.object, | ||
onClick: React.PropTypes.func | ||
activeClassName: PropTypes.string.isRequired, | ||
to: PropTypes.string.isRequired, | ||
params: PropTypes.object, | ||
query: PropTypes.object, | ||
onClick: PropTypes.func | ||
}, | ||
@@ -47,0 +48,0 @@ |
var React = require('react'); | ||
var FakeNode = require('../mixins/FakeNode'); | ||
var PropTypes = require('../utils/PropTypes'); | ||
var Configuration = require('../Configuration'); | ||
var PropTypes = require('../PropTypes'); | ||
@@ -16,8 +16,9 @@ /** | ||
mixins: [ FakeNode ], | ||
mixins: [ Configuration ], | ||
propTypes: { | ||
name: React.PropTypes.string, | ||
name: PropTypes.string, | ||
path: PropTypes.falsy, | ||
handler: React.PropTypes.func.isRequired | ||
children: PropTypes.falsy, | ||
handler: PropTypes.func.isRequired | ||
} | ||
@@ -24,0 +25,0 @@ |
var React = require('react'); | ||
var FakeNode = require('../mixins/FakeNode'); | ||
var PropTypes = require('../utils/PropTypes'); | ||
var Configuration = require('../Configuration'); | ||
var PropTypes = require('../PropTypes'); | ||
@@ -13,8 +13,8 @@ /** | ||
mixins: [ FakeNode ], | ||
mixins: [ Configuration ], | ||
propTypes: { | ||
path: React.PropTypes.string, | ||
from: React.PropTypes.string, // Alias for path. | ||
to: React.PropTypes.string, | ||
path: PropTypes.string, | ||
from: PropTypes.string, // Alias for path. | ||
to: PropTypes.string, | ||
handler: PropTypes.falsy | ||
@@ -21,0 +21,0 @@ } |
var React = require('react'); | ||
var FakeNode = require('../mixins/FakeNode'); | ||
var Configuration = require('../Configuration'); | ||
var PropTypes = require('../PropTypes'); | ||
var RouteHandler = require('./RouteHandler'); | ||
/** | ||
@@ -41,2 +42,4 @@ * <Route> components specify components that are rendered to the page when the | ||
* }); | ||
* | ||
* If no handler is provided for the route, it will render a matched child route. | ||
*/ | ||
@@ -47,9 +50,15 @@ var Route = React.createClass({ | ||
mixins: [ FakeNode ], | ||
mixins: [ Configuration ], | ||
propTypes: { | ||
name: React.PropTypes.string, | ||
path: React.PropTypes.string, | ||
handler: React.PropTypes.func.isRequired, | ||
ignoreScrollBehavior: React.PropTypes.bool | ||
name: PropTypes.string, | ||
path: PropTypes.string, | ||
handler: PropTypes.func, | ||
ignoreScrollBehavior: PropTypes.bool | ||
}, | ||
getDefaultProps: function(){ | ||
return { | ||
handler: RouteHandler | ||
}; | ||
} | ||
@@ -56,0 +65,0 @@ |
var React = require('react'); | ||
var RouteHandlerMixin = require('../mixins/RouteHandler'); | ||
var RouteHandlerMixin = require('../RouteHandlerMixin'); | ||
@@ -12,12 +12,6 @@ /** | ||
mixins: [RouteHandlerMixin], | ||
mixins: [ RouteHandlerMixin ], | ||
getDefaultProps: function () { | ||
return { | ||
ref: '__routeHandler__' | ||
}; | ||
}, | ||
render: function () { | ||
return this.getRouteHandler(); | ||
return this.createChildRouteHandler(); | ||
} | ||
@@ -24,0 +18,0 @@ |
@@ -15,8 +15,9 @@ exports.DefaultRoute = require('./components/DefaultRoute'); | ||
exports.Navigation = require('./mixins/Navigation'); | ||
exports.State = require('./mixins/State'); | ||
exports.History = require('./History'); | ||
exports.Navigation = require('./Navigation'); | ||
exports.RouteHandlerMixin = require('./RouteHandlerMixin'); | ||
exports.State = require('./State'); | ||
exports.create = require('./utils/createRouter'); | ||
exports.run = require('./utils/runRouter'); | ||
exports.create = require('./createRouter'); | ||
exports.run = require('./runRouter'); | ||
exports.History = require('./utils/History'); |
@@ -5,6 +5,9 @@ var expect = require('expect'); | ||
describe('HashLocation.getCurrentPath', function () { | ||
afterEach(function () { | ||
window.location.hash = ''; | ||
}); | ||
//this test is needed because Firefox will pre-decode the value retrieved from | ||
//window.location.hash | ||
it('returns a properly decoded equivalent of what window.location.hash is set to', function () { | ||
it('returns a properly decoded equivalent of window.location.hash', function () { | ||
window.location.hash = ''; | ||
@@ -16,4 +19,5 @@ expect(HashLocation.getCurrentPath()).toBe(''); | ||
// + is only special in the query component, not the hash | ||
window.location.hash = 'test+spaces'; | ||
expect(HashLocation.getCurrentPath()).toBe('test spaces'); | ||
expect(HashLocation.getCurrentPath()).toBe('test+spaces'); | ||
@@ -29,3 +33,3 @@ window.location.hash = 'first%2Fsecond'; | ||
//decodeURI doesn't handle lone percents | ||
// decodeURI doesn't handle lone percents | ||
window.location.hash = '%'; | ||
@@ -42,8 +46,4 @@ expect(function () { | ||
expect(HashLocation.getCurrentPath()) | ||
.toBe('complicated string/full%2Fof%3Fspecial%chars%20and%23escapesሴ'); | ||
.toBe('complicated+string/full%2Fof%3Fspecial%chars%20and%23escapesሴ'); | ||
}); | ||
afterEach(function () { | ||
window.location.hash = ''; | ||
}); | ||
}); |
var LocationActions = require('../actions/LocationActions'); | ||
var History = require('../utils/History'); | ||
var Path = require('../utils/Path'); | ||
var History = require('../History'); | ||
@@ -10,3 +9,3 @@ /** | ||
function getHashPath() { | ||
return Path.decode( | ||
return decodeURI( | ||
// We can't use window.location.hash here because it's not | ||
@@ -71,37 +70,32 @@ // consistent across browsers - Firefox will pre-decode it! | ||
if (_isListening) | ||
return; | ||
if (!_isListening) { | ||
if (window.addEventListener) { | ||
window.addEventListener('hashchange', onHashChange, false); | ||
} else { | ||
window.attachEvent('onhashchange', onHashChange); | ||
} | ||
if (window.addEventListener) { | ||
window.addEventListener('hashchange', onHashChange, false); | ||
} else { | ||
window.attachEvent('onhashchange', onHashChange); | ||
_isListening = true; | ||
} | ||
_isListening = true; | ||
}, | ||
removeChangeListener: function(listener) { | ||
for (var i = 0, l = _changeListeners.length; i < l; i ++) { | ||
if (_changeListeners[i] === listener) { | ||
_changeListeners.splice(i, 1); | ||
break; | ||
_changeListeners = _changeListeners.filter(function (l) { | ||
return l !== listener; | ||
}); | ||
if (_changeListeners.length === 0) { | ||
if (window.removeEventListener) { | ||
window.removeEventListener('hashchange', onHashChange, false); | ||
} else { | ||
window.removeEvent('onhashchange', onHashChange); | ||
} | ||
} | ||
if (window.removeEventListener) { | ||
window.removeEventListener('hashchange', onHashChange, false); | ||
} else { | ||
window.removeEvent('onhashchange', onHashChange); | ||
_isListening = false; | ||
} | ||
if (_changeListeners.length === 0) | ||
_isListening = false; | ||
}, | ||
push: function (path) { | ||
_actionType = LocationActions.PUSH; | ||
window.location.hash = Path.encode(path); | ||
window.location.hash = encodeURI(path); | ||
}, | ||
@@ -111,3 +105,5 @@ | ||
_actionType = LocationActions.REPLACE; | ||
window.location.replace(window.location.pathname + '#' + Path.encode(path)); | ||
window.location.replace( | ||
window.location.pathname + window.location.search + '#' + encodeURI(path) | ||
); | ||
}, | ||
@@ -114,0 +110,0 @@ |
var LocationActions = require('../actions/LocationActions'); | ||
var History = require('../utils/History'); | ||
var Path = require('../utils/Path'); | ||
var History = require('../History'); | ||
@@ -9,3 +8,3 @@ /** | ||
function getWindowPath() { | ||
return Path.decode( | ||
return decodeURI( | ||
window.location.pathname + window.location.search | ||
@@ -42,36 +41,31 @@ ); | ||
if (_isListening) | ||
return; | ||
if (!_isListening) { | ||
if (window.addEventListener) { | ||
window.addEventListener('popstate', onPopState, false); | ||
} else { | ||
window.attachEvent('popstate', onPopState); | ||
} | ||
if (window.addEventListener) { | ||
window.addEventListener('popstate', onPopState, false); | ||
} else { | ||
window.attachEvent('popstate', onPopState); | ||
_isListening = true; | ||
} | ||
_isListening = true; | ||
}, | ||
removeChangeListener: function(listener) { | ||
for (var i = 0, l = _changeListeners.length; i < l; i ++) { | ||
if (_changeListeners[i] === listener) { | ||
_changeListeners.splice(i, 1); | ||
break; | ||
_changeListeners = _changeListeners.filter(function (l) { | ||
return l !== listener; | ||
}); | ||
if (_changeListeners.length === 0) { | ||
if (window.addEventListener) { | ||
window.removeEventListener('popstate', onPopState); | ||
} else { | ||
window.removeEvent('popstate', onPopState); | ||
} | ||
} | ||
if (window.addEventListener) { | ||
window.removeEventListener('popstate', onPopState); | ||
} else { | ||
window.removeEvent('popstate', onPopState); | ||
_isListening = false; | ||
} | ||
if (_changeListeners.length === 0) | ||
_isListening = false; | ||
}, | ||
push: function (path) { | ||
window.history.pushState({ path: path }, '', Path.encode(path)); | ||
window.history.pushState({ path: path }, '', encodeURI(path)); | ||
History.length += 1; | ||
@@ -82,3 +76,3 @@ notifyChange(LocationActions.PUSH); | ||
replace: function (path) { | ||
window.history.replaceState({ path: path }, '', Path.encode(path)); | ||
window.history.replaceState({ path: path }, '', encodeURI(path)); | ||
notifyChange(LocationActions.REPLACE); | ||
@@ -85,0 +79,0 @@ }, |
var HistoryLocation = require('./HistoryLocation'); | ||
var History = require('../utils/History'); | ||
var Path = require('../utils/Path'); | ||
var History = require('../History'); | ||
@@ -13,7 +12,7 @@ /** | ||
push: function (path) { | ||
window.location = Path.encode(path); | ||
window.location = encodeURI(path); | ||
}, | ||
replace: function (path) { | ||
window.location.replace(Path.encode(path)); | ||
window.location.replace(encodeURI(path)); | ||
}, | ||
@@ -20,0 +19,0 @@ |
var invariant = require('react/lib/invariant'); | ||
var LocationActions = require('../actions/LocationActions'); | ||
var History = require('../utils/History'); | ||
var History = require('../History'); | ||
@@ -25,2 +25,4 @@ var _listener; | ||
needsDOM: false, | ||
addChangeListener: function (listener) { | ||
@@ -32,4 +34,2 @@ // TestLocation only ever supports a single listener at a time. | ||
removeChangeListener: function () {}, | ||
push: function (path) { | ||
@@ -36,0 +36,0 @@ TestLocation.history.push(path); |
var expect = require('expect'); | ||
var Path = require('../Path'); | ||
describe('Path.decode', function () { | ||
it('properly decodes a path with a query string', function () { | ||
expect(Path.decode('/my/short+path?a=b&c=d')).toEqual('/my/short path?a=b&c=d'); | ||
}); | ||
}); | ||
describe('Path.encode', function () { | ||
it('properly encodes a path with a query string', function () { | ||
expect(Path.encode('/my/short path?a=b&c=d')).toEqual('/my/short+path?a=b&c=d'); | ||
}); | ||
}); | ||
describe('Path.extractParamNames', function () { | ||
@@ -289,2 +277,8 @@ describe('when a pattern contains no dynamic segments', function () { | ||
}); | ||
describe('when a pattern has optional slashes', function () { | ||
it('returns the correct path', function () { | ||
expect(Path.injectParams('/foo/?/bar/?/baz/?')).toEqual('/foo/bar/baz/'); | ||
}); | ||
}); | ||
}); | ||
@@ -326,3 +320,3 @@ | ||
it('merges two query strings', function () { | ||
expect(Path.withQuery('/path?a=b', { c: [ 'd', 'e' ]})).toEqual('/path?a=b&c%5B0%5D=d&c%5B1%5D=e'); | ||
expect(Path.withQuery('/path?a=b', { c: [ 'd', 'e' ] })).toEqual('/path?a=b&c=d&c=e'); | ||
}); | ||
@@ -329,0 +323,0 @@ }); |
@@ -7,3 +7,3 @@ var invariant = require('react/lib/invariant'); | ||
var paramInjectMatcher = /:([a-zA-Z_$][a-zA-Z0-9_$?]*[?]?)|[*]/g; | ||
var paramInjectTrailingSlashMatcher = /\/\/\?|\/\?/g; | ||
var paramInjectTrailingSlashMatcher = /\/\/\?|\/\?\/|\/\?/g; | ||
var queryMatcher = /\?(.+)/; | ||
@@ -40,16 +40,2 @@ | ||
/** | ||
* 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. | ||
@@ -149,6 +135,6 @@ */ | ||
var queryString = query && qs.stringify(query); | ||
var queryString = qs.stringify(query, { indices: false }); | ||
if (queryString) | ||
return Path.withoutQuery(path) + '?' + queryString; | ||
return Path.withoutQuery(path) + '?' + decodeURIComponent(queryString); | ||
@@ -155,0 +141,0 @@ return path; |
{ | ||
"name": "react-router", | ||
"version": "0.11.6", | ||
"version": "0.12.0", | ||
"description": "A complete routing library for React.js", | ||
"main": "./modules/index", | ||
"main": "modules/index.js", | ||
"repository": { | ||
@@ -16,4 +16,6 @@ "type": "git", | ||
"scripts": { | ||
"test": "scripts/test --browsers Firefox --single-run", | ||
"lint": "jsxhint examples modules" | ||
"build": "NODE_ENV=production webpack modules/index.js dist/react-router.js", | ||
"build-min": "NODE_ENV=production COMPRESS=1 webpack modules/index.js dist/react-router.min.js", | ||
"examples": "webpack-dev-server --config examples/webpack.config.js --no-info --content-base examples", | ||
"test": "jsxhint . && karma start --single-run" | ||
}, | ||
@@ -26,25 +28,20 @@ "authors": [ | ||
"devDependencies": { | ||
"browserify": "4.2.3", | ||
"browserify-shim": "3.6.0", | ||
"bundle-loader": "0.5.1", | ||
"envify": "1.2.0", | ||
"bundle-loader": "^0.5.2", | ||
"events": "1.0.2", | ||
"expect": "0.1.1", | ||
"glob": "4.2.1", | ||
"jsx-loader": "0.12.0", | ||
"expect": "^1.1.0", | ||
"jsx-loader": "^0.12.2", | ||
"jsxhint": "^0.8.1", | ||
"karma": "0.12.16", | ||
"karma-browserify": "1.0.0", | ||
"karma-chrome-launcher": "0.1.4", | ||
"karma": "^0.12.28", | ||
"karma-chrome-launcher": "^0.1.7", | ||
"karma-cli": "0.0.4", | ||
"karma-firefox-launcher": "0.1.3", | ||
"karma-mocha": "0.1.3", | ||
"mocha": "1.20.1", | ||
"karma-firefox-launcher": "^0.1.3", | ||
"karma-mocha": "^0.1.10", | ||
"karma-sourcemap-loader": "^0.3.2", | ||
"karma-webpack": "^1.3.1", | ||
"mocha": "^2.0.1", | ||
"react": "0.12.x", | ||
"reactify": "0.15.x", | ||
"rf-release": "0.4.0", | ||
"rx": "2.3.18", | ||
"uglify-js": "2.4.15", | ||
"webpack": "1.4.5", | ||
"webpack-dev-server": "1.6.5" | ||
"webpack": "^1.4.13", | ||
"webpack-dev-server": "^1.6.6" | ||
}, | ||
@@ -55,4 +52,3 @@ "peerDependencies": { | ||
"dependencies": { | ||
"qs": "2.2.2", | ||
"when": "3.4.6" | ||
"qs": "2.3.3" | ||
}, | ||
@@ -70,6 +66,3 @@ "tags": [ | ||
"router" | ||
], | ||
"browserify-shim": { | ||
"react": "global:React" | ||
} | ||
] | ||
} |
[![npm package](https://img.shields.io/npm/v/react-router.svg?style=flat-square)](https://www.npmjs.org/package/react-router) | ||
[![build status](https://img.shields.io/travis/rackt/react-router.svg?style=flat-square)](https://travis-ci.org/rackt/react-router) | ||
[![build status](https://img.shields.io/travis/rackt/react-router/master.svg?style=flat-square)](https://travis-ci.org/rackt/react-router) | ||
[![dependency status](https://img.shields.io/david/rackt/react-router.svg?style=flat-square)](https://david-dm.org/rackt/react-router) | ||
@@ -44,2 +44,4 @@ | ||
The library is also available on the popular CDN [cdnjs](https://cdnjs.com/libraries/react-router). | ||
Features | ||
@@ -95,3 +97,3 @@ -------- | ||
Benefits of This Approach | ||
Benefits of this Approach | ||
------------------------- | ||
@@ -101,3 +103,3 @@ | ||
use-case when a user visits a route: render something. Every user | ||
interface has layers (or nesting) whether its a simple navbar or | ||
interface has layers (or nesting) whether it's a simple navbar or | ||
multiple levels of master-detail. Coupling nested routes to these | ||
@@ -120,3 +122,3 @@ nested views gets rid of a ton of work for the developer to wire all | ||
Router, you don't get UI on the page without configuring a url first. | ||
Fortunately, its wildly productive this way, too. | ||
Fortunately, it's wildly productive this way, too. | ||
@@ -139,4 +141,4 @@ Related Modules | ||
This library is highly inspired by the Ember.js routing API. In general, | ||
its a translation of the Ember router api to React. Huge thanks to the | ||
it's a translation of the Ember router api to React. Huge thanks to the | ||
Ember team for solving the hardest part already. | ||
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
2
18
2
140
1
150513
51
3777
1
+ Addedqs@2.3.3(transitive)
- Removedwhen@3.4.6
- Removedqs@2.2.2(transitive)
- Removedwhen@3.4.6(transitive)
Updatedqs@2.3.3