Initial commit

This commit is contained in:
Tore Darell 2008-04-17 11:47:13 +02:00
commit 2ea0ee5b85
12 changed files with 761 additions and 0 deletions

View file

@ -0,0 +1,41 @@
//Michael Schuerig
Route.Object = function (url) {
this.url = url;
};
Route.Object.prototype = {
toString: function() { return this.url; }
};
//Replace Route.prototype.generate
(function(oldGenerate){
Route.prototype.generate = function(){
var path = oldGenerate.apply(this, arguments);
return path && new Route.Object(path);
};
})(Route.prototype.generate);
if (window.Prototype) {
Object.extend(Route.Object.prototype, {
get: function(options) { this.method = 'get'; return this.request(options) },
post: function(options) { this.method = 'post'; return this.request(options) },
put: function(options) { this.method = 'put'; return this.request(options) },
'delete': function(options) { this.method = 'delete'; return this.request(options) },
request: function(options) {
var result = this;
options = options || {};
var async = $H(options).any(function(p) { return /^on[A-Z1-5]/.test(p[0]); });
options = Object.extend({ asynchronous: async, method: this.method }, options);
if (!async) {
options.onComplete = function(r) { result = r.responseText; };
}
new Ajax.Request(this.url, options);
return result;
}
});
}

18
lib/javascripts/routes-min.js vendored Normal file
View file

@ -0,0 +1,18 @@
(function(){var iterate=function(o,fn){if(typeof o.length==='number'){for(var i=0;i<o.length;i++){if(fn(o[i],i,o)===false){return false;}}
return true;}else{for(var p in o){if(o.hasOwnProperty(p)){fn(p,o[p]);}}}};var all=function(arr,fn){var allTrue=true;iterate(arr,function(e,i,a){if(!fn(e,i,a)){allTrue=false;return false;}});return allTrue;};var extend=function(target,source){iterate(source,function(k,v){target[k]=v;});return target;};var merge=function(t,s){var rv={};extend(rv,t);extend(rv,s);return rv;};var Route=function(segments,params,name){this.segments=segments||[];this.params=params||{};this.name=name;};Route.prototype={generate:function(pa,op){var options=merge(Routes.defaultOptions,op||{});var params=options.noDefaults?merge({},pa||{}):merge(Routes.defaultParams,pa||{});var path='';var hasParam=false;var routeMatch=true;iterate(this.params,function(k,v){hasParam=false;if((typeof v==='string'&&v===params[k])||((v.constructor===RegExp)&&(new RegExp('^'+v.source+'$')).test(params[k]))){hasParam=true;delete params[k];}
if(!hasParam){routeMatch=false;return;}});if(!routeMatch){return false;}
try{iterate(this.segments,function(segment,index,segments){switch(segment.type){case'divider':path=path+segment.value;break;case'static':path=path+segment.value;break;case'dynamic':if(params[segment.value]){path=path+params[segment.value];delete params[segment.value];}else if(!segment.optional){throw'nomatch';}else{delete params[segment.value];throw'done';}
break;case'path':if(params[segment.value]){if(params[segment.value]instanceof Array){path=path+params[segment.value].join('/');}else{path=path+(params[segment.value]||'');}
delete params[segment.value];}else if(!segment.optional){throw'nomatch';}else{delete params[segment.value];throw'done';}
break;}});}catch(e){if(e!=='done'){if(e==='nomatch'){return false;}else{throw e;}}}
if(!options.includeSlash&&path.match(/.+\/$/)){path=path.slice(0,-1);}
if(!options.onlyPath){var portString=options.port?':'+options.port:'';path=[options.protocol,options.host,portString,path].join('')}
var leftOvers=[];iterate(params,function(k,v){leftOvers.push(k+'='+v);});if(leftOvers.length>0){path=path+'?'+leftOvers.join('&');}
if(options.escape){path=encodeURI(path);}
return path;},toString:function(){return this.segments.join('');}};Route.Segment=function(value,type,optional){this.value=value;this.type=type||'static';this.optional=(typeof optional==='boolean'?optional:true);};Route.Segment.prototype={isDynamic:function(){return this.type==='dynamic'||this.type==='path';},toString:function(){if(this.type==='dynamic'){return':'+this.value;}else if(this.type==='path'){return'*'+this.value;}else{return this.value;}},equal:function(other){return other.constructor===this.constructor&&other.value===this.value&&other.type===this.type&&other.optional===this.optional;}};Route.createSegment=function(s,optional){if(s.match(/^[\/;?.]$/)){return new Route.Segment(s,'divider',optional);}else if(s.indexOf(':')===0){return new Route.Segment(s.slice(1),'dynamic',optional);}else if(s.indexOf('*')===0){return new Route.Segment(s.slice(1),'path',optional);}else{return new Route.Segment(s,'static',optional);}};Route.S=Route.createSegment;var Routes=[];Routes.named=[];Routes.defaultParams={action:'index'};Routes.defaultOptions={escape:true,port:window.location.port,protocol:window.location.protocol+'//',host:window.location.hostname};Routes.extractNamed=function(){var route;for(var i=0;i<this.length;i++){route=this[i];if(route.name){this.named.push(route);this.named[route.name]=route;this[route.name]=(function(route){var fn=function(){var params={},options={},count;for(var p in route.params){if(route.params.hasOwnProperty(p)&&route.params[p].constructor!==RegExp){params[p]=route.params[p];}}
if(typeof arguments[0]==='object'&&!(arguments[0]instanceof Array)){extend(params,arguments[0]);options=arguments[1];}else{if(typeof arguments[arguments.length-1]==='object'){options=arguments[arguments.length-1];}
var count=0;for(var i=0;i<route.segments.length;i++){if(route.segments[i].isDynamic()){if(arguments.length>count){params[route.segments[i].value]=arguments[count];}
count++;}}}
return route.generate(params,options);};fn.toParams=function(params){return merge(route.params,params||{});};return fn;})(route);}}};Routes.generate=function(params,options){params=params||{};var path;for(var i=0;i<this.length;i++){path=this[i].generate(params,options);if(path){return path;}}
return false;};Routes.named.toString=Routes.toString=function(){return this.join(', ');};window['Route']=Route;window['Routes']=Routes;})();

