Skip to content
Browse files

Rest path segments

  • Loading branch information...
1 parent 9c90711 commit ec965c124a1f081e63eb4220f47772b969677913 @AlexGalays committed Mar 3, 2014
Showing with 90 additions and 5 deletions.
  1. +15 −1 README.md
  2. +8 −1 src/Router.js
  3. +14 −3 src/State.js
  4. +53 −0 test/unit-tests.js
View
16 README.md
@@ -295,8 +295,9 @@ var state = router.currentState();
<a name="api-state"></a>
## State
+### Basics
States represent path segments of an url.
-Additionally, a state can own a list of query params: While all states will be able to read these params, isolated changes to these
+A state can own a list of query params: While all states will be able to read these params, isolated changes to these
will only trigger a transition up to the state owning them (it will be exited and re-entered). The same applies to dynamic query params.
How much you decompose your applications into states is completely up to you;
For instance you could have just one state:
@@ -314,6 +315,19 @@ State('some', {
})
```
+### Rest segments
+Additionaly, the last path segment can end with a `*` to match any number of extra path segments:
+
+```javascript
+State('path/:rest*')
+
+// All these state changes will result in that state being entered:
+
+// router.state('path'); // params.rest === undefined
+// router.state('path/other'); // params.rest === 'other'
+// router.state('path/other/yetAnother'); // params.rest === 'other/yetAnother'
+```
+
### addState (name: String, state: State): State
Add a child state.
Returns the current state to allow chaining.
View
9 src/Router.js
@@ -464,18 +464,25 @@ function Router(declarativeStates) {
* Translate the crossroads argument format to what we want to use.
* We want to keep the path and query names and merge them all in one object for convenience.
*/
+ var crossroadsParam = /\{\w*\}/g;
+ var crossroadsRestParam = /:\w*\*:/;
function fromCrossroadsParams(state, crossroadsArgs) {
var args = Array.prototype.slice.apply(crossroadsArgs),
query = args.pop(),
params = {},
pathName;
- state.fullPath().replace(/\{\w*\}/g, function(match) {
+ state.fullPath().replace(crossroadsParam, function(match) {
pathName = match.slice(1, -1);
params[pathName] = args.shift();
return '';
});
+ state.fullPath().replace(crossroadsRestParam, function(match) {
+ pathName = match.slice(1, -2);
+ params[pathName] = args.shift();
+ });
+
if (query) util.mergeObjects(params, query);
// Decode all params
View
17 src/State.js
@@ -220,12 +220,23 @@ function getArgs(args) {
result.queryParams = util.arrayToObject(result.queryParams.split('&'));
}
- // Replace dynamic params like :id with {id}, which is what crossroads uses,
+ // Replace dynamic params like :id with {id} or :rest* with :rest*:, which is what crossroads uses,
// and store them for later lookup.
- result.path = result.path.replace(/:\w*/g, function(match) {
+ result.path = result.path.replace(/:[^\\?\/]*/g, function(match) {
+ var isRestParam;
+
param = match.substring(1);
+
+ if (param[param.length - 1] == '*') {
+ param = param.slice(0, -1);
+ isRestParam = true;
+ }
+
result.params[param] = 1;
- return '{' + param + '}';
+
+ return isRestParam
+ ? (':' + param + '*:')
+ : ('{' + param + '}');
});
return result;
View
53 test/unit-tests.js
@@ -1273,6 +1273,59 @@ asyncTest('Redirecting from transition.started', function() {
});
+asyncTest('rest params', function() {
+
+ var lastParams;
+
+ var router = Router({
+ index: State(),
+ colors: State('colors/:rest*', function(params) {
+ lastParams = params;
+ })
+ }).init('');
+
+ whenSignal(router.changed)
+ .then(goToColors)
+ .then(wentToColorsOk)
+ .then(goToColors2)
+ .then(wentToColors2Ok)
+ .then(goToColors3)
+ .then(wentToColors3Ok)
+ .done(start);
+
+ function goToColors() {
+ router.state('colors');
+ }
+
+ function wentToColorsOk() {
+ return nextTick().then(function() {
+ strictEqual(lastParams.rest, undefined);
+ });
+ }
+
+ function goToColors2() {
+ router.state('colors/red');
+ }
+
+ function wentToColors2Ok() {
+ return nextTick().then(function() {
+ strictEqual(lastParams.rest, 'red');
+ });
+ }
+
+ function goToColors3() {
+ router.state('colors/red/blue');
+ }
+
+ function wentToColors3Ok() {
+ return nextTick().then(function() {
+ strictEqual(lastParams.rest, 'red/blue');
+ });
+ }
+
+});
+
+
asyncTest('backTo', function() {
var passedParams;

0 comments on commit ec965c1

Please sign in to comment.
Something went wrong with that request. Please try again.