Index: Dev/trunk/deploy.sh
===================================================================
--- Dev/trunk/deploy.sh	(revision 471)
+++ Dev/trunk/deploy.sh	(revision 472)
@@ -4,6 +4,6 @@
 DEPLOYDIR=quod-erat.git
 
-if [ -z $1 ]; then
-    echo "Suage: $o <commit message>"
+if [ -z "$1" ]; then
+    echo "Usage: $o <commit message>"
     exit 1
 fi
@@ -13,3 +13,3 @@
 fi
 
-(cd "$DEPLOYDIR" && rm -rf * && cp -r ../build/* . && git add . && git commit -a "$1")
+(cd "$DEPLOYDIR" && git pull && rm -rf * && cp -r ../build/* . && git add . && git commit -a -m "$1" && git push)
Index: Dev/trunk/docs/TODO.md
===================================================================
--- Dev/trunk/docs/TODO.md	(revision 471)
+++ Dev/trunk/docs/TODO.md	(revision 472)
@@ -2,84 +2,63 @@
 ====
 
- * Drop separate development directory for more complicated build process.
-   - Generate files in-place (maybe even include in commit, although I hate that.)
-     Automatically update gitignore for generated files?
-   - Add header to files to make sure they are not edited as source files by accident.
-   - A smarter copy might also fix this, maybe we should implement our own copy.
-   - Can we do amd dependency checks?
-   - We should also lint the generated javascript, because coffee
-     doesn't catch accidental globals
- * Have a generic page-wide note (rounded corner, close button thingy)
-   for notification (maybe completely replace the toaster?)
- * Response:
-   - should we show response answers after submission?
-   - idem after the run ended?
- * Questions
+ * App / General
+   - Introduce a page-wide note (rounded corner box at the top e.g.)
+     for notifications that the user has to confirm.
+   - Prevent pages from moving away if they contain unsaved edits.
+   - Make sure no user generated content is directly inserted in the
+     DOM tree (i.e. innerHTML or .content assignments)
+
+ * Response
+   - response url stops working after response is submitted or surveyRun is closed
+   - Check if this works on tablets as well.
+   - Should we provide degraded options for filling in surveys for
+     browsers that do not support JS? This would involve server-side
+     rendering, old-school form submission and server-side validation.
+
+ * Question
    - Question is always shown as 'no topic' when no category is added to it.
-   - Fragile: widget creation relies on the names in Factory, but
-     these must match the types returned by the actual widgets. Fix
-     this.
-   - Would be nicer if only newly dropped questions are in edit mode
-     and the ones that exist on load in view mode.
- * Codes
-   - Details need to be figured out. Now we have a code in one place,
-     we add indices to disambiguate. Should we allow code editing all
-     the way to the lowest detail? And should it be the complete code or
-     just additions?
-   - Check that question codes are unique in the database.
-   - It might be good to show the codes in GUI, so they know at least
-     which element will be called what
- * Validation
-   - restore our json schema, there's probably several problems, it
-     was disabled because the questions didn't pass anymore.
-   - use it server side (and maybe client side as well?)
- * Editing
-   - Warn if leaving a page that has edits.
- * Validate documents on the server before saving them.
- * Implement authentication and later authorization.
-   - Can we hook in request API so stores work correctly?
- * Export answers for a survey run
-   - Allow to include partial results, or just include submission date.
-   - Include an URL to the dataset/run so it can easily be traced back.
-   - Flatten object structure
- * Check if it works on tablets. We could consider special tablet UI
-   later.
+   - QuestionWidgetFactory relies on the names in the factory, but
+     also on the name set in the widget. This is redundant and can
+     cause inconsistencies. Remove the names from the widgets, only
+     relying on the factory for the mapping.
+   - Question codes are not checked for uniqueness.
+   - Are question codes defined on the right level? Maybe they want
+     control on a per-input basis. We can also provide an alias system
+     for older data.
+   - Users cannot see the code of a question easily. In survey view
+     the code should be shown as well as the title.
+   - When editing a question, the user should see the final codes the
+     different inputs get, so they can match them more easily to their
+     data.
+   - Cannot easily find a question based on a code. This is important
+     if a researcher wants to see the question related to one of his
+     datasets in SPSS.
+
+ * Store
+   - Data is not validated before being stored in the database, nor
+     when it's used afterwards.
+   - Data format should be designedso the database is mostly
+     additive. It should also allow for adding metadata later
+     (e.g. annotating questions with statistical information about the
+     outcome).
+
+ * SurveyRun
+   - Cannot export responses as CSV
+   - Current response modes are unclear.
+
  * Sessions
-   - modes: fixed, bulk, registration
-   - off-line session:
-     * provide a portal page where people can select available survey,
-       maybe later see progress.
-     * Allow for a registration round at the beginning (email, nick).
-     * Show name clearly in portal, to prevent mistakes with the
-       tablets.
-     * Allow sessions based on subnet or a session code (A23X5Y).
-     * Easy grouping of participants or selecting a subset for a
-       survey.
-     * On the server (localhost) show the ip(s) that people should
-       connect to.
+   - Allow ease of use for real-life sessions
+     * allow registration by participants or pre-registration by GOD
+     * provide a portal with simple access code so people don't have
+       to type complicated URL's.
+     * Make it easy to bookmark a session as a home icon on iP* or
+       Android.
+     * Clearly show a participant name/email in the screen to prevent
+       errors because of mixing hardware. Maybe force confirmation
+       after period of inactivity?
+     * It should be easy for a host to start a survey or game to all
+       or a subset of the participants. The UI could lead the
+       participants in what they have to do next.
 
-Checklist
-=========
-
- * Form validation (use tooltips!)
- * Input validation & escaping
-   - E.g. texts and labels of ScaleWidget are directly put in innerHTML, I don't think TextBox does any escaping.
- * Output escaping
- * Widget life-cycle
-   buildRendering -> widgets in code before set attributes
-   postCreate -> after all inits, but before in DOM
-   startup -> after insertion in DOM?
- * Review current JSON formats, do they allow for extension or extra meta-data?
- 
-Open issues
-===========
-
- * Do different inputs in one question get different codes? E.g. in 
-   To ease exporting into other programs and easy communication, the codes
-   are important I think. It should be easy to pronounce, and easy to
-   find in the tool (people might get a dataset and not know where it
-   came from).
- * What if a question is included in a survey multiple times. Use block
-   or allow a pre/post-fix on the code to differentiate it.
-   Should not be too much work, so if an scale with 5 items has 5 codes,
-   you should be able to set a prefix on all of them at once.
+ * Rethink build process
+   - AMD dependency analysis/checking would be nice
Index: Dev/trunk/src/client/qed-client/css/qed.css
===================================================================
--- Dev/trunk/src/client/qed-client/css/qed.css	(revision 471)
+++ Dev/trunk/src/client/qed-client/css/qed.css	(revision 472)
@@ -1,2 +1,3 @@
+/* This CSS file is generated. All edits will be lost on recompile. */
 @import "dijit/claro.css";
 /* line 1, /home/hendrik/gamelab/qed.svn/Dev/trunk/src/client/qed-client/css/colors.less */
Index: Dev/trunk/src/client/qed-client/index.js
===================================================================
--- Dev/trunk/src/client/qed-client/index.js	(revision 471)
+++ Dev/trunk/src/client/qed-client/index.js	(revision 472)
@@ -1,11 +1,6 @@
 define([
-    "./app/Content",
-    "./app/Page",
     "./app/Router",
     "./routes",
     "./session",
-    "./store",
-    "./store/request",
-    "./ui/LoginDialogWrapper",
     "./ui/MainMenu",
     "dojo/_base/array",
@@ -13,6 +8,5 @@
     "./stddeps",
     "dojo/domReady!"
-], function(Content, Page, Router, routes, session, store,
-            request, LoginDialogWrapper, MainMenu, array, parser) {
+], function(Router, routes, session, MainMenu, array, parser) {
 
     parser.parse();
Index: Dev/trunk/src/client/qed-client/store/CouchStore.js
===================================================================
--- Dev/trunk/src/client/qed-client/store/CouchStore.js	(revision 471)
+++ Dev/trunk/src/client/qed-client/store/CouchStore.js	(revision 472)
@@ -241,5 +241,7 @@
 
             for ( var opt in queryOpts ) {
-                queryOpts[opt] = json.toJson(queryOpts[opt]);
+                if ( queryOpts.hasOwnProperty(opt) ) {
+                    queryOpts[opt] = json.toJson(queryOpts[opt]);
+                }
             }
             
Index: Dev/trunk/src/client/qed-client/widgets/LineWithActionsWidget.js
===================================================================
--- Dev/trunk/src/client/qed-client/widgets/LineWithActionsWidget.js	(revision 471)
+++ Dev/trunk/src/client/qed-client/widgets/LineWithActionsWidget.js	(revision 472)
@@ -34,32 +34,34 @@
             }
             for (var action in this.actions) {
-                var properties;
-                if (this.actions[action].properties.blockButton === true) {
-                    properties = lang.mixin({
-                        baseClass: 'rftBlockButton',
-                        label: "Default",
-                        iconClass: 'rftIcon rftIcon'+this.actions[action].properties.icon,
-                        title: this.actions[action].properties.tooltip,
-                        onClick: lang.hitch(this, function(action, e){
-                            if ( action.callback ) { action.callback(e); }
-                            event.stop(e);
-                            return false;
-                        }, this.actions[action])
-                    }, this.actions[action].properties);
-                    new Button(properties).placeAt(this.buttonsNode);
-                } else {
-                    properties = lang.mixin({
-                        baseClass: 'rftInlineButton',
-                        label: "Default",
-                        showLabel: false,
-                        iconClass: 'rftIcon rftIcon'+this.actions[action].properties.icon,
-                        title: this.actions[action].properties.tooltip,
-                        onClick: lang.hitch(this, function(action, e){
-                            if ( action.callback ) { action.callback(e); }
-                            event.stop(e);
-                            return false;
-                        }, this.actions[action])
-                    }, this.actions[action].properties);
-                    new Button(properties).placeAt(this.buttonsNode);
+                if ( this.actions.hasOwnProperty(action) ) {
+                    var properties;
+                    if (this.actions[action].properties.blockButton === true) {
+                        properties = lang.mixin({
+                            baseClass: 'rftBlockButton',
+                            label: "Default",
+                            iconClass: 'rftIcon rftIcon'+this.actions[action].properties.icon,
+                            title: this.actions[action].properties.tooltip,
+                            onClick: lang.hitch(this, function(action, e){
+                                if ( action.callback ) { action.callback(e); }
+                                event.stop(e);
+                                return false;
+                            }, this.actions[action])
+                        }, this.actions[action].properties);
+                        new Button(properties).placeAt(this.buttonsNode);
+                    } else {
+                        properties = lang.mixin({
+                            baseClass: 'rftInlineButton',
+                            label: "Default",
+                            showLabel: false,
+                            iconClass: 'rftIcon rftIcon'+this.actions[action].properties.icon,
+                            title: this.actions[action].properties.tooltip,
+                            onClick: lang.hitch(this, function(action, e){
+                                if ( action.callback ) { action.callback(e); }
+                                event.stop(e);
+                                return false;
+                            }, this.actions[action])
+                        }, this.actions[action].properties);
+                        new Button(properties).placeAt(this.buttonsNode);
+                    }
                 }
             }
Index: Dev/trunk/src/client/qed-client/widgets/ObjectBox.js
===================================================================
--- Dev/trunk/src/client/qed-client/widgets/ObjectBox.js	(revision 471)
+++ Dev/trunk/src/client/qed-client/widgets/ObjectBox.js	(revision 472)
@@ -41,14 +41,16 @@
             var line3Actions = {};
             for (var action in this.actions) {
-                line3Actions[action] = {
-                    callback: lang.hitch(this, function(callback){
-                        if ( this.value ) { callback(this.value); }
-                    }, this.actions[action]),
-                    properties: {
-                        blockButton: true,
-                        label: action,
-                        icon: action.charAt(0).toUpperCase()+action.slice(1)
-                    }
-                };
+                if ( this.actions.hasOwnProperty(action) ) {
+                    line3Actions[action] = {
+                        callback: lang.hitch(this, function(callback){
+                            if ( this.value ) { callback(this.value); }
+                        }, this.actions[action]),
+                        properties: {
+                            blockButton: true,
+                            label: action,
+                            icon: action.charAt(0).toUpperCase()+action.slice(1)
+                        }
+                    };
+                }
             }
             return line3Actions;
Index: Dev/trunk/src/client/qed-client/widgets/Selector.js
===================================================================
--- Dev/trunk/src/client/qed-client/widgets/Selector.js	(revision 471)
+++ Dev/trunk/src/client/qed-client/widgets/Selector.js	(revision 472)
@@ -57,17 +57,19 @@
             if ( this.selectedActions !== null ) {
                 for (var actionName in this.selectedActions) {
-                    action = this.selectedActions[actionName];
-                    actions[actionName] = {
-                        callback: action.callback &&
-                                lang.hitch(this,this._onSelectedAction,
-                                        action.callback),
-                        properties: {
-                            blockButton: true,
-                            label: action.title || actionName,
-                            icon: action.icon,
-                            tooltip: action.description
-                        }
-
-                    };
+                    if ( this.selectedActions.hasOwnProperty(actionName) ) {
+                        action = this.selectedActions[actionName];
+                        actions[actionName] = {
+                            callback: action.callback &&
+                                    lang.hitch(this,this._onSelectedAction,
+                                            action.callback),
+                            properties: {
+                                blockButton: true,
+                                label: action.title || actionName,
+                                icon: action.icon,
+                                tooltip: action.description
+                            }
+
+                        };
+                    }
                 }
             }
@@ -180,14 +182,16 @@
             if (this.itemActions) {
                 for (var actionName in this.itemActions) {
-                    action = this.itemActions[actionName];
-                    actions[actionName] = {
-                        callback: action.callback && lang.partial(action.callback,item),
-                        properties: {
-                            blockButton: false,
-                            showLabel: false,
-                            icon: action.icon + " black",
-                            tooltip: action.description
-                        }
-                    };
+                    if ( this.itemActions.hasOwnProperty(actionName) ) {
+                        action = this.itemActions[actionName];
+                        actions[actionName] = {
+                            callback: action.callback && lang.partial(action.callback,item),
+                            properties: {
+                                blockButton: false,
+                                showLabel: false,
+                                icon: action.icon + " black",
+                                tooltip: action.description
+                            }
+                        };
+                    }
                 }
             }
Index: Dev/trunk/src/client/qed-client/widgets/_ComplexValueMixin.coffee
===================================================================
--- Dev/trunk/src/client/qed-client/widgets/_ComplexValueMixin.coffee	(revision 471)
+++ Dev/trunk/src/client/qed-client/widgets/_ComplexValueMixin.coffee	(revision 472)
@@ -46,4 +46,4 @@
             # widgets within other forms, the onSubmit must either be
             # ignored or propagated, but not handled here.
-            event.stop if e
+            event.stop e if e
             false
