Ignore:
Timestamp:
04/29/13 19:35:10 (12 years ago)
Author:
hendrikvanantwerpen
Message:

Big cleanup of the question content.

  • Replaced old list implementations with a new one that behaves like a form widget.
  • All question content is now in separate widgets, not in the factory itself.
  • Added form and widget validation for question editing.
Location:
Dev/trunk/client/qed/model/widgets/questions
Files:
1 added
1 moved

Legend:

Unmodified
Added
Removed
  • Dev/trunk/client/qed/model/widgets/questions/Factory.js

    r435 r441  
    11define([
    2     "../../widgets/list/OrderedList",
    3     "../../widgets/list/_EditableListMixin",
     2    "./HeaderConfigWidget",
     3    "./HeaderWidget",
     4    "./MultipleChoiceInputConfigWidget",
     5    "./MultipleChoiceInputWidget",
     6    "./NumberInputConfigWidget",
     7    "./NumberInputWidget",
    48    "./ScaleInputConfigWidget",
    59    "./ScaleInputWidget",
    6     "dijit/_Container",
    7     "dijit/_TemplatedMixin",
     10    "./StringInputConfigWidget",
     11    "./StringInputWidget",
     12    "./TextConfigWidget",
     13    "./TextInputConfigWidget",
     14    "./TextInputWidget",
     15    "./TextWidget",
    816    "dijit/_WidgetBase",
    9     "dijit/form/Button",
    10     "dijit/form/CheckBox",
    11     "dijit/form/Form",
    12     "dijit/form/NumberSpinner",
    13     "dijit/form/RadioButton",
    14     "dijit/form/TextBox",
    15     "dijit/form/Textarea",
    16     "dojo/_base/array",
    17     "dojo/_base/declare",
    18     "dojo/_base/lang",
    19     "dojo/dom-construct",
    20     "dojox/layout/TableContainer"
    21 ], function(OrderedList, _EditableListMixin, ScaleInputConfigWidget, ScaleInputWidget, _Container, _TemplatedMixin, _WidgetBase, Button, CheckBox, Form, NumberSpinner, RadioButton, TextBox, Textarea, array, declare, lang, domConstruct, TableContainer) {
     17    "dojo/_base/declare"
     18], function(HeaderConfigWidget, HeaderWidget, MultipleChoiceInputConfigWidget, MultipleChoiceInputWidget, NumberInputConfigWidget, NumberInputWidget, ScaleInputConfigWidget, ScaleInputWidget, StringInputConfigWidget, StringInputWidget, TextConfigWidget, TextInputConfigWidget, TextInputWidget, TextWidget, _WidgetBase, declare) {
    2219    var factory = declare(null, {
    2320        createViewWidget: function(/*Object*/options) {
     
    3128        createEditWidget: function(/*Object*/options) {
    3229            var fun = this['create'+options.type+'EditWidget'];
    33             var view = fun !== undefined ? fun() : null;
    34             if (view) {
    35                 view.set('value', options);
    36             }
     30            var view = fun !== undefined ? fun(options) : null;
    3731            return view;
    3832        },
    3933
    40         createHeaderViewWidget: function(options) {
    41             return new HeaderView({
    42                 options: options
     34        createHeaderViewWidget: function(config) {
     35            return new HeaderWidget(config);
     36        },
     37        createHeaderEditWidget: function(config) {
     38            return new HeaderConfigWidget({
     39                value: config
    4340            });
    4441        },
    45         createHeaderEditWidget: function() {
    46             return new HeaderEdit();
     42
     43        createTextViewWidget: function(config) {
     44            return new TextWidget(config);
    4745        },
    48 
    49         createTextViewWidget: function(options) {
    50             return new TextView({
    51                 options: options
     46        createTextEditWidget: function(config) {
     47            return new TextConfigWidget({
     48                value: config
    5249            });
    53         },
    54         createTextEditWidget: function() {
    55             return new TextEdit();
    5650        },
    5751
     
    6256        },
    6357
    64         createStringInputViewWidget: function(options) {
    65             return new StringInputView({
    66                 options: options
     58        createStringInputViewWidget: function(config) {
     59            return new StringInputWidget(config);
     60        },
     61        createStringInputEditWidget: function(config) {
     62            return new StringInputConfigWidget({
     63                value: config
    6764            });
    6865        },
    69         createStringInputEditWidget: function() {
    70             return new StringInputEdit();
     66
     67        createTextInputViewWidget: function(config) {
     68            return new TextInputWidget(config);
     69        },
     70        createTextInputEditWidget: function(config) {
     71            return new TextInputConfigWidget({
     72                value: config
     73            });
    7174        },
    7275
    73         createTextInputViewWidget: function(options) {
    74             return new TextInputView({
    75                 options: options
     76        createNumberInputViewWidget: function(config) {
     77            return new NumberInputWidget(config);
     78        },
     79        createNumberInputEditWidget: function(config) {
     80            return new NumberInputConfigWidget({
     81                value: config
    7682            });
    7783        },
    78         createTextInputEditWidget: function() {
    79             return new TextInputEdit();
     84
     85        createMultipleChoiceInputViewWidget: function(config) {
     86            return new MultipleChoiceInputWidget(config);
    8087        },
    81 
    82         createIntegerInputViewWidget: function(options) {
    83             return new IntegerInputView({
    84                 options: options
     88        createMultipleChoiceInputEditWidget: function(config) {
     89            return new MultipleChoiceInputConfigWidget({
     90                value: config
    8591            });
    86         },
    87         createIntegerInputEditWidget: function() {
    88             return new IntegerInputEdit();
    89         },
    90 
    91         createMultipleChoiceInputViewWidget: function(options) {
    92             return new MultipleChoiceInputView({
    93                 options: options
    94             });
    95         },
    96         createMultipleChoiceInputEditWidget: function() {
    97             return new MultipleChoiceInputEdit();
    9892        },
    9993
     
    108102    });
    109103
    110     var DefaultEdit = declare([Form,_Container],{
    111         type: null,
    112         addChild: function(widget) {
    113             domConstruct.create("label",{
    114                 innerHTML: widget.title || ''
    115             },this.containerNode,'last');
    116             this.inherited(arguments,[widget]);
    117         },
    118         _getValueAttr: function() {
    119             var val = this.inherited(arguments);
    120             val.type = this.type;
    121             return val;
    122         }
    123     });
    124 
    125     var HeaderView = declare([_WidgetBase], {
    126         postCreate: function() {
    127             this.domNode.innerHTML = "<h2>"+this.options.content+"</h2>";
    128         }
    129     });
    130 
    131     var HeaderEdit = declare([DefaultEdit], {
    132         type: 'Header',
    133         postCreate: function() {
    134             this.inherited(arguments);
    135             this.addChild(new TextBox({
    136                 title: 'Content',
    137                 name: 'content'
    138             }));
    139         }
    140     });
    141 
    142     var TextView = declare([_WidgetBase], {
    143         postCreate: function() {
    144             this.domNode.innerHTML = "<p>"+this.options.content+"</p>";
    145         }
    146     });
    147 
    148     var TextEdit = declare([DefaultEdit], {
    149         type: 'Text',
    150         postCreate: function() {
    151             this.inherited(arguments);
    152             this.addChild(new Textarea({
    153                 title: 'Content',
    154                 name: 'content'
    155             }));
    156         }
    157     });
    158 
    159104    var DividerView = declare([_WidgetBase], {
    160105        postCreate: function() {
     
    163108    });
    164109
    165     var DefaultInputEdit = declare([DefaultEdit],{
    166         postCreate: function() {
    167             this.inherited(arguments);
    168             this.addChild(new TextBox({
    169                 title: 'Text',
    170                 name: 'text'
    171             }));
    172         }
    173     });
    174 
    175     var StringInputView = declare([_WidgetBase, _Container],{
    176         _textBox: null,
    177         postCreate: function() {
    178             this._textBox = new TextBox({
    179                 name: this.options.code || ''
    180             });
    181             this.addChild(this._textBox);
    182             this._textBox.startup();
    183         },
    184         _setReadOnlyAttr: function(value) {
    185             this._textBox.set('readOnly', value);
    186         },
    187         _getCodeAttr: function() {
    188             return this.options.code;
    189         },
    190         _getValueAttr: function() {
    191             return this._textBox.get('value') || "";
    192         },
    193         _setValueAttr: function(value) {
    194             this._textBox.set('value',value || "");
    195         }
    196     });
    197 
    198     var StringInputEdit = declare([DefaultInputEdit],{
    199         type: 'StringInput'
    200     });
    201 
    202     var TextInputView = declare([_WidgetBase, _Container], {
    203         _textArea: null,
    204         postCreate: function() {
    205             this._textArea = new Textarea({
    206                 name: this.options.code
    207             });
    208             this._textArea.set('maxLength', this.options.maxLength || 1000);
    209             this._textArea.set('value', this.options.defaultValue || "");
    210             this.addChild(this._textArea);
    211             this._textArea.startup();
    212         },
    213         _getCodeAttr: function() {
    214             return this.options.code;
    215         },
    216         _getValueAttr: function() {
    217             return this._textArea.get('value');
    218         },
    219         _setReadOnlyAttr: function(value) {
    220             this._textArea.set('readOnly', value);
    221         }
    222     });
    223 
    224     var TextInputEdit = declare([DefaultInputEdit], {
    225         type: 'TextInput',
    226         postCreate: function() {
    227             this.inherited(arguments);
    228             this.addChild(new NumberSpinner({
    229                 name: 'maxLength',
    230                 title: "Maximum length",
    231                 constraints: {
    232                     min: 0
    233                 }
    234             }));
    235         }
    236     });
    237 
    238     var IntegerInputView = declare([_WidgetBase, _Container], {
    239         _numberInput: null,
    240         postCreate: function() {
    241             this._numberInput = new NumberSpinner({
    242                 name: this.options.code || '',
    243                 constraints: {
    244                     min: this.options.min,
    245                     max: this.options.max,
    246                     smallDelta: this.options.step
    247                 }
    248             });
    249             this.addChild(this._numberInput);
    250             this._numberInput.startup();
    251         },
    252         _getCodeAttr: function() {
    253             return this.options.code;
    254         },
    255         _getValueAttr: function() {
    256             return this._numberInput.get('value');
    257         },
    258         _setReadOnlyAttr: function(value) {
    259             this._numberInput.set('readOnly', value);
    260         }
    261     });
    262 
    263     var IntegerInputEdit = declare([DefaultInputEdit], {
    264         type: 'IntegerInput',
    265         postCreate: function() {
    266             this.inherited(arguments);
    267             this.addChild(new NumberSpinner({
    268                 title: "Minimum",
    269                 name: 'min'
    270             }));
    271             this.addChild(new NumberSpinner({
    272                 title: "Maximum",
    273                 name: 'max'
    274             }));
    275             this.addChild(new NumberSpinner({
    276                 title: "Step",
    277                 name: 'step'
    278             }));
    279         }
    280     });
    281 
    282     var MultipleChoiceInputView = declare([_WidgetBase, _Container], {
    283         postCreate: function() {
    284             var table = new TableContainer({ cols: 1, customClass: "labelsAndValues"} );
    285 
    286             var Ctor = this.options.multiple === true ? CheckBox : RadioButton;
    287             array.forEach(this.options.items || [], function(item){
    288                 table.addChild(new Ctor({
    289                     name: this.options.code || '',
    290                     title: item
    291                 }));
    292             },this);
    293 
    294             this.addChild(table);
    295             table.startup();
    296         },
    297         _getCodeAttr: function() {
    298             return this.options.code;
    299         },
    300         _getValueAttr: function() {
    301             var checked = array.filter(this.getChildren(),function(child){
    302                 return child.get('checked');
    303             });
    304             if ( this.options.multiple ) {
    305                 return array.map(checked,function(child){
    306                     return child.get('value');
    307                 });
    308             } else {
    309                 return checked.length > 0 ? checked[0].get('value') : null;
    310             }
    311         },
    312         _setReadOnlyAttr: function(value) {
    313             array.forEach(this.getChildren(),function(child){
    314                 child.set('readOnly', value);
    315             },this);
    316         }
    317     });
    318 
    319     var MCOptionItem = declare([_WidgetBase,_TemplatedMixin,_Container],{
    320         templateString: '<div><span class="dojoDndHandle">=</span></div>',
    321         _textBox: null,
    322         postCreate: function() {
    323             this._textBox = new TextBox({});
    324             this.addChild(this._textBox);
    325             this._textBox.startup();
    326 
    327             var del = new Button({
    328                 label: "X",
    329                 onClick: lang.hitch(this,'onDelete')
    330             });
    331             this.addChild(del);
    332             del.startup();
    333         },
    334         _getValueAttr: function() {
    335             return this._textBox.set('value');
    336         },
    337         _setValueAttr: function(value) {
    338             this._textBox.set('value',value);
    339         },
    340         onDelete: function(){}
    341     });
    342 
    343     var MCOptionList = declare([OrderedList,_EditableListMixin],{
    344         type: 'multipleChoiceOption',
    345         withHandles: true,
    346         _createAvatarNode: function(item){
    347             return domConstruct.create("div",{
    348                 'class': 'dragAvatar',
    349                 innerHTML: item
    350             });
    351         },
    352         _createListNode: function(item) {
    353             var w = new MCOptionItem();
    354             w.startup();
    355             w.set('value',item);
    356             w.on('delete',lang.hitch(this,'_onRemove',w,item));
    357             return w.domNode;
    358         },
    359         _onRemove: function(w,item) {
    360             w.destroyRecursive();
    361             if ( this.removeCallback ) { this.removeCallback(item); }
    362             this.source.sync();
    363         }
    364     });
    365 
    366     var MultipleChoiceInputEdit = declare([_WidgetBase, _Container], {
    367         _multipleInput: null,
    368         postCreate: function() {
    369             var table = new TableContainer({ cols: 1, customClass: "labelsAndValues"} );
    370 
    371             this._multipleInput = new CheckBox({
    372                 title: "Allow multiple"
    373             });
    374             table.addChild(this._multipleInput);
    375             this._multipleInput.startup();
    376 
    377             var add = new Button({
    378                 label: "Add",
    379                 onClick: lang.hitch(this,'_addOption',"")
    380             });
    381             table.addChild(add);
    382             add.startup();
    383 
    384             this._optionsList = new MCOptionList();
    385             table.addChild(this._optionsList);
    386             this._optionsList.startup();
    387 
    388             this.addChild(table);
    389             table.startup();
    390         },
    391 
    392         _addOption: function() {
    393             this._optionsList.appendItems([""]);
    394         },
    395 
    396         _setValueAttr: function(value) {
    397             this._multipleInput.set('checked', value.multiple);
    398             this._optionsList.deleteItems();
    399             this._optionsList.appendItems(value.items || []);
    400         },
    401         _getValueAttr: function() {
    402             return {
    403                 type: "MultipleChoiceInput",
    404                 multiple: this._multipleInput.get('checked'),
    405                 items: array.map(this._optionsList.getItems(),function(item){
    406                     return item.get('value');
    407                 },this)
    408             };
    409         }
    410     });
    411 
    412110    return factory;
    413111});
Note: See TracChangeset for help on using the changeset viewer.