Changeset 508
- Timestamp:
- 03/12/14 02:23:11 (11 years ago)
- Location:
- Dev/trunk/src
- Files:
-
- 2 added
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
Dev/trunk/src/client/qed-client/model/widgets/QuestionEditorPreviewItem.js
r504 r508 103 103 }, 104 104 _showViewWidget: function() { 105 var newWidget = this._factory.createViewWidget( this.value ); 105 // we pass an empty code, just in case the widget depends 106 // on it,but we don't know the actual code here. 107 var newWidget = this._factory.createViewWidget( lang.mixin({code:""},this.value) ); 106 108 if ( newWidget !== null ) { 107 109 this._destroyInnerWidget(); 108 110 this.innerWidget = newWidget; 111 this.innerWidget.set('readOnly',true); 109 112 this.addChild(this.innerWidget); 110 this.innerWidget.set('readOnly',true);111 113 this.titleNode.innerHTML = this.value.type+" [preview]"; 112 114 domClass.replace(this.editButton.iconNode, "rftIconEdit", "rftIconAccept"); … … 120 122 this._destroyInnerWidget(); 121 123 this.innerWidget = newWidget; 122 this.addChild(this.innerWidget);123 124 this.innerWidget.set('readOnly',this.readOnly); 124 125 this.innerWidget.set('disabled',this.disabled); 126 this.addChild(this.innerWidget); 125 127 this.titleNode.innerHTML = this.value.type+" [editing]"; 126 128 domClass.replace(this.editButton.iconNode, "rftIconAccept", "rftIconEdit"); -
Dev/trunk/src/client/qed-client/model/widgets/SurveyRenderWidget.js
r487 r508 21 21 this.survey = survey; 22 22 var f = new QuestionWidgetFactory(); 23 array.forEach(this.survey.questions,function(question ,question_index){24 array.forEach(question.content || [], function(item ,item_index){25 // The dot causes values to be grouped in an object!23 array.forEach(this.survey.questions,function(question){ 24 array.forEach(question.content || [], function(item){ 25 item.code = question.code; 26 26 var w = f.createViewWidget(item); 27 27 if ( w !== null ) { 28 w.name = question_index.toString()+'/'+question.code.toString()+'.'+item_index.toString();29 28 w.placeAt(this.domNode); 29 w.startup(); 30 30 } 31 31 },this); -
Dev/trunk/src/client/qed-client/model/widgets/questions/MultipleChoiceInputWidget.js
r500 r508 1 1 define([ 2 "../../../widgets/_ComplexValueWidget", 2 "dijit/_Container", 3 "dijit/_TemplatedMixin", 4 "dijit/_WidgetBase", 5 "dijit/_WidgetsInTemplateMixin", 3 6 "dijit/form/CheckBox", 4 7 "dijit/form/RadioButton", … … 7 10 "dojo/dom-construct", 8 11 "dojo/text!./templates/MultipleChoiceInputWidget.html" 9 ], function(_Co mplexValueWidget, CheckBox, RadioButton, array, declare, domConstruct, template) {10 return declare([_ ComplexValueWidget],{12 ], function(_Container, _TemplatedMixin, _WidgetBase, _WidgetsInTemplateMixin, CheckBox, RadioButton, array, declare, domConstruct, template) { 13 return declare([_WidgetBase,_TemplatedMixin,_WidgetsInTemplateMixin,_Container],{ 11 14 templateString: template, 12 allowMultiple: false,13 15 startup: function() { 14 16 if ( this._started ) { return; } … … 17 19 domConstruct.empty(this.domNode); 18 20 var Ctor = this.allowMultiple === true ? CheckBox : RadioButton; 19 array.forEach(this.items, function(item , index){21 array.forEach(this.items, function(item){ 20 22 var div = domConstruct.create("div", { 21 23 }, this.domNode, "last"); 22 24 var input = new Ctor({ 23 name: this. allowMultiple === true ? index.toString() : 'choice',24 value: item.text25 name: this.code + (this.allowMultiple === true ? item.subcode : ''), 26 value: this.allowMultiple === true ? null : item.subcode 25 27 }).placeAt(div); 26 28 var label = domConstruct.create("label",{ … … 29 31 }, div); 30 32 }, this); 31 },32 _getValueAttr: function() {33 var value = this.inherited(arguments);34 /*if ( this.allowMultiple === true ) {35 return value;36 } else {37 return value.choice; //.length > 0;38 }*/39 },40 _setValueAttr: function(value) {41 var inherited = this.getInherited(arguments);42 if ( this.allowMultiple === true ) {43 inherited.call(this,value);44 } else {45 inherited.call(this,{choice:value ? ["on"] : []});46 }47 33 } 48 34 }); -
Dev/trunk/src/client/qed-client/model/widgets/questions/NumberInputWidget.js
r443 r508 1 1 define([ 2 "../../../widgets/_ComplexValueWidget", 2 "dijit/_Container", 3 "dijit/_TemplatedMixin", 4 "dijit/_WidgetBase", 5 "dijit/_WidgetsInTemplateMixin", 3 6 "dojo/_base/declare", 4 7 "dojo/text!./templates/NumberInputWidget.html" 5 ], function(_ComplexValueWidget, declare, template) { 6 return declare([_ComplexValueWidget],{ 8 ], function(_Container, _TemplatedMixin, _WidgetBase, _WidgetsInTemplateMixin, declare, template) { 9 return declare([_WidgetBase,_TemplatedMixin,_WidgetsInTemplateMixin,_Container],{ 10 templateString: template, 7 11 text: '', 8 maxLength: null,9 templateString: template,10 12 startup: function() { 13 if ( this._started ) { return; } 14 this.inherited(arguments); 15 11 16 var constraints = {}; 12 if ( this.min !== null&& !isNaN(this.min) ) {17 if ( this.min && !isNaN(this.min) ) { 13 18 constraints.min = this.min; 14 19 } 15 if ( this.max !== null&& !isNaN(this.max) ) {20 if ( this.max && !isNaN(this.max) ) { 16 21 constraints.max = this.max; 17 22 } 18 if ( this.places !== null&& !isNaN(this.places) ) {23 if ( this.places && !isNaN(this.places) ) { 19 24 constraints.places = this.places; 20 25 } 21 26 this.numberBox.set('constraints', constraints); 22 },23 _getValueAttr: function() {24 return this.numberBox.get('value');25 },26 _setValueAttr: function(value) {27 return this.numberBox.set('value', value);28 27 } 29 28 }); -
Dev/trunk/src/client/qed-client/model/widgets/questions/ScaleInputWidget.js
r443 r508 1 1 define([ 2 "../../../widgets/_ComplexValueWidget", 2 "dijit/_Container", 3 "dijit/_TemplatedMixin", 4 "dijit/_WidgetBase", 5 "dijit/_WidgetsInTemplateMixin", 3 6 "dijit/form/RadioButton", 4 7 "dojo/_base/array", … … 8 11 "dojo/dom-construct", 9 12 "dojo/text!./templates/ScaleInputWidget.html" 10 ], function(_Co mplexValueWidget, RadioButton, array, declare, lang, domAttr, domConstruct, template) {11 return declare([_ ComplexValueWidget],{13 ], function(_Container, _TemplatedMixin, _WidgetBase, _WidgetsInTemplateMixin, RadioButton, array, declare, lang, domAttr, domConstruct, template) { 14 return declare([_WidgetBase,_TemplatedMixin,_WidgetsInTemplateMixin,_Container],{ 12 15 templateString: template, 13 16 baseClass: "qedScaleWidget", 14 min: 0,15 max: 0,16 minLabel: "",17 maxLabel: "",18 naLabel: null,19 items: null,20 value: null,21 constuctor: function() {22 this.items = [];23 this.value = {};24 },25 17 startup: function() { 26 18 if ( this._started ) { return; } … … 42 34 }, 43 35 _renderItems: function() { 44 array.forEach(this.items, function(item ,index) {36 array.forEach(this.items, function(item) { 45 37 var tr = domConstruct.create("tr", {}, this.itemsNode); 46 38 var td; … … 57 49 td = domConstruct.create("td", {}, tr); 58 50 radio = new RadioButton({ 59 name: index.toString(),51 name: this.code+item.subcode, 60 52 value: i.toString() 61 53 }); … … 69 61 td = domConstruct.create("td", {}, tr); 70 62 radio = new RadioButton({ 71 name: index.toString(),63 name: this.code+item.subcode, 72 64 value: "n/a" 73 65 }); -
Dev/trunk/src/client/qed-client/model/widgets/questions/StringInputWidget.js
r443 r508 1 1 define([ 2 "../../../widgets/_ComplexValueWidget", 2 "dijit/_Container", 3 "dijit/_TemplatedMixin", 4 "dijit/_WidgetBase", 5 "dijit/_WidgetsInTemplateMixin", 3 6 "dojo/_base/declare", 4 7 "dojo/text!./templates/StringInputWidget.html" 5 ], function(_ComplexValueWidget, declare, template) { 6 return declare([_ComplexValueWidget],{ 7 text: '', 8 ], function(_Container, _TemplatedMixin, _WidgetBase, _WidgetsInTemplateMixin, declare, template) { 9 return declare([_WidgetBase,_TemplatedMixin,_WidgetsInTemplateMixin,_Container],{ 8 10 templateString: template, 9 _getValueAttr: function() { 10 return this.textBox.get('value'); 11 }, 12 _setValueAttr: function(value) { 13 return this.textBox.set('value', value); 14 } 11 text: '' 15 12 }); 16 13 }); -
Dev/trunk/src/client/qed-client/model/widgets/questions/TextInputWidget.js
r461 r508 1 1 define([ 2 "../../../widgets/_ComplexValueWidget", 2 "dijit/_Container", 3 "dijit/_TemplatedMixin", 4 "dijit/_WidgetBase", 5 "dijit/_WidgetsInTemplateMixin", 3 6 "dojo/_base/declare", 4 7 "dojo/text!./templates/TextInputWidget.html" 5 ], function(_ComplexValueWidget, declare, template) { 6 return declare([_ComplexValueWidget],{ 8 ], function(_Container, _TemplatedMixin, _WidgetBase, _WidgetsInTemplateMixin, declare, template) { 9 return declare([_WidgetBase,_TemplatedMixin,_WidgetsInTemplateMixin,_Container],{ 10 templateString: template, 7 11 text: '', 8 maxLength: null,9 templateString: template,10 12 startup: function() { 13 if ( this._started ) { return; } 14 this.inherited(arguments); 15 11 16 if ( this.maxLength ) { 12 17 this.textArea.set('maxLength', this.maxLength); 13 18 } 14 },15 _getValueAttr: function() {16 return this.textArea.get('value');17 },18 _setValueAttr: function(value) {19 return this.textArea.set('value', value);20 19 } 21 20 }); -
Dev/trunk/src/client/qed-client/model/widgets/questions/templates/MultipleChoiceInputWidget.html
r461 r508 1 < form>2 </ form>1 <div> 2 </div> -
Dev/trunk/src/client/qed-client/model/widgets/questions/templates/NumberInputWidget.html
r461 r508 1 < form>1 <div> 2 2 <p>${text}</p> 3 <div class="qedField" data-dojo-attach-point="numberBox" data-dojo-type="dijit/form/NumberTextBox" name="text"></div> 4 </form> 3 <div class="qedField" 4 data-dojo-attach-point="numberBox" 5 data-dojo-type="dijit/form/NumberTextBox" 6 name="${code}${subcode}"></div> 7 </div> -
Dev/trunk/src/client/qed-client/model/widgets/questions/templates/ScaleInputWidget.html
r461 r508 1 < formclass="${baseClass}">1 <div class="${baseClass}"> 2 2 <table> 3 3 <thead> … … 12 12 </tbody> 13 13 </table> 14 </ form>14 </div> -
Dev/trunk/src/client/qed-client/model/widgets/questions/templates/StringInputWidget.html
r461 r508 1 < form>1 <div> 2 2 <p>${text}</p> 3 <div data-dojo-attach-point="textBox" data-dojo-type="dijit/form/TextBox" name="text"></div> 4 </form> 3 <div data-dojo-type="dijit/form/TextBox" 4 name="${code}${subcode}"></div> 5 </div> -
Dev/trunk/src/client/qed-client/model/widgets/questions/templates/TextInputWidget.html
r492 r508 1 < form>1 <div> 2 2 <p>${text}</p> 3 <textarea class="qedField" data-dojo-attach-point="textArea" data-dojo-type="dijit/form/Textarea" name="text"></textarea> 4 </form> 3 <textarea class="qedField" 4 data-dojo-attach-point="textArea" 5 data-dojo-type="dijit/form/Textarea" 6 name="${code}${subcode}"></textarea> 7 </div> -
Dev/trunk/src/client/qed-client/model/widgets/templates/SurveyRunWidget.html
r493 r508 1 1 <form class="${baseClass}"> 2 3 <div> 4 <label for="mode" class="qedLabel">Title</label> 5 <textarea name="title" class="qedField" 6 data-dojo-props="required: true" 7 data-dojo-type="dijit/form/ValidationTextBox"></textarea> 8 </div> 2 9 3 10 <div> -
Dev/trunk/src/client/qed-client/pages/response.js
r503 r508 42 42 var canDelete = (this.response && 43 43 this.response._surveyRun.respondentCanDeleteOwnResponse); 44 this.cancelButton.set('disabled',canDelete ||false);44 this.cancelButton.set('disabled',canDelete?false:true); 45 45 this.surveyWidget.set('readOnly', false); 46 46 }, -
Dev/trunk/src/client/qed-client/pages/surveys.js
r497 r508 49 49 _onRunSurvey:function(survey){ 50 50 var surveyRun = surveyRuns.create(); 51 surveyRun.title = 'Run of "' + survey.title + '" of '+(new Date().toString()); 51 52 surveyRun.survey = survey; 52 53 surveyRuns.save(surveyRun) -
Dev/trunk/src/server/app.js
r507 r508 154 154 } 155 155 function areDocsPublished(docs) { 156 return _.every(docs, isDocPublished);156 return _.every(docs, isDocPublished); 157 157 } 158 158 function isDocPublished(doc) { … … 592 592 if ( !areDocsUnique(doc.questions) ) { 593 593 hr = new HTTPResult(400,{error:"Survey contains duplicate questions."}); 594 } else if ( !areDocsPublished(doc.questions) || isDocPublished(doc) ) {594 } else if ( isDocPublished(doc) && !areDocsPublished(doc.questions) ) { 595 595 hr = new HTTPResult(400,{error:"Cannot publish Survey with unpublished questions."}); 596 596 } else { … … 610 610 var doc = req.body; 611 611 var rev = etags.parse(req.header('If-Match'))[0] || (doc && doc._rev); 612 var hr;613 612 if ( !areDocsUnique(doc.questions) ) { 614 613 new HTTPResult(400,{error:"Survey contains duplicate questions."}) 615 614 .handle(res.send.bind(res)); 616 } else if ( !areDocsPublished(doc.questions) || isDocPublished(doc) ) { 617 hr = new HTTPResult(400,{error:"Cannot publish Survey with unpublished questions."}); 615 } else if ( isDocPublished(doc) && !areDocsPublished(doc.questions) ) { 616 new HTTPResult(400,{error:"Cannot publish Survey with unpublished questions."}) 617 .handle(res.send.bind(res)); 618 618 } else { 619 619 putDocument(id,rev,'Survey',doc) … … 718 718 .handle({ 719 719 200: function(responses) { 720 var flatResponses = responsesToVariables(responses); 720 var answers = _.map(responses,function(response){ 721 return response.answers; 722 }); 721 723 res.set({ 722 724 'Content-Disposition': 'attachment; filename=surveyRun-'+id+'-responses.csv' 723 725 }); 724 726 res.status(200); 725 writeObjectsToCSVStream( flatResponses, res);727 writeObjectsToCSVStream(answers, res); 726 728 res.end(); 727 729 }, … … 953 955 } 954 956 955 function responsesToVariables(responses) {956 return _.map(responses, responseToVariables);957 }958 959 function responseToVariables(response) {960 var result = flattenObject(response.answers);961 return result;962 }963 964 function flattenObject(value) {965 var result = {};966 (function agg(val,key,res){967 if ( _.isObject(val) ) {968 var keys = _.keys(val);969 // FIXME : dirty hack for questions with only one input970 if ( keys.length === 1 ) {971 agg(val[keys[0]],key,res);972 } else {973 _.forEach(val, function(v,k){974 agg(v,(key ? key+'.' : '')+k,res);975 });976 }977 } else if ( _.isArray(val) ) {978 // FIXME : dirty hack for questions with only one input979 if ( val.length === 1 ) {980 agg(val[0],key,res);981 } else {982 _.forEach(val, function(v,i){983 agg(v,(key ? key+'.' : '')+i,res);984 });985 }986 } else {987 res[key] = val;988 }989 })(value,null,result);990 return result;991 }992 993 957 function writeObjectsToCSVStream(objects, stream, prelude) { 994 958 var keys = _.chain(objects) -
Dev/trunk/src/server/config/couchdb-design-docs.js
r506 r508 11 11 12 12 "qed/schemaInfo": { 13 version: " 3"13 version: "4" 14 14 }, 15 15 -
Dev/trunk/src/server/config/couchdb-schema.json
r506 r508 2 2 "$schema": "http://json-schema.org/draft-04/schema#", 3 3 "title": "QED Object Schema", 4 "version": " 3",4 "version": "4", 5 5 "type": "object", 6 6 "oneOf": [ … … 10 10 "definitions": { 11 11 "nonEmptyString": { "type": "string", "minLength": 1 }, 12 "codeString": { "type": "string", "pattern": "^[A-Za-z0-9]+$" }, 12 13 "schemaInfo": { 13 14 "type": "object", … … 37 38 "_rev": { "$ref": "#/definitions/nonEmptyString" }, 38 39 "categories": { "type": "array", "items": { "$ref": "#/definitions/nonEmptyString" } }, 39 "code": { "$ref": "#/definitions/ nonEmptyString" },40 "code": { "$ref": "#/definitions/codeString" }, 40 41 "content": { "type": "array", "items": { "$ref": "#/definitions/content/any" } }, 41 42 "description": { "$ref": "#/definitions/nonEmptyString" }, … … 86 87 "_id": { "$ref": "#/definitions/nonEmptyString" }, 87 88 "_rev": { "$ref": "#/definitions/nonEmptyString" }, 88 "answers": { "type": "object" }, 89 "answers": { 90 "type": "object", 91 "patternProperties": { 92 "^[A-Za-z0-9]+$": {} 93 }, 94 "additionalProperties": false 95 }, 89 96 "email": { "type": "string", "format": "email" }, 90 97 "publicationDate": { "type": "string", "format": "datetime" }, … … 139 146 "properties": { 140 147 "type": { "type": "string", "pattern": "^StringInput$" }, 141 "subcode": { "$ref": "#/definitions/ nonEmptyString" },148 "subcode": { "$ref": "#/definitions/codeString" }, 142 149 "text": { "$ref": "#/definitions/nonEmptyString" } 143 150 }, … … 150 157 "type": { "type": "string", "pattern": "^TextInput$" }, 151 158 "maxLength": { "type": "integer" }, 152 "subcode": { "$ref": "#/definitions/ nonEmptyString" },159 "subcode": { "$ref": "#/definitions/codeString" }, 153 160 "text": { "$ref": "#/definitions/nonEmptyString" } 154 161 }, … … 163 170 "max": { "type": "integer" }, 164 171 "places": { "type": "integer" }, 165 "subcode": { "$ref": "#/definitions/ nonEmptyString" },172 "subcode": { "$ref": "#/definitions/codeString" }, 166 173 "text": { "$ref": "#/definitions/nonEmptyString" } 167 174 }, … … 183 190 "minLabel": { "$ref": "#/definitions/nonEmptyString" }, 184 191 "maxLabel": { "$ref": "#/definitions/nonEmptyString" }, 185 "subcode": { "$ref": "#/definitions/ nonEmptyString" },192 "subcode": { "$ref": "#/definitions/codeString" }, 186 193 "text": { "$ref": "#/definitions/nonEmptyString" } 187 194 }, … … 201 208 "type": "object", 202 209 "properties": { 203 "subcode": { "$ref": "#/definitions/ nonEmptyString" },210 "subcode": { "$ref": "#/definitions/codeString" }, 204 211 "text": { "$ref": "#/definitions/nonEmptyString" } 205 212 }, … … 210 217 "type": "object", 211 218 "properties": { 212 "subcode": { "$ref": "#/definitions/ nonEmptyString" },219 "subcode": { "$ref": "#/definitions/codeString" }, 213 220 "text": { "$ref": "#/definitions/nonEmptyString" } 214 221 },
Note: See TracChangeset
for help on using the changeset viewer.