r9679 - in helma-ng/trunk: apps/demo apps/demo/skins apps/filestore apps/filestore/skins apps/googlestore apps/googlestore/skins modules/helma

[email protected] Mon, 27 Apr 2009 16:46:18 +0200 (CEST)
Newsgroups gmane.comp.java.helma.cvs
Message-ID <20090427144618.116653D0D6@mia>
Author: hannes
Date: 2009-04-27 16:46:17 +0200 (Mon, 27 Apr 2009)
New Revision: 9679

Modified:
   helma-ng/trunk/apps/demo/config.js
   helma-ng/trunk/apps/demo/skins/base.html
   helma-ng/trunk/apps/filestore/config.js
   helma-ng/trunk/apps/filestore/main.js
   helma-ng/trunk/apps/filestore/skins/base.html
   helma-ng/trunk/apps/filestore/skins/index.html
   helma-ng/trunk/apps/googlestore/config.js
   helma-ng/trunk/apps/googlestore/main.js
   helma-ng/trunk/apps/googlestore/skins/base.html
   helma-ng/trunk/apps/googlestore/skins/index.html
   helma-ng/trunk/modules/helma/webapp.js
Log:
Make webapps nestable by pointing to a nested config file in the urls map. Make storage apps nestable in demo apps, plus a lot of cosmetic fixes: update to new skin features, use strings instead of regexps as url mapping keys, and more.

Details at http://dev.helma.org/trac/helma/changeset/9679

Modified: helma-ng/trunk/apps/demo/config.js
===================================================================
--- helma-ng/trunk/apps/demo/config.js	2009-04-27 14:46:15 UTC (rev 9678)
+++ helma-ng/trunk/apps/demo/config.js	2009-04-27 14:46:17 UTC (rev 9679)
@@ -3,15 +3,15 @@
 };
 
 exports.urls = [
-    [ /^mount\/point/, 'webmodule' ],
-    [ /^/, 'actions' ],
+    [ '/mount/point', 'webmodule' ],
+    [ '/storage', 'storage/config' ],
+    [ '/', 'actions' ],
 ];
 
 exports.middleware = [
     'helma/webapp/continuation',
-    // 'helma/profiler',
     'helma/logging',
 ];
 
-exports.charset = 'utf8';
+exports.charset = 'UTF-8';
 exports.contentType = 'text/html';

Modified: helma-ng/trunk/apps/demo/skins/base.html
===================================================================
--- helma-ng/trunk/apps/demo/skins/base.html	2009-04-27 14:46:15 UTC (rev 9678)
+++ helma-ng/trunk/apps/demo/skins/base.html	2009-04-27 14:46:17 UTC (rev 9679)
@@ -26,6 +26,7 @@
             <li><a href="/continuation">continuations</a></li>
             <li><a href="/logging">logging</a></li>
             <li><a href="/profiler">profiler</a></li>
+            <!-- <li><a href="/storage">storage</a></li> -->
         </ul>
     </div>
     <div id="footer"><% footer %></div>

Modified: helma-ng/trunk/apps/filestore/config.js
===================================================================
--- helma-ng/trunk/apps/filestore/config.js	2009-04-27 14:46:15 UTC (rev 9678)
+++ helma-ng/trunk/apps/filestore/config.js	2009-04-27 14:46:17 UTC (rev 9679)
@@ -1,10 +1,10 @@
 exports.urls = [
-    [ /^$/, 'main' ]
+    [ '/', 'main' ]
 ];
 
 exports.middleware = [
     'helma/logging'
 ]
 
-exports.charset = 'utf8';
-exports.contentType = 'text/html';
\ No newline at end of file
+exports.charset = 'UTF-8';
+exports.contentType = 'text/html';

Modified: helma-ng/trunk/apps/filestore/main.js
===================================================================
--- helma-ng/trunk/apps/filestore/main.js	2009-04-27 14:46:15 UTC (rev 9678)
+++ helma-ng/trunk/apps/filestore/main.js	2009-04-27 14:46:17 UTC (rev 9679)
@@ -1,5 +1,5 @@
 include('helma/webapp/response');
-include('model');
+include('./model');
 
 export('index');
 
@@ -12,14 +12,10 @@
     if (req.params.remove) {
         return removeBook(req);
     }
-    return SkinnedResponse('skins/index.html', {
-        title: 'Storage Demo',
-        books: function(/*tag, skin, context*/) {
-            var books = Book.all();
-            return books.map(function(book) {
-                return book.getFullTitle() + ' ' + getDeleteLink(book);
-            }).join('<br>\r\n');
-        }
+    return SkinnedResponse(getResource('./skins/index.html'), {
+        title: 'Storage',
+        books: Book.all(),
+        action: req.path
     });
 }
 
@@ -28,20 +24,16 @@
     var book = new Book({author: author, title: req.params.title});
     // author is saved transitively
     book.save();
-    return new RedirectResponse('/');
+    return new RedirectResponse(req.path);
 }
 
 function removeBook(req) {
     var book = Book.get(req.params.remove);
     // author is removed through cascading delete
     book.remove();
-    return new RedirectResponse('/');
+    return new RedirectResponse(req.path);
 }
 
