crossroads
Advanced tools
Comparing version 0.5.0 to 0.6.0
# Crossroads.js Changelog # | ||
## v0.6.0 (2011/08/31) ## | ||
## API Changes ## | ||
- changed `crossroads.shouldTypecast` default value to `false` (issue #23) | ||
- added magic rule to normalize route params before dispatch `rules.normalize_`. (#21) | ||
- added crossroads.VERSION | ||
### Fixes ### | ||
- fix optional "/" between required params. (#25) | ||
- only test optional params if value != null. (#26) | ||
- fix CommonJS wrapper, wasn't exporting crossroads properly (#27) | ||
### Other ### | ||
- Migrated unit tests from YUI to Jasmine to allow testing on nodejs and also | ||
because it runs locally and gives better error messages. Increased a lot the | ||
number of tests that helped to spot a few edge cases. (#5) | ||
- Changed wrapper to generate a single distribution file that runs on all | ||
environments. (#27) | ||
## v0.5.0 (2011/08/17) ## | ||
@@ -8,7 +32,7 @@ | ||
- added numbered rules for RegExp pattern and alias to segments (#16) | ||
- added support to optional segments (#17) | ||
- added property `crossroads.shouldTypecast` to enable/disable typecasting | ||
segments values. (issue #18) | ||
- added support to optional segments (issue #17) | ||
- added support to multiple instances (issue #19) | ||
- added numbered rules for RegExp pattern and alias to segments (issue #16) | ||
segments values. (#18) | ||
- added support to multiple instances (#19) | ||
@@ -19,4 +43,8 @@ ### Other ### | ||
### Fixes ### | ||
- fix trailing slash before optional param (#22) | ||
## v0.4 (2011/06/06) ## | ||
@@ -26,7 +54,7 @@ | ||
- added magic rule to validate whole request `rules.request_`. (issue #14) | ||
- added magic rule to validate whole request `rules.request_`. (#14) | ||
### Other ### | ||
- changed behavior of trailing slash at the end of string pattern so it doesn't affect route anymore (issue #12). | ||
- changed behavior of trailing slash at the end of string pattern so it doesn't affect route anymore (#12). | ||
- added NPM package. | ||
@@ -40,4 +68,4 @@ | ||
- added support for RegExp route pattern. (issue #8) | ||
- added signal `routed` to crossroads. (issue #9) | ||
- added support for RegExp route pattern. (#8) | ||
- added signal `routed` to crossroads. (#9) | ||
- added commonjs module wrapper. | ||
@@ -51,3 +79,3 @@ | ||
- added priority param to `addRoute`. (issue #2) | ||
- added priority param to `addRoute`. (#2) | ||
@@ -54,0 +82,0 @@ ### Other ### |
@@ -5,14 +5,15 @@ /** @license | ||
* Author: Miller Medeiros | ||
* Version 0.5.0 - Build: 58 (2011/08/17 02:00 AM) | ||
* Version: 0.6.0 - Build: 77 (2011/08/31 11:12 PM) | ||
*/ | ||
(function(global){ | ||
(function(def){ | ||
def(['signals'], function(signals){ | ||
var crossroads, | ||
patternLexer, | ||
BOOL_REGEXP = /^(true|false)$/i; | ||
// Helpers ----------- | ||
//==================== | ||
function arrayIndexOf(arr, val){ | ||
@@ -26,15 +27,15 @@ var n = arr.length; | ||
} | ||
function isType(type, val){ | ||
return '[object '+ type +']' === Object.prototype.toString.call(val); | ||
} | ||
function isRegExp(val){ | ||
return isType('RegExp', val); | ||
} | ||
function isArray(val){ | ||
return isType('Array', val); | ||
} | ||
function isFunction(val){ | ||
@@ -61,6 +62,6 @@ return isType('Function', val); | ||
// Crossroads -------- | ||
//==================== | ||
/** | ||
@@ -76,3 +77,3 @@ * @constructor | ||
Crossroads.prototype = { | ||
create : function(){ | ||
@@ -82,3 +83,3 @@ return new Crossroads(); | ||
shouldTypecast : true, | ||
shouldTypecast : false, | ||
@@ -90,3 +91,3 @@ addRoute : function(pattern, callback, priority){ | ||
}, | ||
removeRoute : function(route){ | ||
@@ -97,3 +98,3 @@ var i = arrayIndexOf(this._routes, route); | ||
}, | ||
removeAllRoutes : function(){ | ||
@@ -106,7 +107,7 @@ var n = this.getNumRoutes(); | ||
}, | ||
parse : function(request){ | ||
request = request || ''; | ||
var route = this._getMatchedRoute(request), | ||
params = route? patternLexer.getParamValues(request, route._matchRegexp, this.shouldTypecast) : null; | ||
params = route? route._getParamsArray(request) : null; | ||
if(route){ | ||
@@ -119,3 +120,3 @@ params? route.matched.dispatch.apply(route.matched, params) : route.matched.dispatch(); | ||
}, | ||
getNumRoutes : function(){ | ||
@@ -132,3 +133,3 @@ return this._routes.length; | ||
}, | ||
_getMatchedRoute : function(request){ | ||
@@ -148,11 +149,12 @@ var routes = this._routes, | ||
}; | ||
//"static" instance | ||
crossroads = new Crossroads(); | ||
crossroads.VERSION = '0.6.0'; | ||
// Route -------------- | ||
//===================== | ||
/** | ||
@@ -166,2 +168,3 @@ * @constructor | ||
this._paramsIds = isRegexPattern? null : patternLexer.getParamIds(this._pattern); | ||
this._optionalParamsIds = isRegexPattern? null : patternLexer.getOptionalParamsIds(this._pattern); | ||
this._matchRegexp = isRegexPattern? pattern : patternLexer.compilePattern(pattern); | ||
@@ -172,11 +175,11 @@ this.matched = new signals.Signal(); | ||
} | ||
Route.prototype = { | ||
rules : void(0), | ||
match : function(request){ | ||
return this._matchRegexp.test(request) && this._validateParams(request); //validate params even if regexp because of `request_` rule. | ||
}, | ||
_validateParams : function(request){ | ||
@@ -193,3 +196,3 @@ var rules = this.rules, | ||
}, | ||
_isValidParam : function(request, prop, values){ | ||
@@ -199,4 +202,7 @@ var validationRule = this.rules[prop], | ||
isValid; | ||
if (isRegExp(validationRule)) { | ||
if ( val == null && this._optionalParamsIds && arrayIndexOf(this._optionalParamsIds, prop) !== -1) { | ||
isValid = true; | ||
} | ||
else if (isRegExp(validationRule)) { | ||
isValid = validationRule.test(val); | ||
@@ -210,6 +216,6 @@ } | ||
} | ||
return isValid || false; //fail silently if validationRule is from an unsupported type | ||
}, | ||
_getParamValuesObject : function(request){ | ||
@@ -229,7 +235,19 @@ var shouldTypecast = this._router.shouldTypecast, | ||
}, | ||
_getParamsArray : function(request){ | ||
var vals = this._getParamValuesObject(request), | ||
norm = this.rules? this.rules.normalize_ : null, | ||
params; | ||
if(isFunction(norm)){ | ||
params = norm(request, vals); | ||
} else { | ||
params = patternLexer.getParamValues(request, this._matchRegexp, this._router.shouldTypecast); | ||
} | ||
return params; | ||
}, | ||
dispose : function(){ | ||
this._router.removeRoute(this); | ||
}, | ||
_destroy : function(){ | ||
@@ -239,19 +257,20 @@ this.matched.dispose(); | ||
}, | ||
toString : function(){ | ||
return '[Route pattern:"'+ this._pattern +'", numListeners:'+ this.matched.getNumListeners() +']'; | ||
} | ||
}; | ||
// Pattern Lexer ------ | ||
//===================== | ||
patternLexer = crossroads.patternLexer = (function(){ | ||
var ESCAPE_CHARS_REGEXP = /[\\.+*?\^$\[\](){}\/'#]/g, //match chars that should be escaped on string regexp | ||
UNNECESSARY_SLASHES_REGEXP = /\/$/g, //trailing slash | ||
OPTIONAL_SLASHES_REGEXP = /([:}]|\w(?=\/))\/?(:)/g, //slash between `::` or `}:` or `\w:`. $1 = before, $2 = after | ||
REQUIRED_SLASHES_REGEXP = /([:}])\/?(\{)/g, | ||
@@ -261,3 +280,3 @@ REQUIRED_PARAMS_REGEXP = /\{([^}]+)\}/g, //match everything between `{ }` | ||
PARAMS_REGEXP = /(?:\{|:)([^}:]+)(?:\}|:)/g, //capture everything between `{ }` or `: :` | ||
//used to save params during compile (avoid escaping things that shouldn't be escaped) | ||
@@ -267,7 +286,9 @@ SAVE_REQUIRED_PARAMS = '___CR_REQ___', | ||
SAVE_OPTIONAL_SLASHES = '___CR_OPT_SLASH___', | ||
SAVE_REQUIRED_SLASHES = '___CR_REQ_SLASH___', | ||
SAVED_REQUIRED_REGEXP = new RegExp(SAVE_REQUIRED_PARAMS, 'g'), | ||
SAVED_OPTIONAL_REGEXP = new RegExp(SAVE_OPTIONAL_PARAMS, 'g'), | ||
SAVED_OPTIONAL_SLASHES_REGEXP = new RegExp(SAVE_OPTIONAL_SLASHES, 'g'); | ||
SAVED_OPTIONAL_SLASHES_REGEXP = new RegExp(SAVE_OPTIONAL_SLASHES, 'g'), | ||
SAVED_REQUIRED_SLASHES_REGEXP = new RegExp(SAVE_REQUIRED_SLASHES, 'g'); | ||
function getParamIds(pattern){ | ||
@@ -280,3 +301,11 @@ var ids = [], match; | ||
} | ||
function getOptionalParamsIds(pattern){ | ||
var ids = [], match; | ||
while(match = OPTIONAL_PARAMS_REGEXP.exec(pattern)){ | ||
ids.push(match[1]); | ||
} | ||
return ids; | ||
} | ||
function compilePattern(pattern){ | ||
@@ -295,12 +324,14 @@ pattern = pattern || ''; | ||
pattern = pattern.replace(OPTIONAL_SLASHES_REGEXP, '$1'+ SAVE_OPTIONAL_SLASHES +'$2'); | ||
pattern = pattern.replace(REQUIRED_SLASHES_REGEXP, '$1'+ SAVE_REQUIRED_SLASHES +'$2'); | ||
pattern = pattern.replace(OPTIONAL_PARAMS_REGEXP, SAVE_OPTIONAL_PARAMS); | ||
return pattern.replace(REQUIRED_PARAMS_REGEXP, SAVE_REQUIRED_PARAMS); | ||
} | ||
function untokenize(pattern){ | ||
pattern = pattern.replace(SAVED_OPTIONAL_SLASHES_REGEXP, '\\/?'); | ||
pattern = pattern.replace(SAVED_REQUIRED_SLASHES_REGEXP, '\\/'); | ||
pattern = pattern.replace(SAVED_OPTIONAL_REGEXP, '([^\\/]+)?\/?'); | ||
return pattern.replace(SAVED_REQUIRED_REGEXP, '([^\\/]+)'); | ||
} | ||
function getParamValues(request, regexp, shouldTypecast){ | ||
@@ -316,15 +347,34 @@ var vals = regexp.exec(request); | ||
} | ||
//API | ||
return { | ||
getParamIds : getParamIds, | ||
getOptionalParamsIds : getOptionalParamsIds, | ||
getParamValues : getParamValues, | ||
compilePattern : compilePattern | ||
}; | ||
}()); | ||
global.crossroads = crossroads; | ||
}(window || this)); | ||
return crossroads; | ||
}); | ||
}( | ||
// wrapper to run code everywhere | ||
// based on http://bit.ly/c7U4h5 | ||
typeof require === 'undefined'? | ||
//Browser (regular script tag) | ||
function(deps, factory){ | ||
this.crossroads = factory(signals); | ||
} : | ||
((typeof exports === 'undefined')? | ||
//AMD | ||
function(deps, factory){ | ||
define('crossroads', deps, factory); | ||
} : | ||
//CommonJS | ||
function(deps, factory){ | ||
module.exports = factory.apply(this, deps.map(require)); | ||
} | ||
) | ||
)); |
@@ -6,10 +6,11 @@ /* | ||
Author: Miller Medeiros | ||
Version 0.5.0 - Build: 58 (2011/08/17 02:00 AM) | ||
Version: 0.6.0 - Build: 77 (2011/08/31 11:12 PM) | ||
*/ | ||
(function(n){function k(a,b){for(var c=a.length;c--;)if(a[c]===b)return c;return-1}function h(a,b){return"[object "+a+"]"===Object.prototype.toString.call(b)}function l(a){return a===null?a:o.test(a)?a.toLowerCase()==="true":a===""||isNaN(a)?a:parseFloat(a)}function i(){this._routes=[];this.bypassed=new signals.Signal;this.routed=new signals.Signal}function m(a,b,c,d){var f=h("RegExp",a);this._router=d;this._pattern=a;this._paramsIds=f?null:g.getParamIds(this._pattern);this._matchRegexp=f?a:g.compilePattern(a); | ||
this.matched=new signals.Signal;b&&this.matched.add(b);this._priority=c||0}var j,g,o=/^(true|false)$/i;i.prototype={create:function(){return new i},shouldTypecast:!0,addRoute:function(a,b,c){a=new m(a,b,c,this);this._sortedInsert(a);return a},removeRoute:function(a){var b=k(this._routes,a);b>=0&&this._routes.splice(b,1);a._destroy()},removeAllRoutes:function(){for(var a=this.getNumRoutes();a--;)this._routes[a]._destroy();this._routes.length=0},parse:function(a){var a=a||"",b=this._getMatchedRoute(a), | ||
c=b?g.getParamValues(a,b._matchRegexp,this.shouldTypecast):null;b?(c?b.matched.dispatch.apply(b.matched,c):b.matched.dispatch(),this.routed.dispatch(a,b,c)):this.bypassed.dispatch(a)},getNumRoutes:function(){return this._routes.length},_sortedInsert:function(a){var b=this._routes,c=b.length;do--c;while(b[c]&&a._priority<=b[c]._priority);b.splice(c+1,0,a)},_getMatchedRoute:function(a){for(var b=this._routes,c=b.length,d;d=b[--c];)if(d.match(a))return d;return null},toString:function(){return"[crossroads numRoutes:"+ | ||
this.getNumRoutes()+"]"}};j=new i;m.prototype={rules:void 0,match:function(a){return this._matchRegexp.test(a)&&this._validateParams(a)},_validateParams:function(a){var b=this.rules,c=this._getParamValuesObject(a),d;for(d in b)if(b.hasOwnProperty(d)&&!this._isValidParam(a,d,c))return!1;return!0},_isValidParam:function(a,b,c){var d=this.rules[b],b=c[b],f;h("RegExp",d)?f=d.test(b):h("Array",d)?f=k(d,b||"")!==-1:h("Function",d)&&(f=d(b,a,c));return f||!1},_getParamValuesObject:function(a){for(var b= | ||
this._router.shouldTypecast,c=g.getParamValues(a,this._matchRegexp,b),d={},f=c.length;f--;)d[f]=c[f],this._paramsIds&&(d[this._paramsIds[f]]=c[f]);d.request_=b?l(a):a;return d},dispose:function(){this._router.removeRoute(this)},_destroy:function(){this.matched.dispose();this.matched=this._pattern=this._matchRegexp=null},toString:function(){return'[Route pattern:"'+this._pattern+'", numListeners:'+this.matched.getNumListeners()+"]"}};g=j.patternLexer=function(){var a=/[\\.+*?\^$\[\](){}\/'#]/g,b=/\/$/g, | ||
c=/([:}]|\w(?=\/))\/?(:)/g,d=/\{([^}]+)\}/g,f=/:([^:]+):/g,g=/(?:\{|:)([^}:]+)(?:\}|:)/g,h=RegExp("___CR_REQ___","g"),i=RegExp("___CR_OPT___","g"),j=RegExp("___CR_OPT_SLASH___","g");return{getParamIds:function(a){for(var b=[],c;c=g.exec(a);)b.push(c[1]);return b},getParamValues:function(a,b,c){if(a=b.exec(a))if(a.shift(),c){c=a;a=c.length;for(b=[];a--;)b[a]=l(c[a]);a=b}return a},compilePattern:function(e){if(e=e||"")e=e.replace(b,""),e=e.replace(c,"$1___CR_OPT_SLASH___$2"),e=e.replace(f,"___CR_OPT___"), | ||
e=e.replace(d,"___CR_REQ___"),e=e.replace(a,"\\$&"),e=e.replace(j,"\\/?"),e=e.replace(i,"([^\\/]+)?/?"),e=e.replace(h,"([^\\/]+)");return RegExp("^"+e+"/?$")}}}();n.crossroads=j})(window||this); | ||
(function(h){h(["signals"],function(f){function h(a,b){for(var c=a.length;c--;)if(a[c]===b)return c;return-1}function j(a,b){return"[object "+a+"]"===Object.prototype.toString.call(b)}function m(a){return a===null?a:o.test(a)?a.toLowerCase()==="true":a===""||isNaN(a)?a:parseFloat(a)}function l(){this._routes=[];this.bypassed=new f.Signal;this.routed=new f.Signal}function n(a,b,c,d){var g=j("RegExp",a);this._router=d;this._pattern=a;this._paramsIds=g?null:i.getParamIds(this._pattern);this._optionalParamsIds= | ||
g?null:i.getOptionalParamsIds(this._pattern);this._matchRegexp=g?a:i.compilePattern(a);this.matched=new f.Signal;b&&this.matched.add(b);this._priority=c||0}var k,i,o=/^(true|false)$/i;l.prototype={create:function(){return new l},shouldTypecast:!1,addRoute:function(a,b,c){a=new n(a,b,c,this);this._sortedInsert(a);return a},removeRoute:function(a){var b=h(this._routes,a);b>=0&&this._routes.splice(b,1);a._destroy()},removeAllRoutes:function(){for(var a=this.getNumRoutes();a--;)this._routes[a]._destroy(); | ||
this._routes.length=0},parse:function(a){var a=a||"",b=this._getMatchedRoute(a),c=b?b._getParamsArray(a):null;b?(c?b.matched.dispatch.apply(b.matched,c):b.matched.dispatch(),this.routed.dispatch(a,b,c)):this.bypassed.dispatch(a)},getNumRoutes:function(){return this._routes.length},_sortedInsert:function(a){var b=this._routes,c=b.length;do--c;while(b[c]&&a._priority<=b[c]._priority);b.splice(c+1,0,a)},_getMatchedRoute:function(a){for(var b=this._routes,c=b.length,d;d=b[--c];)if(d.match(a))return d; | ||
return null},toString:function(){return"[crossroads numRoutes:"+this.getNumRoutes()+"]"}};k=new l;k.VERSION="0.6.0";n.prototype={rules:void 0,match:function(a){return this._matchRegexp.test(a)&&this._validateParams(a)},_validateParams:function(a){var b=this.rules,c=this._getParamValuesObject(a),d;for(d in b)if(b.hasOwnProperty(d)&&!this._isValidParam(a,d,c))return!1;return!0},_isValidParam:function(a,b,c){var d=this.rules[b],g=c[b],f;g==null&&this._optionalParamsIds&&h(this._optionalParamsIds,b)!== | ||
-1?f=!0:j("RegExp",d)?f=d.test(g):j("Array",d)?f=h(d,g||"")!==-1:j("Function",d)&&(f=d(g,a,c));return f||!1},_getParamValuesObject:function(a){for(var b=this._router.shouldTypecast,c=i.getParamValues(a,this._matchRegexp,b),d={},g=c.length;g--;)d[g]=c[g],this._paramsIds&&(d[this._paramsIds[g]]=c[g]);d.request_=b?m(a):a;return d},_getParamsArray:function(a){var b=this._getParamValuesObject(a),c=this.rules?this.rules.normalize_:null;return j("Function",c)?c(a,b):i.getParamValues(a,this._matchRegexp, | ||
this._router.shouldTypecast)},dispose:function(){this._router.removeRoute(this)},_destroy:function(){this.matched.dispose();this.matched=this._pattern=this._matchRegexp=null},toString:function(){return'[Route pattern:"'+this._pattern+'", numListeners:'+this.matched.getNumListeners()+"]"}};i=k.patternLexer=function(){var a=/[\\.+*?\^$\[\](){}\/'#]/g,b=/\/$/g,c=/([:}]|\w(?=\/))\/?(:)/g,d=/([:}])\/?(\{)/g,g=/\{([^}]+)\}/g,f=/:([^:]+):/g,h=/(?:\{|:)([^}:]+)(?:\}|:)/g,i=RegExp("___CR_REQ___","g"),j=RegExp("___CR_OPT___", | ||
"g"),k=RegExp("___CR_OPT_SLASH___","g"),l=RegExp("___CR_REQ_SLASH___","g");return{getParamIds:function(a){for(var b=[],c;c=h.exec(a);)b.push(c[1]);return b},getOptionalParamsIds:function(a){for(var b=[],c;c=f.exec(a);)b.push(c[1]);return b},getParamValues:function(a,b,c){if(a=b.exec(a))if(a.shift(),c){c=a;a=c.length;for(b=[];a--;)b[a]=m(c[a]);a=b}return a},compilePattern:function(e){if(e=e||"")e=e.replace(b,""),e=e.replace(c,"$1___CR_OPT_SLASH___$2"),e=e.replace(d,"$1___CR_REQ_SLASH___$2"),e=e.replace(f, | ||
"___CR_OPT___"),e=e.replace(g,"___CR_REQ___"),e=e.replace(a,"\\$&"),e=e.replace(k,"\\/?"),e=e.replace(l,"\\/"),e=e.replace(j,"([^\\/]+)?/?"),e=e.replace(i,"([^\\/]+)");return RegExp("^"+e+"/?$")}}}();return k})})(typeof require==="undefined"?function(h,f){this.crossroads=f(signals)}:typeof exports==="undefined"?function(h,f){define("crossroads",h,f)}:function(h,f){module.exports=f.apply(this,h.map(require))}); |
@@ -6,3 +6,3 @@ { | ||
"homepage" : "http://millermedeiros.github.com/crossroads.js/", | ||
"version" : "0.5.0", | ||
"version" : "0.6.0", | ||
"author" : "Miller Medeiros", | ||
@@ -13,3 +13,3 @@ "repository" : { | ||
}, | ||
"main" : "dist/crossroads.cjs.js", | ||
"main" : "dist/crossroads.js", | ||
"bugs" : { | ||
@@ -16,0 +16,0 @@ "web" : "https://github.com/millermedeiros/crossroads.js/issues" |
@@ -42,4 +42,2 @@ | ||
* crossroads.js : Uncompressed source code with comments. | ||
* crossroads.amd.js : Uncompressed source code wrapped as an [asynchronous module](http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition) to be used together with [RequireJS](http://requirejs.org/) or any other AMD loader. | ||
* crossroads.cjs.js : Uncompressed source code wrapped as an [CommonJS module](http://wiki.commonjs.org/wiki/Modules/1.1) to be used on [nodejs](http://nodejs.org/) or any other environment that supports CommonJS modules. | ||
* crossroads.min.js : Compressed code. | ||
@@ -85,1 +83,26 @@ | ||
## Running unit tests ## | ||
### On the browser ### | ||
Open `dev/tests/spec_runner-dist.html` on your browser. | ||
`spec_runner-dist` tests `dist/crossroads.js` and `spec_runner-dev` tests files inside | ||
`dev/src` - they all run the same specs. | ||
### On Node.js ### | ||
Install [npm](http://npmjs.org) and run: | ||
``` | ||
npm install jasmine-node -g | ||
npm link | ||
jasmine-node dev/tests/spec | ||
``` | ||
Note that node.js can only run the distribution file, so any change to the | ||
`dev/src` files will require a new `ant compile`. `npm link` takes care of | ||
installing dependencies and [updating](https://github.com/isaacs/npm/blob/master/doc/link.md) | ||
crossroads at each change to the `crossroads.cjs.js` file. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
107
22984
8
318
1