can-route
Advanced tools
Comparing version 3.0.0-pre.15 to 3.0.0-pre.16
@@ -20,2 +20,4 @@ /*jshint -W079 */ | ||
var types = require('can-util/js/types/types'); | ||
var dev = require('can-util/js/dev/dev'); | ||
var diff = require('can-util/js/diff/diff'); | ||
@@ -31,3 +33,4 @@ | ||
// Any word character or a period is matched. | ||
var matcher = /[\:|\{]([\w.]+)\}?/g; | ||
var curliesMatcher = /\{([\w.]+)\}/g; | ||
var colonMatcher = /\:([\w.]+)/g; | ||
// Regular expression for identifying &key=value lists. | ||
@@ -143,3 +146,3 @@ var paramsMatcher = /^(?:&[^=]+=[^&]*)+/; | ||
// if route ends with a / and url starts with a /, remove the leading / of the url | ||
var root =canRoute._call("root"); | ||
var root = canRoute._call("root"); | ||
@@ -157,7 +160,20 @@ if (root.lastIndexOf("/") === root.length - 1 && | ||
test = "", | ||
lastIndex = matcher.lastIndex = 0, | ||
matcher, | ||
lastIndex, | ||
next, | ||
querySeparator =canRoute._call("querySeparator"), | ||
matchSlashes =canRoute._call("matchSlashes"); | ||
querySeparator = canRoute._call("querySeparator"), | ||
matchSlashes = canRoute._call("matchSlashes"); | ||
// fall back to legacy `:foo` RegExp if necessary | ||
if (colonMatcher.test(url)) { | ||
matcher = colonMatcher; | ||
dev.warn('update route "' + url + '" to "' + url.replace(colonMatcher, function(name, key) { | ||
return '{' + key + '}'; | ||
}) + '"'); | ||
} else { | ||
matcher = curliesMatcher; | ||
} | ||
lastIndex = matcher.lastIndex = 0; | ||
// res will be something like ["{foo}","foo"] | ||
@@ -177,2 +193,18 @@ while (res = matcher.exec(url)) { | ||
.replace("\\", ""); | ||
// warn if new route uses same map properties as an existing route | ||
if (dev) { | ||
each(canRoute.routes, function(r) { | ||
var existingKeys = r.names.concat(Object.keys(r.defaults)).sort(); | ||
var keys = names.concat(Object.keys(defaults)).sort(); | ||
if (!diff(existingKeys, keys).length) { | ||
dev.warn('two routes were registered with matching keys:\n' + | ||
'\t(1) route("' + r.route + '", ' + JSON.stringify(r.defaults) + ')\n' + | ||
'\t(2) route("' + url + '", ' + JSON.stringify(defaults) + ')\n' + | ||
'(1) will always be chosen since it was registered first'); | ||
} | ||
}); | ||
} | ||
// Add route in a form that can be easily figured out. | ||
@@ -344,3 +376,7 @@ canRoute.routes[url] = { | ||
routeName = data.route, | ||
propCount = 0; | ||
propCount = 0, | ||
cpy, | ||
res, | ||
after, | ||
matcher; | ||
@@ -368,15 +404,16 @@ delete data.route; | ||
if (canRoute.routes[routeName] && matchesData(canRoute.routes[routeName], data) === matches) { | ||
route =canRoute.routes[routeName]; | ||
route = canRoute.routes[routeName]; | ||
} | ||
// If this is match... | ||
if (route) { | ||
var cpy = assign({}, data), | ||
// Create the url by replacing the var names with the provided data. | ||
// If the default value is found an empty string is inserted. | ||
res = route.route.replace(matcher, function (whole, name) { | ||
delete cpy[name]; | ||
return data[name] === route.defaults[name] ? "" : encodeURIComponent(data[name]); | ||
}) | ||
.replace("\\", ""), | ||
after; | ||
cpy = assign({}, data); | ||
// fall back to legacy :foo RegExp if necessary | ||
matcher = colonMatcher.test(route.route) ? colonMatcher : curliesMatcher; | ||
// Create the url by replacing the var names with the provided data. | ||
// If the default value is found an empty string is inserted. | ||
res = route.route.replace(matcher, function (whole, name) { | ||
delete cpy[name]; | ||
return data[name] === route.defaults[name] ? "" : encodeURIComponent(data[name]); | ||
}) | ||
.replace("\\", ""); | ||
// Remove matching default values | ||
@@ -388,3 +425,2 @@ each(route.defaults, function (val, name) { | ||
}); | ||
// The remaining elements of data are added as | ||
@@ -398,3 +434,3 @@ // `&` separated parameters to the url. | ||
} | ||
return res + (after ?canRoute._call("querySeparator") + after : ""); | ||
return res + (after ? canRoute._call("querySeparator") + after : ""); | ||
} | ||
@@ -438,4 +474,4 @@ // If no route was found, there is no hash URL, only paramters. | ||
* ```js | ||
* route.attr("id", 5) // location.hash -> #!id=5 | ||
* route.attr("type", "videos"); | ||
* route.data.id = 5 // location.hash -> #!id=5 | ||
* route.data.type = "videos" | ||
* // location.hash -> #!id=5&type=videos | ||
@@ -548,3 +584,3 @@ * route.deparam(location.hash); | ||
* route.ready(); | ||
* route.attr("page"); // -> "home" | ||
* route.data.page; // -> "home" | ||
* ``` | ||
@@ -694,4 +730,4 @@ * | ||
* | ||
* route.current({page: "recipes"}) //-> false | ||
* route.current({page: "recipes"}, true) //-> true | ||
* route.current({page: "recipes"}); //-> false | ||
* route.current({page: "recipes"}, true); //-> true | ||
* ``` | ||
@@ -716,9 +752,9 @@ * | ||
* ```js | ||
* route.attr('id', 5) // location.hash -> "#!id=5" | ||
* route.current({ id: 5 }) // -> true | ||
* route.current({ id: 5, type: 'videos' }) // -> false | ||
* route.data.id = 5; // location.hash -> "#!id=5" | ||
* route.current({ id: 5 }); // -> true | ||
* route.current({ id: 5, type: 'videos' }); // -> false | ||
* | ||
* route.attr('type', 'videos') | ||
* route.data.type = 'videos'; | ||
* // location.hash -> #!id=5&type=videos | ||
* route.current({ id: 5, type: 'videos' }) // -> true | ||
* route.current({ id: 5, type: 'videos' }); // -> true | ||
* ``` | ||
@@ -725,0 +761,0 @@ */ |
@@ -35,3 +35,3 @@ @function can-route can-route | ||
## Background Information | ||
## Background information | ||
@@ -68,9 +68,9 @@ To support the browser's back button and bookmarking in a JavaScript | ||
## map | ||
## data | ||
Underlying can-route is an observable map. Depending on what type of map your application uses this could be a [can-map], a [can-define/map/map], or maybe even a [can-simple-map]. | ||
Underlying can-route is an observable map: `route.data`. Depending on what type of map your application uses this could be a [can-map], a [can-define/map/map], or maybe even a [can-simple-map]. | ||
Understanding how maps work is essential to understanding can-route. | ||
You can listen to changes in a map with `on(eventName, handler(ev, args...))` and change can-route's properties with `route.attr()`. | ||
You can listen to changes in a map with `on(eventName, handler(ev, args...))` and change can-route's properties by modifying `route.data`. | ||
@@ -94,6 +94,6 @@ ### Listening to changes in can-route | ||
Create changes in the route data with [can.Map.prototype.attr attr] like: | ||
When using a [can-define/map/map DefineMap] to back can-route, create changes in the route data by modifying it directly: | ||
```js | ||
route.attr('type','images'); | ||
route.data.type = 'image'; | ||
``` | ||
@@ -104,3 +104,3 @@ | ||
```js | ||
route.attr({type: 'pages', id: 5}, true); | ||
route.data.set({type: 'page', id: 5}, true); | ||
``` | ||
@@ -111,4 +111,6 @@ | ||
## Creating a Route | ||
If using [can-map] or [can-simple-map] to back your route, update `route.data` using `attr`. | ||
## Creating a route | ||
Use `route(url, defaults)` to create a | ||
@@ -141,3 +143,3 @@ route. A route is a mapping from a url to | ||
// route -> {type : "images"} | ||
route.attr("type", "songs") | ||
route.data.type = "songs"; | ||
// location.hash -> "#!content/songs" | ||
@@ -160,3 +162,3 @@ ``` | ||
location.hash = "#!"; | ||
// route.attr() -> { page: "index" } | ||
// route -> {page : "index"} | ||
// location.hash -> "#!" | ||
@@ -174,3 +176,3 @@ ``` | ||
## Changing the route. | ||
## Changing the route | ||
@@ -182,3 +184,3 @@ Typically, you don't set `location.hash` | ||
```js | ||
route.attr('type', 'videos'); | ||
route.data.type = 'videos'; | ||
``` | ||
@@ -196,1 +198,64 @@ | ||
``` | ||
## Finding the matched route | ||
The matched route is the one that will be used to set the `window.location.hash`. The process can-route uses to find the matched route is: | ||
- Find all routes with all of their map properties set | ||
- If multiple routes are matched, find the route with the highest number of set properties | ||
- If multiple routes are still matched, use the route that was registered first | ||
### Find all routes with all of their map properties set | ||
In order for a route to be matched, all of the map properties it uses must be set. For example, in the following route, `page` and `section` must be set in order for this route to be matched: | ||
```js | ||
route('{page}/{section}'); | ||
route.ready(); | ||
route.data.page = 'contact'; | ||
route.data.section = 'email'; | ||
route.data.route; // "{page}/{section}" | ||
``` | ||
If a route contains default values, these map properties must also be set to match the default value in order for the route to be matched: | ||
```js | ||
route('{page}', { section: 'email' }); | ||
route.ready(); | ||
route.data.page = 'contact'; | ||
route.data.section = 'email'; | ||
route.data.route; // "{page}" | ||
``` | ||
### Find the route with the highest number of set properties | ||
If multiple routes have all of their properties set, the route with the highest number of set properties will be used: | ||
```js | ||
route('{page}'); | ||
route('{page}/{section}'); | ||
route.ready(); | ||
route.data.page = 'two'; | ||
route.data.section = 'a'; | ||
route.data.route; // "{page}/{section}" | ||
``` | ||
### Find the route that was registered first | ||
If multiple routes are still matched, the route that was registered first will be matched: | ||
```js | ||
route('', { page: 'home' }); | ||
route('{section}'); | ||
route.ready(); | ||
route.data.page = 'home'; | ||
route.data.section = 'a'; | ||
route.data.route; // "" | ||
``` |
{ | ||
"name": "can-route", | ||
"version": "3.0.0-pre.15", | ||
"version": "3.0.0-pre.16", | ||
"description": "", | ||
@@ -62,3 +62,3 @@ "homepage": "", | ||
"can-list": "^3.0.0-pre.4", | ||
"can-define": "^0.7.7", | ||
"can-define": "^0.8.0", | ||
"bit-docs": "0.0.7", | ||
@@ -65,0 +65,0 @@ "jshint": "^2.9.1", |
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
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
0
111630
19
3338