Changeset 9111
- Timestamp:
- 06/13/08 11:46:44 (3 months ago)
- Files:
-
- sandbox/aida/demo-app/app/controllers/article_controller.js (modified) (1 diff)
- sandbox/aida/demo-app/app/controllers/root_controller.js (modified) (1 diff)
- sandbox/aida/demo-app/app/controllers/say_controller.js (modified) (1 diff)
- sandbox/aida/demo-app/app/controllers/twitter_controller.js (modified) (1 diff)
- sandbox/aida/demo-app/app/routes/article_routes.js (modified) (1 diff)
- sandbox/aida/demo-app/app/routes/root_routes.js (modified) (1 diff)
- sandbox/aida/demo-app/app/views/article/delete.html.skin (modified) (1 diff)
- sandbox/aida/demo-app/app/views/article/edit.html.skin (modified) (1 diff)
- sandbox/aida/demo-app/app/views/article/show.html.skin (modified) (1 diff)
- sandbox/aida/demo-app/app/views/say/skin.html.skin (added)
- sandbox/aida/demo-app/main.js (modified) (2 diffs)
- sandbox/aida/modules/aida/appLoader.js (deleted)
- sandbox/aida/modules/aida/controller.js (modified) (8 diffs)
- sandbox/aida/modules/aida/loader.js (deleted)
- sandbox/aida/modules/aida/routing.js (modified) (22 diffs)
- sandbox/aida/modules/aida/twitter.js (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
sandbox/aida/demo-app/app/controllers/article_controller.js
r9100 r9111 7 7 importModule('app.orm.hibernate', 'db'); 8 8 9 this.actions = { 9 function ArticleController(req, res, session) { 10 11 this.actions = { 10 12 11 index : function() {12 this.context.articles = db.find('from Article a order by a.createTime desc')13 },13 index : function() { 14 this.context.articles = db.find('from Article a order by a.createTime desc') 15 }, 14 16 15 "new" : function() {},17 "new" : function() {}, 16 18 17 create : function() {18 model.doCreate(req.data);19 res.redirect('/blog');20 },19 create : function() { 20 model.doCreate(req.data); 21 res.redirect('/blog'); 22 }, 21 23 22 show : function() {23 this.context.article = db.get('Article', req.data.id);24 },24 show : function() { 25 this.context.article = db.get('Article', req.data.id); 26 }, 25 27 26 edit : function() {27 this.context.article = db.get('Article', req.data.id);28 },28 edit : function() { 29 this.context.article = db.get('Article', req.data.id); 30 }, 29 31 30 update : function() { 31 model.doUpdate(req.data); 32 res.redirect('/blog/' + req.data.id); 33 }, 32 update : function() { 33 logger.info(uneval(req.data)) 34 model.doUpdate(req.data); 35 res.redirect('/blog/'); 36 return; 37 res.write("danke"); return; 38 res.redirect('/blog/' + req.data.id); 39 }, 34 40 35 "delete" : function() {36 this.context.article = db.get('Article', req.data.id);37 },41 "delete" : function() { 42 this.context.article = db.get('Article', req.data.id); 43 }, 38 44 39 destroy : function() { 40 model.doDelete(req.data.id); 41 res.redirect('/blog'); 42 } 45 destroy : function() { 46 model.doDelete(req.data.id); 47 res.redirect('/blog'); 48 } 49 } 43 50 44 51 } sandbox/aida/demo-app/app/controllers/root_controller.js
r9100 r9111 1 1 importFromModule("aida.controller", "*"); 2 2 3 function index_action() { 4 this.context.hello = "Hello World!"; 5 // calls views/root/index.html 3 function RootController(req, res, session) { 4 5 this.index_action = function() { 6 this.context.hello = "Hello World!"; 7 // calls views/root/index.html 8 } 9 10 this.ejs_action = function() { 11 this.context.hello = "Hello World!"; 12 } 13 6 14 } 7 8 function ejs_action() {9 this.context.hello = "Hello World!";10 }11 12 function env_action() {13 window.location = "http://alistapart.com/";14 res.write("global.window:" + window.document)15 return;16 var o = new Object();17 load("foo.js");18 return;19 20 window.onload = function(){21 res.write("Newest A List Apart Posts:");22 $("h4.title").each(function(){23 res.write(" - " + this.textContent);24 });25 };26 }sandbox/aida/demo-app/app/controllers/say_controller.js
r9100 r9111 2 2 3 3 foo("bar", "Bar"); 4 var foo1 = "Foo 1"; 4 5 5 function SayController() { 6 shell.writeln("---" + this.constructor.name) 6 function foo2_action() { 7 // -> /say/foo2 8 // can't access res!! 9 // throws an error 10 res.write(foo1) 7 11 } 8 12 9 function index_action() { 10 res.writeln("---" + this.getShortName()) 11 res.writeln("---" + this.routes.getAll()) 12 // this will call views/root/index.html by default 13 function SayController(req, res, session) { 14 15 this.bla = "bla" 16 17 function hidden() { 18 res.writeln("oops"); 19 } 20 21 this.skin_action = function() { 22 // render("hello"); 23 } 24 25 this.index_action = function() { 26 res.writeln("---" + getShortName()) 27 res.writeln("---" + this.foo1) 28 res.writeln("---" + this.foo2) 29 } 30 31 this.actions = { 32 goodBye : function() { 33 render({ 34 inline : '<div> \ 35 <h2>Good Bye <% name %>!</h2> \ 36 <p>and have a nice day.</p> \ 37 </div>', 38 locals : { 39 name : "Matthias" 40 } 41 }); 42 }, 43 index2 : function() { 44 render(req, res, session); 45 } 46 } 47 48 this.actions.html = { 49 hello3 : function() { 50 51 }, 52 hello2 : function() { 53 res.writeln("xx") 54 } 55 } 56 57 this.hello_action = function() { 58 hidden(); 59 res.writeln("Hello World!" + __name__ + ":" + bar + ":" + getShortName()); 60 } 61 13 62 } 14 63 15 actions = {16 goodBye : function() {17 render({18 inline : '<div> \19 <h2>Good Bye <% name %>!</h2> \20 <p>and have a nice day.</p> \21 </div>',22 locals : {23 name : "Matthias"24 }25 });26 },27 index2 : function() {28 render();29 }30 }31 32 actions.html = {33 hello3 : function() {34 35 }36 }37 38 function hello_action() {39 render({action:"hello2"});40 return;41 hidden();42 res.writeln("Hello World!" + __name__ + ":" + bar + ":" + shortName());43 }44 45 function hidden() {46 res.writeln("oops");47 }48 sandbox/aida/demo-app/app/controllers/twitter_controller.js
r9100 r9111 7 7 importModule("aida.prototype", "prototype"); 8 8 9 function TwitterController(req, res, session) { 10 11 this.index_action = function() {}; 9 12 10 function index_action() {} 11 12 13 function friends_action() { 14 if (!req.data.id) { 15 res.redirect("/twitter"); 16 } 17 this.timeline = twitter.userTimeline({ 18 id : req.data.id 19 }); 13 this.friends_action = function () { 14 if (!req.data.id) { 15 res.redirect("/twitter"); 16 } 17 this.timeline = twitter.userTimeline({ 18 id : req.data.id 19 }); 20 } 21 20 22 } sandbox/aida/demo-app/app/routes/article_routes.js
r9100 r9111 1 importModule("aida.routing" , "routing");1 importModule("aida.routing"); 2 2 3 ArticleController.routes.draw( routing.RESTFUL_ROUTES ); 3 var routeSet = new aida.routing.RouteSet("article").add( 4 aida.routing.RESTFUL_ROUTES 5 ); sandbox/aida/demo-app/app/routes/root_routes.js
r9090 r9111 1 importFromModule("aida.routing", "RouteSet"); 1 2 2 RootController.routes.draw([ 3 var routeSet = new RouteSet("root").add([ 3 4 { 4 5 pattern : "/blog->", 5 forwardTo : ArticleController6 forwardTo : "article" 6 7 }, 7 { 8 pattern : "/$controller/$action/$id", 9 } 8 "/$controller/$action/$id" 10 9 ]); sandbox/aida/demo-app/app/views/article/delete.html.skin
r9100 r9111 6 6 </div> 7 7 8 <form action="/blog/<% param .id %>?method=DELETE" method="post" accept-charset="utf-8">8 <form action="/blog/<% params.id %>?method=DELETE" method="post" accept-charset="utf-8"> 9 9 <input type="hidden" name="id" value="<% id %>" /> 10 10 <p> sandbox/aida/demo-app/app/views/article/edit.html.skin
r9100 r9111 10 10 </div> 11 11 12 <form action="/blog/<% param .id %>?method=PUT" method="post" accept-charset="utf-8">12 <form action="/blog/<% params.id %>?method=PUT" method="post" accept-charset="utf-8"> 13 13 <input type="hidden" name="id" value="<% id %>" /> 14 14 <p> sandbox/aida/demo-app/app/views/article/show.html.skin
r9100 r9111 14 14 <small> 15 15 <i>posted: BUG!</i><br /> 16 <a href="/blog/<% param .id %>/edit">» Edit this article</a> | <a href="/blog/<% param.id %>/delete">» Delete this article</a>16 <a href="/blog/<% params.id %>/edit">» Edit this article</a> | <a href="/blog/<% params.id %>/delete">» Delete this article</a> 17 17 </small> 18 18 </p> sandbox/aida/demo-app/main.js
r9090 r9111 1 1 importModule('helma.app', 'app'); 2 2 importModule('helma.rhino', 'rhino'); 3 importModule('helma.logging', 'logging'); 4 importModule("helma.shell", "shell"); 5 // this is just for convinience while developing/debugging aida - i will remove this in the future 6 global.shell = shell; 7 global.logger = logging.getLogger(__name__); 8 3 9 importFromModule("helma.file", "File"); 4 global.APP_DIR = new File(""); 10 // try to fix this with helma-ng 0.3 11 global.APP_DIR = new File(getResource(".").name); 5 12 6 // load app dirs 7 import Module("modules.appLoader");13 importModule("aida.controller"); 14 importFromModule("aida.routing", "RouteSet"); 8 15 9 16 // main method called to start application … … 11 18 app.start({ staticDir: 'static' }); 12 19 } 20 21 /** 22 * Helma-NG handler function that connects to the Helma servlet. 23 * 24 * @param {object} req will be passed by helma-ng 25 * @param {object} res will be passed by helma-ng 26 * @param {object} session will be passed by helma-ng 27 */ 28 global.handleRequest = function(req, res, session) { 29 global.req = req; 30 global.res = res; 31 global.session = session; 32 aida.controller.handleRequest("root", req, res, session); 33 } 34 35 /* 36 var rs = RootRoutes = new RouteSet("root").draw(function() { 37 this.connect("/blog->", { forwardTo : "article" }); 38 this.connect("/$controller/$action/$id"); 39 }); 40 rs.add(["/my/own/route"]); 41 res.writeln(rs.routes.join("\n")); 42 res.writeln(rs.recognizePath("POST /say/hello")); 43 // res.writeln(rs.generate({path:"/blog/hello"})); 44 res.writeln(rs.generate({controller:"foo", action:"hello", id:"11"})); 45 */ sandbox/aida/modules/aida/controller.js
r9100 r9111 4 4 importModule('prototype'); 5 5 importModule('routing'); 6 6 7 importFromModule("loader", "loadHelpers"); 7 8 importFromModule("config.environments.development", "config"); 8 9 9 function instance() { 10 this.context = {}; 11 return new this["ctor"](); 12 } 13 10 this.context = {}; 11 12 function getControllerInstance(name, req, res, session) { 13 importModule("app.controllers." + name + "_controller"); 14 var ctor = app.controllers[name + "_controller"][getClassNameFromName(name)]; 15 ctor.prototype = app.controllers[name + "_controller"]; 16 ctor.prototype.__name__ = getClassNameFromName(name); 17 var c = new ctor(req, res, session); 18 c.importHelpers("application") 19 c.importHelpers(name) 20 return c; 21 } 22 23 function getClassNameFromName(name) { 24 return name.capitalize() + "Controller"; 25 } 14 26 15 27 /** … … 18 30 * 19 31 * @param {object} controller Controller object 20 * @param {object} req Request object 32 * @param {object} req Request object, passed by helma-ng 33 * @param {object} res Response object, passed by helma-ng 34 * @param {object} session Session object, passed by helma-ng 21 35 */ 22 function handleRequest(controller, req) { 23 var route = req.route = req.route || routing.recognizeRequest(req, controller); 36 function handleRequest(controllerName, req, res, session) { 37 var routeSet = routing.loadRoutes(controllerName).routeSet; 38 var route = req.route = req.route || routeSet.recognizeRequest(req); 24 39 if (!route) return; // FIXME 404 25 logger.info("found route:" + route.toString()); 40 var controller = getControllerInstance(route.controllerName, req, res, session); 41 26 42 Object.extend(req.data, route.params); 43 Object.extend(req.params, route.params); 27 44 28 if (route.controller) controller = route.controller;29 if (typeof controller === "string") controller = global[controller.capitalize() + "Controller"];30 45 route.handler = controller.getAction(route); 31 logger.info("route.handler:"+route.handler)32 46 var content = ""; 33 47 res.push(); 34 try {48 // try { 35 49 route.handler.call(controller); 36 } catch(e) {50 /* } catch(e) { 37 51 res.write(e.rhinoException); 38 } 52 } */ 39 53 content = res.pop(); 40 if (!res.calledRender === true) controller.render(content);54 (res.calledRender) ? res.write(content) : controller.render(); 41 55 } 42 56 … … 217 231 */ 218 232 function render(options) { 233 if (!res.contentType) res.contentType = routing.Formats.getMimeType(req.route.format); 219 234 if (!options) options = {}; 220 235 if (res.calledRender) throw new DoubleRenderError(); … … 267 282 } 268 283 } else { 269 var type = determineTemplateType({action:action});284 var type = this.determineTemplateType({action:action, format:req.route.format}); 270 285 if (type === "est") { 271 286 var resource = this.getTemplateSource({action:action, type:type}); … … 276 291 res.write(result); 277 292 } else if (type === "skin") { 278 helma.skin.render( getTemplatePath({action:action, type:type}), context);293 helma.skin.render(this.getTemplatePath({action:action, type:type}), context); 279 294 } else if (type) { 280 helma.skin.render( getTemplatePath({action:action, type:type}), context);295 helma.skin.render(this.getTemplatePath({action:action, type:type}), context); 281 296 } else { 282 res.writeln("Couldn't find " + this.getTemplateSource( action));297 res.writeln("Couldn't find " + this.getTemplateSource({action:action, type:type || "skin"})); 283 298 } 284 299 } … … 294 309 295 310 function determineTemplateType(options) { 296 var types = ["est", "ejs", "skin", ((req.route.format) || options.format)];311 var types = ["est", "ejs", "skin", options.format]; 297 312 for (var i=0; i<types.length; i++) { 298 if ( getTemplateSource(Object.extend(options, {type:types[i]})).exists()) {313 if (this.getTemplateSource(Object.extend(options, {type:types[i]})).exists()) { 299 314 return types[i]; 300 315 } … … 304 319 305 320 function getTemplateSource(options) { 306 return getResource(this.getTemplatePath(options));321 return this.getResource(this.getTemplatePath(options)); 307 322 } 308 323 309 324 function getTemplatePath(options) { 325 logger.info(uneval(options)) 310 326 var options = Object.extend({ 311 action : req.route.action,312 controller : (typeof req.route.controller === "string") ? req.route.controller : req.route.controller.getShortName(),313 format : (req.route.format) ||"html",327 action : "index", 328 controller : this.getShortName(), 329 format : "html", 314 330 type : "skin" 315 }, options) 316 return (config.templateRoot || "app/views") + '/' + options.controller + '/' + options.action + '.' + options.format + ((options.type != options.format) ? ('.' + options.type) : ''); 331 }, options || {}); 332 var result = (config.templateRoot || "app/views") + '/' + options.controller + '/' + options.action + '.' + options.format + ((options.type != options.format) ? ('.' + options.type) : ''); 333 return result; 317 334 } 318 335 … … 322 339 323 340 function getShortName() { 324 var namePattern = /^(.*)Controller$/ i341 var namePattern = /^(.*)Controller$/; 325 342 return this.__name__.match(namePattern)[1].toLowerCase(); 326 343 } sandbox/aida/modules/aida/routing.js
r9100 r9111 1 1 importModule("helma.shell", "shell"); 2 2 importModule("prototype"); 3 4 __shared__ = true; 3 5 4 6 /** … … 13 15 * generate your application in the file app/routes/root_routes.js: 14 16 * <pre language=JavaScript> 15 * RootController.routes.draw([17 * var RootController.routes.draw([ 16 18 * { 17 19 * pattern : "/$controller/$action/$id" … … 128 130 129 131 132 function loadRoutes(name) { 133 importModule("app.routes." + name + "_routes"); 134 return app.routes[name + "_routes"]; 135 } 136 137 130 138 /** 131 * Tries to resolve the incoming request, for a given controller. 132 * If no controller is specified it will fall back to RootController. 139 * Tries to resolve the incoming request, for a given RouteSet. 133 140 * 134 * @param { object} req Request object135 * @param { object} [controller] Controller object, defaults to RootController136 * @return { object} Returns the result object from Route.match()141 * @param {Object} [RouteSet] RoutSet, to be checked for matching routes. 142 * @param {Object} req Request object 143 * @return {Object} Returns the result object from Route.match() 137 144 */ 138 function recognizeRequest(req, controller) { 145 function recognizeRequest(routeSet, req) { 146 var routes = routeSet.routes; 139 147 var result; 140 var controller = controller || RootController.instance();141 var routes = (controller.routes || controller.__proto__.routes).getAll();142 148 for (var i=0; i<routes.length; i++) { 143 149 var result = routes[i].match(req); 144 150 if (result) { 145 151 if (result.forwardTo) { 146 return recognizeRequest(req, result.forwardTo) 152 var routeSet = loadRoutes(result.forwardTo).routeSet; 153 return recognizeRequest(routeSet, req) 147 154 } else { 148 logger.info("found:" + result)149 155 return result; 150 156 } … … 156 162 157 163 /** 158 * Tries to resolve a path with optionals parameters, for a given controller. 159 * If no controller is specified it will fall back to RootController. 164 * Tries to resolve a path with optionals parameters, for a given RouteSet. 160 165 * 161 * @param { string} path Request path162 * @param { object} options Request ooptions163 * @ config {string} method HTTP method164 * @param { object} [controller] Controller object, defaults to RootController165 * @return { object} Returns the result object from Route.match()166 * @param {Object} [RouteSet] RoutSet, to be checked for matching routes. 167 * @param {String} path Request path 168 * @param {Object} params Request params 169 * @param {String} [params.method] HTTP method (uppercase), defaults to "GET" 170 * @return {Object} Returns the result object from Route.match() 166 171 */ 167 function recognizePath(path, options, controller) { 168 options.path = path; 169 return recognizeRequest(options, controller) 172 function recognizePath(routeSet, path, params) { 173 var routes = routeSet.routes; 174 // detect HTTP method 175 var methodMatch = path.match(/([A-Z]+) /); 176 var method; 177 if (methodMatch) { 178 method = methodMatch[1]; 179 path = path.substr(methodMatch[0].length); 180 } else { 181 method = "GET"; 182 } 183 var req = Object.extend({ 184 method : method, 185 path : path 186 }, params || {}); 187 return recognizeRequest(routeSet, req) 170 188 } 171 189 … … 173 191 /** 174 192 * Generates a URL for a route. 193 * 194 * @param {Object} [RouteSet] RoutSet, to be checked for matching routes. 195 * @param {Object} options Request params 196 * @param {String} [options.method] HTTP method (uppercase), defaults to "GET" 197 * @param {Request} req Request object 198 * @return {String} Returns the resulting path (URL) 199 * @return {null} Returns null if no path could be generated. 175 200 */ 176 function generate(options, req, controller) { 177 // return (options+req+controller) 201 function generate(routeSet, options, req) { 178 202 var result; 179 var controller = controller || RootController; 180 var req = req || global.req; 181 var routes = controller.routes.getAll(); 203 var routes = routeSet.routes; 182 204 for (var i=0; i<routes.length; i++) { 183 var result = routes[i].getPath( controller,options, req);205 var result = routes[i].getPath(options, req); 184 206 if (result) return result; 185 207 } … … 189 211 190 212 /** 191 * Route constructor for new routes. 192 * You don't need to create your own Route objects. Just use .connect and .draw to add new routes. 213 * Set constructor for holding a set of routes for a controller. 214 * You don't need to create your the Route objects on your own. 215 * Just use .connect, .add and .draw to add new routes. 193 216 * 194 * @param { object} controller Controller object217 * @param {Object} controllerName Short name ("article" for "ArticleController") of the controller. 195 218 */ 196 var Route s = function(controller) {197 this.__proto__ = controller;198 219 var RouteSet = function(controllerName) { 220 if (controllerName == null) controllerName = "root"; 221 199 222 var routes = []; 200 201 /** 202 * Add a new route, or an array of new routes, specified in options. 203 * @param {object} options Options 204 * @param {array} options Array of options 223 224 /** 225 * Add route(s) by passing a route defintion object, or an array of route 226 * definition objects. 227 * @param {Object} routeDefinitions routeDefinitions 228 * @param {Array} options Array of options 229 * @see Route 205 230 * @return Array of all routes 206 231 */ 207 this.add = function(options) { 208 (options instanceof Array) ? this.draw(options) : this.connect(options); 209 return routes; 210 } 211 212 /** 213 * Add an array of routes specified in options. 214 * @param {array} options Array of options 215 * @return {array} Array of all routes 232 this.add = function(routeDefinitions) { 233 if (!routeDefinitions instanceof Array) routeDefinitions = [routeDefinitions]; 234 for (var i=0; i<routeDefinitions.length; i++) { 235 var rd = routeDefinitions[i]; 236 (typeof rd === "string") ? 237 this.connect(rd) : 238 this.connect(rd.pattern, rd); 239 } 240 return this; 241 } 242 243 /** 244 * Rails like syntax for adding new routes, by providing a mapper. 245 * @param {Function} mapper Function, within you can access this RouteSet via "this". 246 * @return {RouteSet} Array of all routes 216 247 */ 217 this.draw = function(options) { 218 // add new routes 219 for (var i=0; i<options.length; i++) { 220 this.connect(options[i]); 221 } 222 return routes; 248 this.draw = function(mapper) { 249 mapper.apply(this); 250 return this; 223 251 } 224 252 225 253 /** 226 * Add a new route specified in options. 227 * @param {object} options Options 228 * @return {object} Route 254 * Add a new route specified in pattern and options. 255 * @param {Object} options Options for the new route. 256 * @see Route 257 * @return {Route} Returns the new Route, that was just added to this RouteSet. 229 258 */ 230 this.connect = function( options) {259 this.connect = function(pattern, options) { 231 260 return routes.push( 232 new Route( 261 new Route( controllerName, 233 262 Object.extend({ 234 controller : controller235 }, options )263 pattern : pattern 264 }, options || {}) 236 265 ) 237 266 ); 267 return this; 238 268 } 239 269 … … 241 271 * Call routing.recognizeRequest for this controller. 242 272 * 243 * @param { object} req Request object244 * @return { object} Returns the result object from Route.match()273 * @param {Object} req Request object 274 * @return {Object} Returns the result object from Route.match() 245 275 */ 246 276 this.recognizeRequest = function(req) { 247 return recognizeRequest( req, controller);277 return recognizeRequest(this, req); 248 278 }, 249 279 … … 251 281 * Call routing.recognizePath for this controller. 252 282 * 253 * @param { string} path Request path254 * @param { object} options Request ooptions255 * @config { string} method HTTP method256 * @return { object} Returns the result object from Route.match()283 * @param {String} path Request path 284 * @param {Object} options Request ooptions 285 * @config {String} method HTTP method 286 * @return {Object} Returns the result object from Route.match() 257 287 */ 258 288 this.recognizePath = function(path, options) { 259 return recognizePath( path, options, controller);289 return recognizePath(this, path, options); 260 290 }, 261 291 262 292 /** @ignore */ 263 293 this.generate = function(options, req) { 264 return generate( options, req || global.req, controller);294 return generate(this, options, req); 265 295 }, 266 296 267 297 /** 268 * Returns all routes.269 * @return {array} Routes270 */271 this.getAll = function() {272 return routes;273 }274 275 /**276 298 * Return a single route at index. 277 * @param { number} index Index starting at 0 (zero)278 * @return { object} Route299 * @param {Number} index Index starting at 0 (zero) 300 * @return {Route} A single Route object. 279 301 */ 280 302 this.get = function(index) { … … 288 310 routes = []; 289 311 } 290 291 /** @ignore */ 312 313 this.toString = function() { 314 return routes.invoke('toString').join("\n"); 315 } 316 317 /** 318 * Returns all routes. 319 * @return {Array} Array of Route objects 320 */ 321 this.__defineGetter__("routes", function() { 322 return routes; 323 }) 324 325 /** 326 * Returns the short name of the controller. 327 * @return {String} 328 */ 292 329 this.__defineGetter__("controller", function() { 293 return controller ;330 return controllerName; 294 331 }) 332 333 /** 334 * Holds the number of routes. To be compatible with Arrays. 335 * @return {Number} 336 */ 337 this.__defineGetter__("length", function() { 338 return routes.length; 339 }) 295 340 296 341 } 342 343 /** 344 * Global RouteSet to be used for root. // ?? 345 * ?? That's the rails way, but i'm not sure if we should keep that, 346 * because routes are mounted at controllers. 347 */ 348 Routes = new RouteSet(); 297 349 298 350 … … 302 354 * options go to the file overview. 303 355 * 304 * @param { object} options305 * @config { string} pattern356 * @param {Object} options 357 * @config {String} pattern 306 358 * Pattern to match against the incoming request, starting with a leading slash. 307 359 * A variable is identified by a laeding $ (dollar-sign) for example '/$controller/$action'. 308 * @config { string} [action] Name of the action. Will be used as default if the pattern doesn't contain an '$action'309 * @config { string} [controller] Controller object name as string, for example "BlogController".310 * @config { object} [controller] Controller object, for example BlogController.311 * @config { string} [forwardTo]360 * @config {String} [action] Name of the action. Will be used as default if the pattern doesn't contain an '$action' 361 * @config {String} [controller] Controller object name as string, for example "BlogController". 362 * @config {Object} [controller] Controller object, for example BlogController. 363 * @config {String} [forwardTo] 312 364 * Controller object name as string to which the route should forward, if the incoming request path 313 365 * does match the pattern, but is longer than the pattern. 314 * @config { object} [forwardTo] Controller as obect to be used for forwardTo.315 * @config { object} [defaults]366 * @config {Object} [forwardTo] Controller as obect to be used for forwardTo. 367 * @config {Object} [defaults] 316 368 * Object containing default values to be used, if the incoming request path doesn't provide the 317 369 * information becuase it's to short. 318 * @config { object} [requirements]370 * @config {Object} [requirements] 319 371 * Contains regular expressions, that will be tested against the resulting routes named values. 320 372 * For example requirements.id will be tested against route.param.id when performing Route.match(). 321 * @config { object} [conditions]373 * @config {Object} [conditions] 322 374 * Each condition will be called on Named object of functions that will be called to perform extra tests. The following attributes will be 323 375 * passed to the function call: … … 330 382 * @see draw 331 383 */ 332 var Route = function( options) {384 var Route = function(controllerName, options) { 333 385 334 386 var VARIABLE_IDENTIFIER = "$"; … … 338 390 var route = this; 339 391 392 this.controllerName = controllerName || "root"; 340 393 this.options = options; 394 this.originalOptions = Object.clone(options); 395 delete this.originalOptions.pattern; 341 396 this.pattern = options.pattern; 342 397 this.action = options.action; 343 this.controller = options.controller;344 398 345 399 // detect HTTP method … … 365 419 this.options = options || {}; 366 420 this.defaults = Object.extend({ 367 controller : options.controller || "root",368 421 action : options.action || "index", 369 422 id : null … … 393 446 return route.components[idx].substr(VARIABLE_IDENTIFIER.length); 394 447 }; 395 396 var getNameForController = function(controller) {397 return (typeof controller === "string") ? controller : controller.getShortName();398 }399 400 var getControllerFromName = function(name) {401 var controller = name;402 if (typeof controller === "string") controller = controller.endsWith("Controller") ? global[controller] : global[controller.capitalize().dasherize().camelize() + "Controller"];403 if (typeof controller === "object" && controller.instance) controller = controller.instance();404 return controller;405 }406 407 448 408 449 /** … … 434 475 * <dt><i>string</i> controller</dt> 435 476 * <dd>The matching part from the path for $controller. Otherwise it will default to 'root'</dd> 436 * @param { string} [req] Request object, or something that is similar to a request object.437 * @config { object} data Hash containing request parameters with their values.438 * @config { string} method HTTP-Method in uppercase letters. May also be ANY.439 * @param { string} path Relative path of the incoming request, starting with a leading slash (/path/to/something).440 * @return { object}477 * @param {String} [req] Request object, or something that is similar to a request object. 478 * @config {Object} data Hash containing request parameters with their values. 479 * @config {String} method HTTP-Method in uppercase letters. May also be ANY. 480 * @param {String} path Relative path of the incoming request, starting with a leading slash (/path/to/something). 481 * @return {Object} 441 482 * The result object is a clone of this route augmented by the following properties: 442 483 * params, method, doForward, extension, format, path, request, action, controller. … … 511 552 result.request = req; 512 553 result.action = result.params["action"] || "index"; 513 result.controller = getControllerFromName(result.params["controller"] || "root");554 result.controllerName = result.params["controller"] || this.controllerName; 514 555 result.route = this; 515 556 for (var name in result.params) { … … 520 561 req.remainingPath = result.remainingPath; 521 562 result.toString = function() { 522 var r = "{"; 523 for (var i in this) { 524 r += i + ":"; 525 switch (typeof this[i]) { 526 case "undefined": 527 r += "undefined"; 528 break; 529 case "function": 530 r += "function"; 531 break; 532 default: 533 r += this[i].toString() 534 } 535 r += "," 536 } 537 return r.substr(0, r.length-1) + "}"; 563 return uneval(this.params); 538 564 } 539 565 … … 541 567 * Result object from the method Route.match() 542 568 * @see Route.match 543 * @param { object} params Object filled with values for each variable for this route pattern. For example an incoming request with the path "/say/hello" matching against a route with the pattern "/$controller/$action/$id" will result in a params object -> {controller:"say", action: "hello", id: null}569 * @param {Object} params Object filled with values for each variable for this route pattern. For example an incoming request with the path "/say/hello" matching against a route with the pattern "/$controller/$action/$id" will result in a params object -> {controller:"say", action: "hello", id: null} 544 570 * @param {string) method HTTP-Method in uppercase letters. May also be ANY. 545 571 */ … … 547 573 }; 548 574 549 this.getPath = function(controller, options, req) { 575 this.getPath = function(options, req) { 576 logger.debug("this.getPath("+uneval(options)+","+uneval(req)+") for " + this.toString()) 550 577 var result = ""; 551 var req = req || global.req; 552 var controller = getControllerFromName(options.controller || req.data.controller || controller); 553 options = options || {}; 554 delete options.controller; 555 578 var req = Object.extend({ 579 method : "GET", 580 path : "/", 581 data : {}