Index: Dev/branches/rest-dojo-ui/client/rft/pages/question.html
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/pages/question.html	(revision 414)
+++ Dev/branches/rest-dojo-ui/client/rft/pages/question.html	(revision 415)
@@ -3,5 +3,5 @@
         <h2>
             <span class="rftIcon rftIconSurvey"></span>
-            <span class="headerText">Question 123 [Editing]</span>
+            <span class="headerText"><span data-dojo-attach-point="titleNode">Question title</span> [Editing]</span>
         </h2>
     </div>
Index: Dev/branches/rest-dojo-ui/client/rft/pages/question.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/pages/question.js	(revision 414)
+++ Dev/branches/rest-dojo-ui/client/rft/pages/question.js	(revision 415)
@@ -21,5 +21,12 @@
             if ( this._started ) { return; }
             this.inherited(arguments);
-            if (this.questionId) {
+            if ( !this.questionId ) {
+                throw new Error("Error: no reference to object set!");
+            }
+            this._setupEditor();
+            if (this.questionId === "new") {
+                this.question = { type: 'Question' };
+                this._refresh();
+            } else {
                 Deferred.when(store.get(this.questionId))
                 .then(lang.hitch(this, function(obj) {
@@ -27,8 +34,5 @@
                     this._refresh();
                 }));
-            } else {
-                throw new Error("Error: no reference to object set!");
             }
-            this._setupEditor();
         },
         onLeave: function() {
@@ -36,4 +40,5 @@
         },
         _refresh: function () {
+            this.titleNode.innerHTML = this.question.title || "";
             this._toolkit.set('value',this.question);
             this._preview.appendItems(this.question.content || []);
@@ -46,5 +51,5 @@
                 Router.go('/questions');
             },function(err){
-                Content.notify(err.reason,'error');
+                Content.notify(err,'error');
             });
             evt && event.stop( evt );
Index: Dev/branches/rest-dojo-ui/client/rft/pages/questions.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/pages/questions.js	(revision 414)
+++ Dev/branches/rest-dojo-ui/client/rft/pages/questions.js	(revision 415)
@@ -40,8 +40,5 @@
         },
         onNewQuestion: function() {
-            Deferred.when(store.add({type:'Question'}))
-            .then(lang.hitch(this,function(question){
-                this.onEditQuestion(question);
-            }));
+            Router.go("/question/new");
         },
         onDeleteQuestion: function(question) {
@@ -50,5 +47,5 @@
                 Content.notify("Question deleted.");
             },function(err){
-                Content.notify(err.reason,'error');
+                Content.notify(err,'error');
             });
         },
@@ -62,5 +59,5 @@
                 Content.notify("Question published.");
             },function(err){
-                Content.notify(err.reason,'error');
+                Content.notify(err,'error');
             });
         }
Index: Dev/branches/rest-dojo-ui/client/rft/pages/survey.html
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/pages/survey.html	(revision 414)
+++ Dev/branches/rest-dojo-ui/client/rft/pages/survey.html	(revision 415)
@@ -40,11 +40,6 @@
          data-dojo-attach-event="onSubmit:_onPropertiesOk">
 
-        <form data-dojo-type="dijit/form/Form"
-              data-dojo-attach-point="propertiesForm">
-            <label for="title">Title</label>
-            <input data-dojo-type="dijit/form/TextBox" name="title"/><br/>
-            <label for="description">Description</label>
-            <input data-dojo-type="dijit/form/Textarea" name="description"/><br/>
-        </form>
+        <div data-dojo-type="rft/ui/model/SurveyForm"
+              data-dojo-attach-point="propertiesForm"></div>
             
         <div>
Index: Dev/branches/rest-dojo-ui/client/rft/pages/surveys.html
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/pages/surveys.html	(revision 414)
+++ Dev/branches/rest-dojo-ui/client/rft/pages/surveys.html	(revision 415)
@@ -36,3 +36,12 @@
     </div>
 
+    <div data-dojo-type="dijit/Dialog"
+         title="SurveyRun properties"
+         data-dojo-attach-point="surveyRunDialog">
+        <form data-dojo-type="rft/ui/model/SurveyRunForm" data-dojo-attach-point="surveyRunForm">
+            <button data-dojo-type="dijit/form/Button">OK</button>
+            <button data-dojo-type="dijit/form/Button">Cancel</button>
+        </form>
+    </div>
+
 </div>