275
lib/javascripts/routes.js Normal file
View file

@ -0,0 +1,275 @@
(function(){
var iterate = function(o, fn){
if (typeof o.length === 'number') {//Array
for (var i = 0; i < o.length; i++) {
//Stop iterating if return value is false
if (fn(o[i], i, o) === false){ return false; }
}
return true;//All done
} else {//Object
for (var p in o){
if (o.hasOwnProperty(p)) {
fn(p, o[p]);
}
}
}
};
var all = function(arr, fn){
var allTrue = true;
iterate(arr, function(e,i,a){
if (!fn(e,i,a)) { allTrue = false; return false; }
});
return allTrue;
};
var extend = function(target, source){
iterate(source, function(k,v){ target[k] = v; });
return target;
};
var merge = function(t,s){
var rv = {};
extend(rv, t);
extend(rv, s);
return rv;
};
var Route = function(segments, params, name){
this.segments = segments || [];
this.params = params || {};
this.name = name;
};
Route.prototype = {
generate: function(pa, op){
var options = merge(Routes.defaultOptions, op || {});
var params = options.noDefaults ? merge({}, pa || {}) : merge(Routes.defaultParams, pa || {});
var path = '';
var hasParam = false;
var routeMatch = true;
iterate(this.params, function(k,v){
hasParam = false;
if (
(typeof v === 'string' && v === params[k]) ||
((v.constructor === RegExp) && (new RegExp('^'+v.source+'$')).test(params[k]))
) {
hasParam = true;
delete params[k];
}
if (!hasParam) {
routeMatch = false;
return;
}
});
if (!routeMatch) {
return false;
}
try {
iterate(this.segments, function(segment, index, segments){
switch (segment.type) {
case 'divider':
path = path + segment.value;
break;
case 'static':
path = path + segment.value;
break;
case 'dynamic':
if (params[segment.value]) {
path = path + params[segment.value];
delete params[segment.value];
} else if (!segment.optional) {
throw 'nomatch';
} else {
delete params[segment.value];
throw 'done';
}
break;
case 'path':
if (params[segment.value]) {
if (params[segment.value] instanceof Array) {
path = path + params[segment.value].join('/');
} else {
path = path + (params[segment.value] || '');
}
delete params[segment.value];
} else if (!segment.optional) {
throw 'nomatch';
} else {
delete params[segment.value];
throw 'done';
}
break;
}
});
} catch (e) {
if (e !== 'done') { //done == don't append any more segments
if (e === 'nomatch') { //params don't match this route
return false;
} else {
throw e;
}
}
}
if (!options.includeSlash && path.match(/.+\/$/)) {
path = path.slice(0,-1);
}
if (!options.onlyPath) {
var portString = options.port ? ':'+options.port : '';
path = [options.protocol, options.host, portString, path].join('')
}
var leftOvers = [];
iterate(params, function(k,v){
leftOvers.push(k + '=' + v);
});
if (leftOvers.length > 0) {
path = path + '?' + leftOvers.join('&');
}
if (options.escape) {
path = encodeURI(path);
}
return path;
},
toString: function(){
return this.segments.join('');
}
};
Route.Segment = function(value, type, optional){
this.value = value;
this.type = type || 'static';
this.optional = (typeof optional === 'boolean' ? optional : true);
};
Route.Segment.prototype = {
isDynamic: function(){
return this.type === 'dynamic' || this.type === 'path';
},
toString: function(){
if (this.type === 'dynamic') {
return ':'+this.value;
} else if (this.type === 'path') {
return '*'+this.value;
} else {
return this.value;
}
},
equal: function(other){
return other.constructor === this.constructor && other.value === this.value &&
other.type === this.type && other.optional === this.optional;
}
};
Route.createSegment = function(s, optional){
if (s.match(/^[\/;?.]$/)) {
return new Route.Segment(s, 'divider', optional);
} else if (s.indexOf(':') === 0) {
return new Route.Segment(s.slice(1), 'dynamic', optional);
} else if (s.indexOf('*') === 0) {
return new Route.Segment(s.slice(1), 'path', optional);
} else {
return new Route.Segment(s, 'static', optional);
}
};
Route.S = Route.createSegment;
var Routes = [];
Routes.named = [];
Routes.defaultParams = {action:'index'};//Default parameters for route generation
Routes.defaultOptions = {//Defaults for second parameter
escape: true,
port: window.location.port,
protocol: window.location.protocol+'//',
host: window.location.hostname
};
Routes.extractNamed = function(){
var route;
for (var i = 0; i < this.length; i++) {
route = this[i];
if (route.name) {
this.named.push(route);
this.named[route.name] = route;
this[route.name] = (function(route){
var fn = function(){
var params = {},
options = {},
count;
//Add defaults from route
for (var p in route.params) {
if (route.params.hasOwnProperty(p) && route.params[p].constructor !== RegExp) {
params[p] = route.params[p];
}
}
//Allows Routes.name('foo', 'bar', {opts}) or Routes.name({foo:'foo', bar:'bar'}, {opts})
if (typeof arguments[0] === 'object' && !(arguments[0] instanceof Array)) {
extend(params, arguments[0]);
options = arguments[1];
} else {
if (typeof arguments[arguments.length-1] === 'object') {
options = arguments[arguments.length-1];
}
var count = 0;
for (var i=0; i < route.segments.length; i++) {
if (route.segments[i].isDynamic()) {
if (arguments.length > count) { params[route.segments[i].value] = arguments[count]; }
count++;
}
}
}
return route.generate(params, options);
};
//Routes.name.toParams() => {...}
//Like hash_for_x in Rails, kind of
fn.toParams = function(params){
return merge(route.params, params || {});
};
return fn;
})(route); //Pass the route to keep it in scope
}
}
};
Routes.generate = function(params, options){
params = params || {};
var path;
for (var i = 0; i < this.length; i++) {
path = this[i].generate(params, options);
if (path) {
return path;
}
}
return false;
};
Routes.named.toString = Routes.toString = function(){
return this.join(', ');
};
window['Route'] = Route;
window['Routes'] = Routes;
})();