-function getDeleteLink(book) {
-    return '<a href="/?remove=' + book._id + '">delete</a>';
-}
-
 if (__name__ == "__main__") {
     require('helma/webapp').start();
 }

Modified: helma-ng/trunk/apps/filestore/skins/base.html
===================================================================
--- helma-ng/trunk/apps/filestore/skins/base.html	2009-04-27 14:46:15 UTC (rev 9678)
+++ helma-ng/trunk/apps/filestore/skins/base.html	2009-04-27 14:46:17 UTC (rev 9679)
@@ -4,6 +4,7 @@
 <title>Helma NG Storage API</title>
 </head>
 <body>
+<h1><% title %></h1>
 <% render 'content' %>
 </body>
 </html>

Modified: helma-ng/trunk/apps/filestore/skins/index.html
===================================================================
--- helma-ng/trunk/apps/filestore/skins/index.html	2009-04-27 14:46:15 UTC (rev 9678)
+++ helma-ng/trunk/apps/filestore/skins/index.html	2009-04-27 14:46:17 UTC (rev 9679)
@@ -1,17 +1,20 @@
-<% extends 'base.html' %>
+<% extends 'skins/base.html' %>
 
-<% subskin 'content' %>
-<h1><% title %></h1>
+<% subskin 'content' ----------------------------------- %>
 <% message | prefix "<p>" | suffix "</p>" %>
 
 <h3>Add a new book</h3>
-<form action="/" method="post">
-    <label>Author: </label><input name="author" size="30"/>
-    <label>Title: </label><input name="title" size="30"/>
-    <input type="submit" name="save" value="Save"/>
+<form action="<% action %>" method="post">
+    <div><label>Author: </label></div><div><input name="author" size="30"/></div>
+    <div><label>Title: </label></div><div><input name="title" size="30"/></div>
+    <p><input type="submit" name="save" value="Save"/></p>
 </form>
 
 <h3>Available Books</h3>
 <p>
-<% books %>
+<% for book in <% books %> render book %>
 </p>
+
+<% subskin 'book'  ----------------------------------- %>
+<div><% book.author.name %>: <% book.title %>
+    <a href="?remove=<% book._id %>">[remove]</a></div>

Modified: helma-ng/trunk/apps/googlestore/config.js
===================================================================
--- helma-ng/trunk/apps/googlestore/config.js	2009-04-27 14:46:15 UTC (rev 9678)
+++ helma-ng/trunk/apps/googlestore/config.js	2009-04-27 14:46:17 UTC (rev 9679)
@@ -1,10 +1,10 @@
 exports.urls = [
-    [ /^$/, 'main' ]
+    [ '/', 'main' ]
 ];
 
 exports.middleware = [
     'helma/logging'
 ]
 
-exports.charset = 'utf8';
-exports.contentType = 'text/html';
\ No newline at end of file
+exports.charset = 'UTF-8';
+exports.contentType = 'text/html';

Modified: helma-ng/trunk/apps/googlestore/main.js
===================================================================
--- helma-ng/trunk/apps/googlestore/main.js	2009-04-27 14:46:15 UTC (rev 9678)
+++ helma-ng/trunk/apps/googlestore/main.js	2009-04-27 14:46:17 UTC (rev 9679)
@@ -1,5 +1,5 @@
 include('helma/webapp/response');
-include('model');
+include('./model');
 
 export('index');
 
@@ -12,13 +12,10 @@
     if (req.params.remove) {
         return removeBook(req);
     }
-    return new SkinnedResponse('skins/index.html', {
-        title: 'Storage Demo',
-        books: function(/*tag, skin, context*/) {
-            return Book.all().map(function(book) {
-                return book.getFullTitle() + ' ' + getDeleteLink(book);
-            }).join('<br>\r\n');
-        }
+    return SkinnedResponse(getResource('./skins/index.html'), {
+        title: 'Storage',
+        books: Book.all(),
+        action: req.path
     });
 }
 
@@ -27,7 +24,7 @@
     author.save(); // no cascading save yet
     var book = new Book({author: author, title: req.params.title});
     book.save();
-    return new RedirectResponse('/');
+    return new RedirectResponse(req.path);
 }
 
 function removeBook(req) {
@@ -35,9 +32,5 @@
     // no cascading delete
     book.author.remove();
     book.remove();
-    return new RedirectResponse('/');
+    return new RedirectResponse(req.path);
 }
-
-function getDeleteLink(book) {
-    return '<a href="/?remove=' + book.getId() + '">delete</a>';
-}

Modified: helma-ng/trunk/apps/googlestore/skins/base.html
===================================================================
--- helma-ng/trunk/apps/googlestore/skins/base.html	2009-04-27 14:46:15 UTC (rev 9678)
+++ helma-ng/trunk/apps/googlestore/skins/base.html	2009-04-27 14:46:17 UTC (rev 9679)
@@ -4,6 +4,7 @@
 <title>Helma NG Storage API</title>
 </head>
 <body>