Index: Dev/branches/rest-dojo-ui/client/rft/pages/surveys.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/pages/surveys.js	(revision 414)
+++ Dev/branches/rest-dojo-ui/client/rft/pages/surveys.js	(revision 415)
@@ -23,5 +23,5 @@
                 Router.go('/survey/'+store.getIdentity(survey));
             },function(err){
-                Content.notify(err.reason,'error');
+                Content.notify(err,'error');
             });
         },
@@ -33,5 +33,5 @@
                 self.refreshPublished();
             },function(err){
-                Content.notify(err.reason,'error');
+                Content.notify(err,'error');
             });
         },
@@ -42,5 +42,5 @@
                 self.refreshDrafts();
             },function(err){
-                Content.notify(err.reason,'error');
+                Content.notify(err,'error');
             });
         },
@@ -52,5 +52,5 @@
         },
         _onRunSurvey:function(survey){
-
+            this.surveyRunDialog.show();
         },
         refresh: function() {
Index: Dev/branches/rest-dojo-ui/client/rft/pages/viewSurvey.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/pages/viewSurvey.js	(revision 414)
+++ Dev/branches/rest-dojo-ui/client/rft/pages/viewSurvey.js	(revision 415)
@@ -7,7 +7,7 @@
     '../store',
     '../app/Page',
-    '../ui/content/ContentWidgetFactory',
+    '../ui/model/QuestionWidgetFactory',
     'dojo/text!./viewSurvey.html'
-],function(array,declare,Deferred,event,lang,store,Page,ContentWidgetFactory,template){
+],function(array,declare,Deferred,event,lang,store,Page,QuestionWidgetFactory,template){
     return declare([Page],{
         templateString: template,
@@ -35,5 +35,5 @@
                     this.titleNode.innerHTML = survey.title +
                             (this.options.preview?' [preview]':'');
-                    var f = new ContentWidgetFactory();
+                    var f = new QuestionWidgetFactory();
                     this.survey = survey;
                     store.query(null,{keys:this.survey.questions,include_docs:true})
Index: Dev/branches/rest-dojo-ui/client/rft/schema.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/schema.js	(revision 415)
+++ Dev/branches/rest-dojo-ui/client/rft/schema.js	(revision 415)
@@ -0,0 +1,136 @@
+define(['dojo/_base/lang'],function(lang){
+
+    /** Note on dojox.json.schema
+     * This implementation is not according to the version 03 of the json-schema
+     * draft. Differences:
+     * - doesn't support the 'required' property, but uses 'optional' (which is
+     *   false by default).
+     */
+
+    ////////////////////////////////////////
+    // Base schema types
+    //
+
+    var dateRe = "\\d{4}-\\d{2}-\\d{2}"; // YYYY-MM-DD
+    var timeRe = "\\d{2}:\\d{2}:\\d{2}"; // hh:mm:ss 
+    var datetimeRe = dateRe+"T"+timeRe+"Z"; // YYYY-MM-DDThh:mm:ssZ
+
+    function mixin(obj1,obj2) {
+        return lang.mixin({},obj1||{},obj2||{});
+    }
+    function mkType(base) {
+        return function(props) {
+            return mixin(base,props);
+        };
+    }
+
+    var nestring = mkType({ type:'string', minLength:1 });
+    var string = mkType({ type:'string' });
+    var integer = mkType({ type: 'integer' });
+    var boolean = mkType({ type: 'boolean' });
+    var pattern = function(p){
+        return mixin({
+            type: 'string',
+            pattern: p
+        });
+    };
+    var date = mkType(pattern(dateRe));
+    var time = mkType(pattern(timeRe));
+    var datetime = mkType(pattern(datetimeRe));
+    var array = function(items,props) {
+        return mixin({
+            type: 'array',
+            items: items
+        },props);
+    };
+    var object = function(properties,props) {
+        return mixin({
+            type: 'object',
+            properties: properties,
+            additionalProperties: false
+        },props);
+    };
+    var optional = mkType({ optional: true });
+
+    ////////////////////////////////////////
+    // Domain specific
+    //
+
+    var typedobject = function(type,properties,props) {
+        return object(mixin(properties,{
+            type: pattern(type)
+        }),props);
+    };
+
+    var dbobject = function(type,properties,props) {
+        return typedobject(type,mixin(properties,{
+            _id: nestring(optional()),
+            _rev: nestring(optional())
+        }),props);
+    };
+
+    ////////////////////////////////////////
+    // The QED schema
+    //
+
+    var schema = {type:[
+        dbobject('Question',{
+            code:nestring(),
+            title: nestring(),
+            description: string(optional()),
+            topic: string(optional()),
+            categories: array(nestring(),optional()),
+            content: array([
+                typedobject('Header',{
+                    content:string(optional())
+                }),
+                typedobject('Text',{
+                    content:string(optional())
+                }),
+                typedobject('Divider'),
+                typedobject('StringInput'),
+                typedobject('TextInput',{
+                    maxLength:integer()
+                }),
+                typedobject('IntegerInput',{
+                    min:integer(),
+                    max:integer(),
+                    step:integer()
+                }),
+                typedobject('MultipleChoiceInput',{
+                    multiple:boolean(),
+                    items:array(nestring())
+                })
+            ],optional()),
+            publicationDate:datetime(optional())
+        }),
+        dbobject('Survey',{
+            title: nestring(),
+            description: string(optional()),
+            questions: array(nestring(),optional()),
+            publicationDate:datetime(optional())
+        }),
+        dbobject('SurveyRun',{
+            surveyId: nestring(),
+            publicationDate:datetime(optional()),
+            startDate:datetime(optional()),
+            endDate:datetime(optional()),
+            mode:{type:'string',enum:['open','closed']},
+            respondents: array(nestring(),optional()),
+            metadata:{type:'object'}
+        }),
+        dbobject('Session',{
+            title: nestring(),
+            description: string(optional()),
+            publicationDate: datetime(optional())
+        }),
+        dbobject('SessionTemplate',{
+            title: nestring(),
+            description: string(optional()),
+            publicationDate: datetime(optional()),
+            plannedDate: datetime(optional())
+        })
+    ]};
+
+    return schema;
+});
Index: Dev/branches/rest-dojo-ui/client/rft/stddeps.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/stddeps.js	(revision 414)
+++ Dev/branches/rest-dojo-ui/client/rft/stddeps.js	(revision 415)
@@ -21,4 +21,5 @@
     'dijit/form/Textarea',
     'dijit/form/TextBox',
+    'dijit/form/TimeTextBox',
 
     'dojox/grid/DataGrid',
@@ -33,4 +34,7 @@
     'rft/ui/Selector',
     'rft/ui/TitleGroup',
+    'rft/ui/generic/DateTimeTextBox',
+    'rft/ui/model/SurveyForm',
+    'rft/ui/model/SurveyRunForm',
     'rft/ui/lists/AccountListView',
     'rft/ui/lists/List',
Index: Dev/branches/rest-dojo-ui/client/rft/store.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/store.js	(revision 414)
+++ Dev/branches/rest-dojo-ui/client/rft/store.js	(revision 415)
@@ -1,8 +1,21 @@
 define([
     'dojo/date/stamp',
+    'dojox/json/schema',
+    './schema',
     './store/CouchStore'
-],function(stamp,CouchStore){
+],function(stamp,jsonSchema,schema,CouchStore){
     
-    var store = new CouchStore({target: 'data/couch/'});
+    var store = new CouchStore({
+        target: 'data/couch/',
+        validate: function(object) {
+            var result = jsonSchema.validate(object,schema);
+            if ( result.valid ) {
+                return true;
+            } else {
+                console.log("Found error ",result," for invalid object ",object);
+                return false;
+            }
+        }
+    });
     store.formatDate = function(date){
         return stamp.toISOString(date,{zulu:true});
Index: Dev/branches/rest-dojo-ui/client/rft/store/CouchStore.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/store/CouchStore.js	(revision 414)
+++ Dev/branches/rest-dojo-ui/client/rft/store/CouchStore.js	(revision 415)
@@ -10,7 +10,8 @@
     
     function getCouchError(err){
-        return (err.response && err.response.data)
-                ? json.fromJson(err.response.data)
-                : "Unknown error.";
+        var reason = err.response &&
+                     err.response.data &&
+                     json.fromJson(err.response.data).reason;
+        return reason || "Unknown error.";
     }
 
@@ -74,4 +75,7 @@
             return dfd.promise;
         },
+        validate: function(object) {
+            return true;
+        },
         put: function(object, options){
              // summary:
@@ -83,9 +87,18 @@
              //         id: String
              //
+
+            if ( !this.validate(object) ) {
+                var dfd = new Deferred();
+                dfd.reject("Invalid document.");
+                return dfd.promise;
+            }
+            return this._putValid(object, options);
+
+        },
+        _putValid: function(object,options) {
+            var dfd = new Deferred();
             options = options || {};
-
-            var dfd = new Deferred();
             var id = options.id ? options.id : this.getIdentity(object);
-            var hasId = typeof id != "undefined";
+            var hasId = typeof id !== "undefined";
             xhr(hasId ? "PUT" : "POST", {
                 url: hasId ? this.target + id : this.target,
Index: Dev/branches/rest-dojo-ui/client/rft/ui/QuestionEditorPreviewItem.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/ui/QuestionEditorPreviewItem.js	(revision 414)
+++ Dev/branches/rest-dojo-ui/client/rft/ui/QuestionEditorPreviewItem.js	(revision 415)
@@ -10,5 +10,5 @@
     'dijit/_WidgetBase',
     'dijit/_WidgetsInTemplateMixin',
-    './content/ContentWidgetFactory',
+    './model/QuestionWidgetFactory',
     'dojo/text!./templates/QuestionEditorPreviewItem.html'
 ], function(
@@ -23,5 +23,5 @@
     _WidgetBase,
     _WidgetsInTemplateMixin,
-    ContentWidgetFactory,
+    QuestionWidgetFactory,
     template
 ){
@@ -55,5 +55,5 @@
         },
         _showViewWidget: function() {
-            var factory = new ContentWidgetFactory();
+            var factory = new QuestionWidgetFactory();
             this.innerWidget = factory.createViewWidget( this.item );
             if ( this.innerWidget !== null ) {
@@ -65,5 +65,5 @@
         },
         _showEditWidget: function() {
-            var factory = new ContentWidgetFactory();
+            var factory = new QuestionWidgetFactory();
             this.innerWidget = factory.createEditWidget( this.item );
             if ( this.innerWidget !== null ) {
Index: Dev/branches/rest-dojo-ui/client/rft/ui/generic/DateTimeTextBox.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/ui/generic/DateTimeTextBox.js	(revision 415)
+++ Dev/branches/rest-dojo-ui/client/rft/ui/generic/DateTimeTextBox.js	(revision 415)
@@ -0,0 +1,22 @@
+define([
+    'dojo/_base/declare',
+    'dojo/on',
+    'dijit/_WidgetBase',
+    'dijit/_TemplatedMixin',
+    'dijit/_WidgetsInTemplateMixin',
+    'dojo/text!./templates/DateTimeTextBox.html'
+],function(declare,on,_WidgetBase,_TemplatedMixin,_WidgetsInTemplateMixin,template){
+    return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin],{
+        templateString: template,
+        baseClass: "rftDateTimeTextBox",
+        _getValueAttr: function() {
+            var date = this.dateBox.get('value').getTime();
+            var time = this.timeBox.get('value').getTime();
+            return new Date(date+time);
+        },
+        _setValueAttr: function(value) {
+            this.dateBox.set('value',value);
+            this.timeBox.set('value',value);
+        }
+    });
+});
Index: Dev/branches/rest-dojo-ui/client/rft/ui/generic/TemplatedForm.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/ui/generic/TemplatedForm.js	(revision 415)
+++ Dev/branches/rest-dojo-ui/client/rft/ui/generic/TemplatedForm.js	(revision 415)
@@ -0,0 +1,31 @@
+define([
+    'dojo/_base/array',
+    'dojo/_base/declare',
+    'dojo/on',
+    'dijit/_WidgetsInTemplateMixin',
+    'dijit/form/Form'
+],function(array,declare,on,_WidgetsInTemplateMixin,Form){
+    /** Templated form
+     * Can be used to create form widgets with their content
+     * filled from a template. Inherit from this widget and
+     * provide templateString and optionally baseClass.
+     * 
+     * Example:
+     *    declare("MyForm",[TemplatedForm],{
+     *        templateString: '<form class="${baseClass}"><button>...</button></form>',
+     *        baseClass: 'myForm'
+     *    });
+     */
+    return declare([Form,_WidgetsInTemplateMixin],{
+        _beforeFillContent: function() {
+            this.inherited(arguments);
+            this.containerNode = this.domNode;
+        },
+        postCreate: function() {
+            this.inherited(arguments);
+            /* copied from Form::templateString */
+            on(this.containerNode,"reset",this._onReset);
+            on(this.containerNode,"submit",this._onSubmit);
+        }
+    });
+});
Index: Dev/branches/rest-dojo-ui/client/rft/ui/generic/templates/DateTimeTextBox.html
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/ui/generic/templates/DateTimeTextBox.html	(revision 415)
+++ Dev/branches/rest-dojo-ui/client/rft/ui/generic/templates/DateTimeTextBox.html	(revision 415)
@@ -0,0 +1,4 @@
+<div class="${baseClass}">
+    <div data-dojo-type="dijit/form/DateTextBox" data-dojo-attach-point="dateBox"></div>
+    <div data-dojo-type="dijit/form/TimeTextBox" data-dojo-attach-point="timeBox"></div>
+</div>
Index: Dev/branches/rest-dojo-ui/client/rft/ui/model/QuestionWidgetFactory.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/ui/model/QuestionWidgetFactory.js	(revision 415)
+++ Dev/branches/rest-dojo-ui/client/rft/ui/model/QuestionWidgetFactory.js	(revision 415)
@@ -0,0 +1,410 @@
+define([
+    'dojo/_base/array',
+    'dojo/_base/declare',
+    'dojo/_base/lang', 
+    'dojo/dom-construct', 
+    'dijit/_TemplatedMixin',
+    'dijit/_WidgetBase',
+    'dijit/_Container',
+    'dijit/form/Button',
+    'dijit/form/CheckBox',
+    'dijit/form/Form',
+    'dijit/form/NumberSpinner',
+    'dijit/form/RadioButton',
+    'dijit/form/Textarea',
+    'dijit/form/TextBox',
+    'dojox/layout/TableContainer',
+    './../lists/_EditableListMixin',
+    './../lists/OrderedList'
+],function(array, declare, lang, domConstruct, _TemplatedMixin, _WidgetBase, _Container, Button, CheckBox, Form, NumberSpinner, RadioButton, Textarea, TextBox, TableContainer, _EditableListMixin, OrderedList) {
+    var factory = declare(null, {
+        createViewWidget: function(/*Object*/options) {
+            // options: Object
+            //            type: "header", "text", textinput, etc.
+            //            other type specific fields
+            var fun = this['create'+options.type+'ViewWidget'];
+            var view = fun !== undefined ? fun(options) : null;
+            return view;
+        },
+        createEditWidget: function(/*Object*/options) {
+            var fun = this['create'+options.type+'EditWidget'];
+            var view = fun !== undefined ? fun() : null;
+            if(view)
+                view.set('value', options);
+            return view;
+        },
+
+        createHeaderViewWidget: function(options) {
+            return new HeaderView({
+                options: options
+            });
+        },
+        createHeaderEditWidget: function() {
+            return new HeaderEdit();
+        },
+
+        createTextViewWidget: function(options) {
+            return new TextView({
+                options: options
+            });
+        },
+        createTextEditWidget: function() {
+            return new TextEdit();
+        },
+
+        createDividerViewWidget: function(options) {
+            return new DividerView({
+                options: options
+            });
+        },
+
+        createStringInputViewWidget: function(options) {
+            return new StringInputView({
+                options: options
+            });
+        },
+        createStringInputEditWidget: function() {
+            return new StringInputEdit();
+        },
+
+        createTextInputViewWidget: function(options) {
+            return new TextInputView({
+                options: options
+            });
+        },
+        createTextInputEditWidget: function() {
+            return new TextInputEdit();
+        },
+
+        createIntegerInputViewWidget: function(options) {
+            return new IntegerInputView({
+                options: options
+            });
+        },
+        createIntegerInputEditWidget: function() {
+            return new IntegerInputEdit();
+        },
+
+        createMultipleChoiceInputViewWidget: function(options) {
+            return new MultipleChoiceInputView({
+                options: options
+            });
+        },
+        createMultipleChoiceInputEditWidget: function() {
+            return new MultipleChoiceInputEdit();
+        }
+    });
+
+    var DefaultEdit = declare([Form,_Container],{
+        type: null,
+        addChild: function(widget) {
+            domConstruct.create("label",{
+                innerHTML: widget.title || ''
+            },this.containerNode,'last');
+            this.inherited(arguments,[widget]);
+        },
+        _getValueAttr: function() {
+            var val = this.inherited(arguments);
+            val.type = this.type;
+            return val;
+        }
+    });
+
+    var HeaderView = declare([_WidgetBase], {
+        postCreate: function() {
+            this.domNode.innerHTML = "<h2>"+this.options.content+"</h2>";
+        }
+    });
+
+    var HeaderEdit = declare([DefaultEdit], {
+        type: 'Header',
+        postCreate: function() {
+            this.inherited(arguments);
+            this.addChild(new TextBox({
+                title: 'Content',
+                name: 'content'
+            }));
+        }
+    });
+
+    var TextView = declare([_WidgetBase], {
+        postCreate: function() {
+            this.domNode.innerHTML = "<p>"+this.options.content+"</p>";
+        }
+    });
+
+    var TextEdit = declare([DefaultEdit], {
+        type: 'Text',
+        postCreate: function() {
+            this.inherited(arguments);
+            this.addChild(new Textarea({
+                title: 'Content',
+                name: 'content'
+            }));
+        }
+    });
+
+    var DividerView = declare([_WidgetBase], {
+        postCreate: function() {
+            this.domNode.innerHTML = "<hr>";
+        }
+    });
+
+    var DefaultInputEdit = declare([DefaultEdit],{
+        postCreate: function() {
+            this.inherited(arguments);
+            this.addChild(new TextBox({
+                title: 'Text',
+                name: 'text'
+            }));
+        }
+    });
+
+    var StringInputView = declare([_WidgetBase, _Container],{
+        _textBox: null,
+        postCreate: function() {
+            this._textBox = new TextBox({
+                name: this.options.code || ''
+            });
+            this.addChild(this._textBox);
+            this._textBox.startup();
+        },
+        _setReadOnlyAttr: function(value) {
+            this._textBox.set('readOnly', value);
+        },
+        _getCodeAttr: function() {
+            return this.options.code;
+        },
+        _getValueAttr: function() {
+            return this._textBox.get('value') || "";
+        },
+        _setValueAttr: function(value) {
+            this._textBox.set('value',value || "");
+        }
+    });
+
+    var StringInputEdit = declare([DefaultInputEdit],{
+        type: 'StringInput'
+    });
+
+    var TextInputView = declare([_WidgetBase, _Container], {
+        _textArea: null,
+        postCreate: function() {
+            this._textArea = new Textarea({
+                name: this.options.code
+            });
+            this._textArea.set('maxLength', this.options.maxLength || 1000);
+            this._textArea.set('value', this.options.defaultValue || "");
+            this.addChild(this._textArea);
+            this._textArea.startup();
+        },
+        _getCodeAttr: function() {
+            return this.options.code;
+        },
+        _getValueAttr: function() {
+            return this._textArea.get('value');
+        },
+        _setReadOnlyAttr: function(value) {
+            this._textArea.set('readOnly', value);
+        }
+    });
+
+    var TextInputEdit = declare([DefaultInputEdit], {
+        type: 'TextInput',
+        postCreate: function() {
+            this.inherited(arguments);
+            this.addChild(new NumberSpinner({
+                name: 'maxLength',
+                title: "Maximum length",
+                constraints: {
+                    min: 0
+                }
+            }));
+        }
+    });
+
+    var IntegerInputView = declare([_WidgetBase, _Container], {
+        _numberInput: null,
+        postCreate: function() {
+            this._numberInput = new NumberSpinner({
+                name: this.options.code || '',
+                constraints: {
+                    min: this.options.min,
+                    max: this.options.max,
+                    smallDelta: this.options.step
+                }
+            });
+            this.addChild(this._numberInput);
+            this._numberInput.startup();
+        },
+        _getCodeAttr: function() {
+            return this.options.code;
+        },
+        _getValueAttr: function() {
+            return this._numberInput.get('value');
+        },
+        _setReadOnlyAttr: function(value) {
+            this._numberInput.set('readOnly', value);
+        }
+    });
+
+    var IntegerInputEdit = declare([DefaultInputEdit], {
+        type: 'IntegerInput',
+        postCreate: function() {
+            this.inherited(arguments);
+            this.addChild(new NumberSpinner({
+                title: "Minimum",
+                name: 'min'
+            }));
+            this.addChild(new NumberSpinner({
+                title: "Maximum",
+                name: 'max'
+            }));
+            this.addChild(new NumberSpinner({
+                title: "Step",
+                name: 'step'
+            }));
+        }
+    });
+
+    var MultipleChoiceInputView = declare([_WidgetBase, _Container], {
+        postCreate: function() {
+            var table = new TableContainer({ cols: 1, customClass: "labelsAndValues"} );
+
+            var ctor = this.options.multiple === true ? CheckBox : RadioButton;
+            array.forEach(this.options.items || [],function(item){
+                table.addChild(new ctor({
+                        name: this.options.code || '',
+                        title: item
+                }));
+            },this);
+
+            this.addChild(table);
+            table.startup();
+        },
+        _getCodeAttr: function() {
+            return this.options.code;
+        },
+        _getValueAttr: function() {
+            var checked = array.filter(this.getChildren(),function(child){
+                return child.get('checked');
+            });
+            if ( this.options.multiple ) {
+                return array.map(checked,function(child){
+                    return child.get('value');
+                });
+            } else {
+                return checked.length > 0 ? checked[0].get('value') : null;
+            }
+        },
+        _setReadOnlyAttr: function(value) {
+            array.forEach(this.getChildren(),function(child){
+                child.set('readOnly', value);
+            },this);
+        }
+    });
+
+    var MCOptionItem = declare([_WidgetBase,_TemplatedMixin,_Container],{
+        templateString: '<div><span class="dojoDndHandle">=</span></div>',
+        _textBox: null,
+        postCreate: function() {
+            this._textBox = new TextBox({});
+            this.addChild(this._textBox);
+            this._textBox.startup();
+
+            var del = new Button({
+                label: "X",
+                onClick: lang.hitch(this,'onDelete')
+            });
+            this.addChild(del);
+            del.startup();
+        },
+        _getValueAttr: function() {
+            return this._textBox.set('value');
+        },
+        _setValueAttr: function(value) {
+            this._textBox.set('value',value);
+        },
+        onDelete: function(){}
+    });
+
+    var MCOptionList = declare([OrderedList,_EditableListMixin],{
+        type: 'multipleChoiceOption',
+        withHandles: true,
+        _createAvatarNode: function(item){
+            return domConstruct.create("div",{
+                'class': 'dragAvatar',
+                innerHTML: item
+            });
+        },
+        _createListNode: function(item) {
+            var w = new MCOptionItem();
+            w.startup();
+            w.set('value',item);
+            w.on('delete',lang.hitch(this,'_onRemove',w));
+            return w.domNode;
+        },
+        _onRemove: function(w) {
+            w.destroyRecursive();
+            this.removeCallback && this.removeCallback(item);
+            this.source.sync();
+        }
+    });
+
+    var MultipleChoiceInputEdit = declare([_WidgetBase, _Container], {
+        _codeInput: null,
+        _multipleInput: null,
+        postCreate: function() {
+            var table = new TableContainer({ cols: 1, customClass: "labelsAndValues"} );
+
+            this._codeInput = new TextBox({
+                title: "Code"
+            });
+            table.addChild(this._codeInput);
+            this._codeInput.startup();
+
+            this._multipleInput = new CheckBox({
+                title: "Allow multiple"
+            });
+            table.addChild(this._multipleInput);
+            this._multipleInput.startup();
+
+            var add = new Button({
+                label: "Add",
+                onClick: lang.hitch(this,'_addOption',"")
+            });
+            table.addChild(add);
+            add.startup();
+
+            this._optionsList = new MCOptionList();
+            table.addChild(this._optionsList);
+            this._optionsList.startup();
+
+            this.addChild(table);
+            table.startup();
+        },
+
+        _addOption: function() {
+            this._optionsList.appendItems([""]);
+        },
+
+        _setValueAttr: function(value) {
+            this._codeInput.set('value', value.code || "");
+            this._multipleInput.set('checked', value.multiple);
+            this._optionsList.deleteItems();
+            this._optionsList.appendItems(value.items || []);
+        },
+        _getValueAttr: function() {
+            return {
+                type: "MultipleChoiceInput",
+                code: this._codeInput.get('value') || "",
+                multiple: this._multipleInput.get('checked'),
+                items: array.map(this._optionsList.getItems(),function(item){
+                    return item.get('value');
+                },this)
+            };
+        }
+    });
+
+    return factory;
+});
Index: Dev/branches/rest-dojo-ui/client/rft/ui/model/SurveyForm.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/ui/model/SurveyForm.js	(revision 415)
+++ Dev/branches/rest-dojo-ui/client/rft/ui/model/SurveyForm.js	(revision 415)
@@ -0,0 +1,10 @@
+define([
+    'dojo/_base/declare',
+    'rft/ui/generic/TemplatedForm',
+    'dojo/text!./templates/SurveyForm.html'
+],function(declare,TemplatedForm,template){
+    return declare([TemplatedForm],{
+        templateString: template,
+        baseClass: "rftSurveyForm"
+    });
+});
Index: Dev/branches/rest-dojo-ui/client/rft/ui/model/SurveyRunForm.js
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/ui/model/SurveyRunForm.js	(revision 415)
+++ Dev/branches/rest-dojo-ui/client/rft/ui/model/SurveyRunForm.js	(revision 415)
@@ -0,0 +1,10 @@
+define([
+    'dojo/_base/declare',
+    'rft/ui/generic/TemplatedForm',
+    'dojo/text!./templates/SurveyRunForm.html'
+],function(declare,TemplatedForm,template){
+    return declare([TemplatedForm],{
+        templateString: template,
+        baseClass: "rftSurveyRunForm"
+    });
+});
Index: Dev/branches/rest-dojo-ui/client/rft/ui/model/templates/SurveyForm.html
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/ui/model/templates/SurveyForm.html	(revision 415)
+++ Dev/branches/rest-dojo-ui/client/rft/ui/model/templates/SurveyForm.html	(revision 415)
@@ -0,0 +1,8 @@
+<form class="${baseClass}">
+    <fieldset>
+        <label for="title">Title</label>
+        <input data-dojo-type="dijit/form/TextBox" name="title"/><br/>
+        <label for="description">Description</label>
+        <input data-dojo-type="dijit/form/Textarea" name="description"/><br/>
+    </fieldset>
+</form>
Index: Dev/branches/rest-dojo-ui/client/rft/ui/model/templates/SurveyRunForm.html
===================================================================
--- Dev/branches/rest-dojo-ui/client/rft/ui/model/templates/SurveyRunForm.html	(revision 415)
+++ Dev/branches/rest-dojo-ui/client/rft/ui/model/templates/SurveyRunForm.html	(revision 415)
@@ -0,0 +1,13 @@
+<form class="${baseClass}">
+    <fieldset>
+        <label for="startDate" class="loginLabel">Start date</label>
+        <input type="text" name="startDatetime" data-dojo-type="rft/ui/generic/DateTimeTextBox" />
+        <label for="endDate" class="loginLabel">End date</label>
+        <input type="text" name="endDatetime" data-dojo-type="rft/ui/generic/DateTimeTextBox" />
+        <label for="mode" class="loginLabel">Mode</label>
+        <select name="mode" data-dojo-type="dijit/form/Select">
+            <option value="open" selected="selected">Open</option>
+            <option value="closed">Closed</option>
+        </select><br/>
+    </fieldset>
+</form>
