Changeset 513


Ignore:
Timestamp:
03/13/14 22:21:55 (11 years ago)
Author:
hendrikvanantwerpen
Message:
  • Another shot at getting change events right for _ComplexValueMixin. Our previous approach made it impossible to detect if a change was cause during startup. Now we work purely with widget 'change' events. Children are connected during postCreate, addChild. If you add children otherwise you need to call connectChildsChanges yourself. Also to make sure events are generated, use _setValueInternal if you really need to set the value attribute yourself.
  • Removed unused widget.
Location:
Dev/trunk/src/client/qed-client
Files:
3 deleted
10 edited

Legend:

Unmodified
Added
Removed
  • Dev/trunk/src/client/qed-client/css/qed.less

    r510 r513  
    2323@import "ui/topbar.less";
    2424@import "ui/LoginDialog.less";
    25 @import "widgets/MultipleChoiceWidget.less";
    2625@import "widgets/lists/List.less";
    2726@import "widgets/Selector.less";
  • Dev/trunk/src/client/qed-client/model/widgets/QuestionEditorPreviewItem.js

    r512 r513  
    4444            return false;
    4545        },
    46         _getValueAttr: function(value) {
     46        _getValueAttr: function() {
    4747            if ( this._editing === true ) {
    48                 this.value = this.innerWidget.get('value');
     48                return this.innerWidget.get('value');
    4949            }
    5050            return this.value;
    5151        },
    52         _setValueAttr: function(value) {
    53             this.value = value;
     52        _setValueAttr: function(value,priorityChange) {
     53            this._setValueInternal(value,priorityChange);
    5454            if ( this._editing  === true ) {
    5555                this._showEditWidget();
     
    9797            if ( this._editing === true ) {
    9898                if (!this.innerWidget.validate || this.innerWidget.validate() ) {
    99                     this.value = this.innerWidget.get('value');
     99                    this._setValueInternal(this.innerWidget.get('value'));
    100100                    this._showViewWidget();
    101101                }
     
    149149            if ( this.innerWidget !== null ) {
    150150                if ( this._editing === true ) {
    151                     this.triggerOnChange();
     151                    this._onChange();
     152                    // how to force event on widget here?
    152153                }
    153154                this.removeChild(this.innerWidget);
  • Dev/trunk/src/client/qed-client/model/widgets/SurveyRenderWidget.js

    r511 r513  
    3838                lang.mixin(newValue,widget.get('value'));
    3939            },this);
    40             this.value = newValue;
    41             return this.value;
     40            return newValue;
    4241        },
    43         _setValueAttr: function(value) {
     42        _setValueAttr: function(value,priorityChange) {
     43            this._setValueInternal(value,priorityChange);
    4444            array.forEach(this._getDescendantFormWidgets(),function(widget){
    4545                widget.set('value',value);
    4646            },this);
    47             this.value = value;
    4847        }
    4948    });
  • Dev/trunk/src/client/qed-client/model/widgets/SurveyRunWidget.js

    r512 r513  
    1414            }));
    1515        },
    16         startup: function() {
    17             this.inherited(arguments);
    18         },
    1916        _getValueAttr: function() {
    2017            var value = this.inherited(arguments);
  • Dev/trunk/src/client/qed-client/model/widgets/templates/QuestionEditorToolkit.html

    r502 r513  
    66                <label>Code:</label><input data-dojo-type="dijit/form/ValidationTextBox" required="required" name="code"/>
    77                <label>Categories:</label>
    8                 <div data-dojo-attach-point="categoryListNode" class="rftLineListView"></div> 
     8                <div data-dojo-attach-point="categoryListNode" class="rftLineListView"></div>
    99                <div data-dojo-attach-point="categoryBoxNode"></div>
    1010                <button class="inheritBgColor" data-dojo-type="dijit/form/Button" data-dojo-attach-event="onClick:_onCategoryAdd" data-dojo-props="baseClass:'rftBlockButton', iconClass: 'rftIcon rftIconPlus'">Add</button><br/>
  • Dev/trunk/src/client/qed-client/model/widgets/templates/SurveyRunWidget.html

    r508 r513  
    33    <div>
    44        <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>
     5        <div name="title" class="qedField"
     6             data-dojo-props="required: true"
     7             data-dojo-type="dijit/form/ValidationTextBox"></div>
    88    </div>
    99
    1010    <div>
    1111        <label for="mode" class="qedLabel">Description</label>
    12         <textarea name="description" class="qedField"
    13                   data-dojo-type="dijit/form/Textarea"></textarea>
     12        <div name="description" class="qedField"
     13             data-dojo-type="dijit/form/Textarea"></div>
    1414    </div>
    1515
    1616    <div>
    1717        <label for="startDate" class="qedLabel">Start date</label>
    18         <input type="text" name="startDate" class="qedField"
    19                data-dojo-type="dijit/form/DateTextBox"
    20                data-dojo-attach-point="startDateBox" />
     18        <div name="startDate" class="qedField"
     19             data-dojo-type="dijit/form/DateTextBox"
     20             data-dojo-attach-point="startDateBox"></div>
    2121    </div>
    2222
    2323    <div>
    2424        <label for="endDate" class="qedLabel">End date</label>
    25         <input type="text" name="endDate" class="qedField"
    26                data-dojo-type="dijit/form/DateTextBox"
    27                data-dojo-attach-point="endDateBox" />
     25        <div name="endDate" class="qedField"
     26             data-dojo-type="dijit/form/DateTextBox"
     27             data-dojo-attach-point="endDateBox"></div>
    2828    </div>
    2929
    3030    <div>
    3131        <label for="endDate" class="qedLabel">Allow respondents to delete their unsubmitted response</label>
    32         <input type="text" name="respondentCanDeleteOwnResponse"
    33                class="qedField"
    34                data-dojo-type="dijit/form/CheckBox" />
     32        <div type="text" name="respondentCanDeleteOwnResponse"
     33             class="qedField"
     34             data-dojo-type="dijit/form/CheckBox"></div>
    3535    </div>
    3636
    3737    <div>
    3838        <label for="mode" class="qedLabel">Mode</label>
    39         <select name="mode" class="qedField" data-dojo-type="dijit/form/Select">
     39        <div name="mode" class="qedField" data-dojo-type="dijit/form/Select">
    4040            <option value="open" selected="selected">Open</option>
    4141            <option value="closed">Closed</option>
    42         </select>
     42        </div>
    4343    </div>
    4444
  • Dev/trunk/src/client/qed-client/pages/templates/question.html

    r502 r513  
    3232        </div>
    3333    </div>
    34     <div data-dojo-type="../model/widgets/QuestionEditorPreview"
    35          data-dojo-attach-point="contentList"
    36          data-dojo-props="name:'content',delay:5,region:'center'"></div>
     34    <form data-dojo-type="../model/widgets/QuestionEditorPreview"
     35          data-dojo-attach-point="contentList"
     36          data-dojo-props="name:'content',delay:5,region:'center'"></form>
    3737</div>
  • Dev/trunk/src/client/qed-client/widgets/ListWidget.js

    r511 r513  
    11define([
    2     "dijit/_Container",
     2    "./_ComplexValueMixin",
    33    "dijit/_WidgetBase",
    44    "dijit/registry",
    55    "dojo/_base/array",
    66    "dojo/_base/declare",
     7    "dojo/_base/event",
    78    "dojo/_base/lang",
    89    "dojo/dnd/Source",
    910    "dojo/dnd/common",
    1011    "dojo/dom-construct",
    11     "dojo/_base/event",
    1212    "dojo/on"
    13 ], function(_Container, _WidgetBase, registry, array, declare, lang, Source, dnd, domConstruct, event, on) {
    14     return declare([_WidgetBase,_Container],{
    15         name: "",
    16         value: null,
    17         disabled: false,
    18         readOnly: false,
     13], function(_ComplexValueMixin, _WidgetBase, registry, array, declare, event, lang, Source, dnd, domConstruct, on) {
     14    return declare([_WidgetBase,_ComplexValueMixin],{
    1915        multiple: true,
    2016        type: "text",
     
    6561            this.own(this.source.on('Drop',
    6662                                    lang.hitch(this,'_handleDrop')));
    67             this.own(on(this.domNode,'change',
    68                         lang.hitch(this,'_handleChange')));
    69         },
    70         create: function() {
    71             this.inherited(arguments);
    72             this._onChangeActive = true;
    7363        },
    7464        creator: function(item, hint) {
     
    8373            } else {
    8474                if ( this.createListElement ) {
    85                     nodeOrWidget = this.createListElement(id,item,this._fromDrop);
     75                    nodeOrWidget =
     76                        this.createListElement(id,item,this._fromDrop);
    8677                } else {
    8778                    return this.source.defaultCreator(item, hint);
    8879                }
    8980            }
    90             var node = nodeOrWidget.domNode ? nodeOrWidget.domNode : nodeOrWidget;
     81            if ( nodeOrWidget.on ) {
     82                this.connectChildsChanges(nodeOrWidget);
     83            }
     84            var node = nodeOrWidget.domNode ?
     85                       nodeOrWidget.domNode :
     86                       nodeOrWidget;
    9187            if ( hint !== "avatar" && node.id !== id ) {
    9288                console.warn("Node id '%s' not equal to generated id '%s'. Is this intended?", node.id, id);
     
    10197        createListElement: null, /* function(id,item,fromDrop){},*/
    10298        _getValueAttr: function() {
    103             this.value = array.map(this.source.getAllNodes(),function(node){
    104                 var widget = registry.byNode(node);
    105                 if ( widget && "value" in widget ) {
    106                     return widget.get('value');
    107                 } else {
    108                     return this.source.getItem(node.id).data;
    109                 }
    110             },this);
    111             return this.value;
     99            return array.map(
     100                this._getDescendantFormWidgets(),
     101                function(child) { return child.get('value'); }
     102                ,this);
    112103        },
    113104        _setValueAttr: function(value,priorityChange) {
    114105            this.clear();
    115             this.appendItems(value || []);
     106            this._setValueInternal(value || [], priorityChange);
     107            this.appendItems(this.value);
    116108        },
    117         _setDisabledAttr: function(value) {
    118             this._set("disabled", value);
    119             array.forEach(this.getChildren(), function(child){
    120                 child.set("disabled", value);
    121             });
    122             this._updateContainer();
     109        _setReadOnlyAttr: function() {
     110            this.inherited(arguments);
     111            this._updateSource();
    123112        },
    124         _setReadOnlyAttr: function(value) {
    125             this._set("readOnly", value);
    126             array.forEach(this.getChildren(), function(child){
    127                 child.set("readOnly", value);
    128             });
    129             this._updateContainer();
     113        _setDisabledAttr: function() {
     114            this.inherited(arguments);
     115            this._updateSource();
    130116        },
    131         _updateContainer: function() {
     117        _updateSource: function() {
    132118            if ( this.disabled || this.readOnly ) {
    133119                this.source.accept = [];
     
    139125            }
    140126        },
    141         focus: function() {
    142             var children = this.getChildren();
    143             if ( children.length > 0 ) {
    144                 children[0].focus();
    145             }
     127        getChildren: function() {
     128            return array.filter(
     129                array.map(this.source.getAllNodes(), function(node){
     130                    return registry.byNode(node);
     131                }),
     132                function(widget){ return widget !== null; });
    146133        },
     134        _getDescendantFormWidgets: function() {
     135            return array.filter(
     136                this.getChildren(),
     137                function(child){ return 'value' in child; });
     138        },
     139
    147140        appendItems: function(items,forceEvent) {
    148141            this._fromDrop = false;
    149142            this.source.insertNodes(false,items);
    150             if ( forceEvent ) { this._handleDrop(); }
     143            this._setValueInternal(
     144                this.get('value'),
     145                forceEvent === true ? true : null);
    151146            this._fromDrop = true;
    152147        },
     
    154149            this._fromDrop = false;
    155150            this.source.insertNodes(false,[item]);
    156             if ( forceEvent ) { this._handleDrop(); }
     151            this._setValueInternal(
     152                this.get('value'),
     153                forceEvent === true ? true : null);
    157154            this._fromDrop = true;
    158155        },
    159156        removeItem: function(key,forceEvent) {
    160             array.forEach(array.filter(this.source.getAllNodes(), function(node){
    161                 return node.id === key;
    162             }), lang.hitch(this, "_destroyNodeOrWidget"));
     157            array.forEach(
     158                array.filter(this.source.getAllNodes(), function(node){
     159                    return node.id === key;
     160                }),
     161                lang.hitch(this, "_destroyNodeOrWidget"));
    163162            this.source.delItem(key);
    164             if ( forceEvent ) { this._handleDrop(); }
    165         },
    166         getChildren: function() {
    167             return array.filter(array.map(this.source.getAllNodes(), function(node){
    168                 return registry.byNode(node);
    169             }),function(widget){ return widget !== null; });
     163            this._setValueInternal(
     164                this.get('value'),
     165                forceEvent === true ? true : null);
    170166        },
    171167        clear: function(forceEvent) {
     
    173169                          lang.hitch(this, "_destroyNodeOrWidget"));
    174170            this.source.clearItems();
    175             if ( forceEvent ) { this._handleDrop(); }
     171            this._setValueInternal(
     172                this.get('value'),
     173                forceEvent === true ? true : null);
    176174        },
    177175        _destroyNodeOrWidget: function(node) {
     
    183181            }
    184182        },
    185         validate: function() {
    186             return array.every(array.map(this.source.getAllNodes(),function(node){
    187                 var widget = registry.byNode(node);
    188                 return !widget || widget.disabled || !widget.validate || widget.validate();
    189             }), function(item){ return item; });
    190         },
    191183        destroy: function() {
    192184            this.source.destroy();
    193185            this.inherited(arguments);
    194186        },
    195         _handleChange: function(evt) {
    196             if ( evt.target !== this.domNode ) {
    197                 this._onChange();
    198                 if ( evt ) { event.stop(evt); }
    199                 return false;
    200             } else {
    201                 return evt;
    202             }
    203         },
    204         _handleDrop: function(evt) {
    205             this._onChange();
    206         },
    207         _onChange: function() {
    208             if ( this._onChangeActive &&
    209                  !(this.readOnly || this.disabled) ) {
    210                 if ( this._onChangeHandle ) {
    211                     this._onChangeHandle.cancel();
    212                 }
    213                 this._onChangeHandle = this.defer(function(){
    214                     this._onChangeHandle = null;
    215                     on.emit(this.domNode,'change',{
    216                         target: this.domNode,
    217                         value: this.get('value'),
    218                         bubbles: true,
    219                         cancellable: true
    220                     });
    221                 });
    222             }
     187        _handleDrop: function() {
     188            this._setValueInternal(this.get('value'));
    223189        }
    224190    });
  • Dev/trunk/src/client/qed-client/widgets/ObjectBox.js

    r510 r513  
    22    "../lib/object",
    33    "./LineWithActionsWidget",
     4    "./_ComplexValueWidget",
    45    "dijit/_TemplatedMixin",
    56    "dijit/_WidgetBase",
     
    89    "dojo/_base/lang",
    910    "dojo/text!./templates/ObjectBox.html"
    10 ], function(objectFuns, LineWithActionsWidget, _TemplatedMixin, _WidgetBase, _WidgetsInTemplateMixin, declare, lang, template) {
    11     return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
     11], function(objectFuns, LineWithActionsWidget, _ComplexValueWidget, _TemplatedMixin, _WidgetBase, _WidgetsInTemplateMixin, declare, lang, template) {
     12    return declare([_ComplexValueWidget], {
    1213        baseClass: "rftObjectBox",
    1314        templateString: template,
    14         value: null,
    1515        actions: null,
    1616        startup: function() {
     
    5454        },
    5555        _showInfoBox: function() {},
    56         _setValueAttr: function(value) {
    57             this.value = value;
    58             this._refresh();
    59         },
    60         _getValueAttr: function(value) {
    61             this.value = value;
    62         },
    63         _refresh: function() {
    64             if ( this.value !== null ) {
    65                 this.iconNode.className = "rftIcon typeIcon rftIcon"+(this.value.type || '');
    66                 this.line1.set('title', this.value.title || '');
    67                 this.line2.set('title', this.value.subTitle || '');
    68                 this.line3.set('title', this.value.lowerTitle || '');
     56        onChange: function(value) {
     57            if ( value ) {
     58                this.iconNode.className = "rftIcon typeIcon rftIcon"+(value.type || '');
     59                this.line1.set('title', value.title || '');
     60                this.line2.set('title', value.subTitle || '');
     61                this.line3.set('title', value.lowerTitle || '');
    6962            }
    7063        }
  • Dev/trunk/src/client/qed-client/widgets/_ComplexValueMixin.js

    r512 r513  
    2020        },
    2121        buildRendering: function() {
    22             // capture child change events
     22            // capture child events
    2323            this.inherited(arguments);
    24             this.own(on(this.domNode,'change',
    25                         lang.hitch(this,'_handleChange')));
     24            if ( this.domNode.tagName.toLowerCase() !== "form" ) {
     25                console.warn("Not scoping a _ComplexValueMixin in a form element can cause name clashes. E.g. radio buttons might stop working correctly. It is recommended to use <form> as the root element in your template for", this.declaredClass);
     26            }
     27            this.own(on(this.domNode,'submit',
     28                        lang.hitch(this,'_handleSubmit')));
    2629        },
    2730        create: function() {
     
    3033        },
    3134        postCreate: function() {
    32             this.inherited(arguments);
    33             if ( this.domNode.tagName.toLowerCase() !== "form" ) {
    34                 console.warn("Not scoping a _ComplexValueMixin in a form element can cause name clashes. E.g. radio buttons might stop working correctly. It is recommended to use <form> as the root element in your template for", this.declaredClass);
    35             }
    36             this.own(on(this.domNode, 'submit', lang.hitch(this,'_handleSubmit')));
     35            array.forEach(this._getDescendantFormWidgets(),
     36                          this.connectChildsChanges,
     37                          this);
    3738        },
    38         startup: function() {
    39             if (this._started) { return; }
    40             this.inherited(arguments);
    41         },
    42         _setDisabledAttr: function(value) {
    43             this._set("disabled", value);
    44             array.forEach(this._getDescendantFormWidgets(), function(child) {
    45                 child.set("disabled", value);
    46             });
    47         },
    48         _getValueAttr: function() {
    49             this.value = this.inherited(arguments);
    50             return this.value;
     39        connectChildsChanges: function(child) {
     40            this.own(child.on('change',
     41                              lang.hitch(this,'_handleChildChange')));
    5142        },
    5243        // Yuk, _setValueAttr is taken directly from _FromMixin only
    5344        // to add the priorityChange parameter
    5445                _setValueAttr: function(obj, priorityChange) {
    55             this.value = obj;
     46            this._setValueInternal(obj, priorityChange);
    5647
    5748                        var map = { };
     
    8475                                }
    8576                        }
     77           
     78            if ( priorityChange !== null ) {
     79                this._handleOnChange(this.value);
     80            }
    8681                },
    87         _setReadOnlyAttr: function(value) {
    88             this._set("readOnly", value);
    89             array.forEach(this._getDescendantFormWidgets(), function(child) {
    90                 child.set("readOnly", value);
    91             });
     82        // use _setValueInternal instead of 'this.value = ?' or
     83        // 'this._set('value',?)' so proper events will be generated.
     84        _setValueInternal: function(value,priorityChange) {
     85            this._set('value',value);
     86            if ( priorityChange !== null ){
     87                this._handleOnChange(this.value);
     88            }
    9289        },
     90        _setDisabledAttr: function(disabled) {
     91            this.inherited(arguments);
     92            array.forEach(
     93                this._getDescendantFormWidgets(),
     94                function(child) {
     95                    child.set('disabled', disabled);
     96                },this);
     97        },
     98        _setReadOnlyAttr: function(readOnly) {
     99            this.inherited(arguments);
     100            array.forEach(
     101                this._getDescendantFormWidgets(),
     102                function(child) {
     103                    child.set('readOnly', readOnly);
     104                },this);
     105        },
     106
    93107        focus: function() {
    94108            /*var children = this._getDescendantFormWidgets();
     
    97111            }*/
    98112        },
    99         _handleChange: function(evt) {
    100             if ( evt.target !== this.domNode ) {
    101                 this.triggerOnChange();
    102                 if ( evt ) { event.stop(evt); }
    103                 return false;
    104             } else {
    105                 return evt;
    106             }
     113        addChild: function(child) {
     114            this.inherited(arguments);
     115            this.connectChildsChanges(child);
    107116        },
     117
    108118        _handleSubmit: function(evt) {
    109             var node = this.domNode;
    110             var widget;
    111             while ( node ) {
    112                 node = node.parentNode;
    113                 widget = registry.byNode(node);
    114                 if ( widget && typeof widget._onSubmit === "function" ) {
    115                     widget._onSubmit(evt);
    116                     break;
     119            if ( this._started ) {
     120                var node = this.domNode;
     121                var widget;
     122                while ( node ) {
     123                    node = node.parentNode;
     124                    widget = registry.byNode(node);
     125                    if ( widget &&
     126                         typeof widget._onSubmit === "function" ) {
     127                        widget._onSubmit(evt);
     128                        break;
     129                    }
    117130                }
    118131            }
     
    120133            return false;
    121134        },
    122         triggerOnChange: function() {
     135        _handleChildChange: function() {
     136            this._setValueInternal(this.get('value'));
     137            return false;
     138        },
     139        _handleOnChange: function(value) {
    123140            if ( this._onChangeActive &&
    124141                 !(this.readOnly || this.disabled) ) {
    125142                if ( this._onChangeHandle ) {
    126                     this._onChangeHandle.cancel();
     143                    this._onChangeHandle.remove();
    127144                }
    128145                this._onChangeHandle = this.defer(function(){
    129146                    this._onChangeHandle = null;
    130                     on.emit(this.domNode,'change',{
    131                         target: this.domNode,
    132                         value: this.get('value'),
    133                         bubbles: true,
    134                         cancellable: true
    135                     });
     147                    this.onChange(value);
    136148                });
    137149            }
    138         }
     150        },
     151        onChange: function() {}
    139152    });
    140153});
Note: See TracChangeset for help on using the changeset viewer.