+<h1><% title %></h1>
 <% render 'content' %>
 </body>
 </html>

Modified: helma-ng/trunk/apps/googlestore/skins/index.html
===================================================================
--- helma-ng/trunk/apps/googlestore/skins/index.html	2009-04-27 14:46:15 UTC (rev 9678)
+++ helma-ng/trunk/apps/googlestore/skins/index.html	2009-04-27 14:46:17 UTC (rev 9679)
@@ -1,17 +1,20 @@
-<% extends 'base.html' %>
+<% extends 'skins/base.html' %>
 
-<% subskin 'content' %>
-<h1><% title %></h1>
+<% subskin 'content' ----------------------------------- %>
 <% message | prefix "<p>" | suffix "</p>" %>
 
 <h3>Add a new book</h3>
-<form action="/" method="post">
-    <label>Author: </label><input name="author" size="30"/>
-    <label>Title: </label><input name="title" size="30"/>
-    <input type="submit" name="save" value="Save"/>
+<form action="<% action %>" method="post">
+    <div><label>Author: </label></div><div><input name="author" size="30"/></div>
+    <div><label>Title: </label></div><div><input name="title" size="30"/></div>
+    <p><input type="submit" name="save" value="Save"/></p>
 </form>
 
 <h3>Available Books</h3>
 <p>
-<% books %>
+<% for book in <% books %> render book %>
 </p>
+
+<% subskin 'book'  ----------------------------------- %>
+<div><% book.author.name %>: <% book.title %>
+    <a href="?remove=<% book.getId %>">[remove]</a></div>

Modified: helma-ng/trunk/modules/helma/webapp.js
===================================================================
--- helma-ng/trunk/modules/helma/webapp.js	2009-04-27 14:46:15 UTC (rev 9678)
+++ helma-ng/trunk/modules/helma/webapp.js	2009-04-27 14:46:17 UTC (rev 9679)
@@ -46,6 +46,8 @@
     function getPattern(spec) {
         var pattern = spec[0];
         if (typeof pattern == "string") {
+            if (pattern.startsWith("/"))
+                pattern = pattern.replace("/", "^");
             pattern = spec[0] = new RegExp(pattern);
         } else if (!(pattern instanceof RegExp)) {
             throw Error("Pattern must be a regular expression or string");
@@ -53,10 +55,10 @@
         return pattern;
     }
 
-    function getModule(spec) {
+    function getModule(spec, prefix) {
         var module = spec[1];
         if (typeof module == "string") {
-            module = require(module);
+            module = require(prefix + module);
         } else if (!(module instanceof Object)) {
             throw Error("Module must be a string or object");
         }
@@ -72,29 +74,28 @@
         return null;
     }
 
-    
-
-    try {
-        log.debug('resolving path ' + path);
+    function resolveInConfig(config, path, prefix) {
+        if (log.isDebugEnabled) log.debug('resolving path ' + path);
         if (config.urls instanceof Array) {
             var urls = config.urls;
             for (var i = 0; i < urls.length; i++) {
-                log.debug("checking url line: " + urls[i]);
+                if (log.isDebugEnabled) log.debug("checking url line: " + urls[i]);
                 var match = getPattern(urls[i]).exec(path);
-                log.debug("got match: " + match);
+                if (log.isDebugEnabled) log.debug("got match: " + match);
                 if (match != null) {
-                    var module = getModule(urls[i]);
-                    log.debug("module: " + module);
+                    var module = getModule(urls[i], prefix);
+                    if (log.isDebugEnabled) log.debug("module: " + module);
                     // cut matching prefix from path
                     path = path.substring(match[0].length);
                     // remove leading and trailing slashes
                     path = path.replace(/^\/+|\/+$/g, "");
                     //split
-                    path = path.split(/\/+/);
-                    var action = getAction(module, path[0]);
-                    if (typeof action == "function" && path.length <= action.length) {
+                    var pathArray = path.split(/\/+/);
+                    var action = getAction(module, pathArray[0]);
+                    // log.debug("got action: " + action);
+                    if (typeof action == "function" && pathArray.length <= action.length) {
                         // add remaining path elements as additional action arguments
-                        var actionArgs = path.slice(1).map(decodeURIComponent);
+                        var actionArgs = pathArray.slice(1).map(decodeURIComponent);
                         var matchedArgs = match.slice(1).map(decodeURIComponent);
                         var args = [req].concat(matchedArgs).concat(actionArgs);
                         var middleware = config.middleware;
@@ -107,12 +108,20 @@
                                 return action.apply(module, args);
                             }
                         }
-                        res = req.process();
+                        return req.process();
+                    } else if (module.urls instanceof Array) {
+                        // nested app
+                        return resolveInConfig(module, path, match[0] + "/");
+                    } else {
+                        break;
                     }
-                    break;
                 }
             }
         }
+    }
+
+    try {
+        res = resolveInConfig(config, path, "");
     } catch (e) {
         if (e.retry) {
             throw e;