Changeset 1369

Show
Ignore:
Timestamp:
16/11/09 10:29:39 (4 months ago)
Author:
karel
Message:

Autocomplete kauri control

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/modules/kauri-forms/kauri-forms-extra/src/main/kauri/static/autocomplete/js/autocomplete.js

    r1368 r1369  
    33(function($) { 
    44 
    5   //TODO: implement autocomplete control 
     5    if (!$) 
     6        throw "Kauri Forms AutocompleteControl requires jQuery"; 
     7    if (!$.org.kauriproject.forms) 
     8        throw "Kauri Forms AutocompleteControl requires the kauri-form namespace"; 
    69 
    7 //    if (!$) 
    8 //        throw "Kauri Forms DoubleSelectControl requires jQuery"; 
    9 //    if (!$.org.kauriproject.forms) 
    10 //        throw "Kauri Forms DoubleSelectControl requires the kauri-form namespace"; 
    11 // 
    12 //    var kp = $.org.kauriproject; 
    13 //    var kf = $.org.kauriproject.forms; 
    14 // 
    15 //    kf.controlTypes.put("dblselect-control", DoubleSelectControl); 
    16 // 
    17 //    $.inherit(DoubleSelectControl, kf.Control); 
    18 // 
    19 //    function DoubleSelectControl(id, form, conf) { 
    20 //        this['<super.init>'](id, form, conf); 
    21 // 
    22 //        this.availableOptions = { 
    23 //            userValues: [], 
    24 //            labels: [] 
    25 //        } 
    26 //    } 
    27 // 
    28 //    DoubleSelectControl.prototype.elements = {}; 
    29 //    $.extend(DoubleSelectControl.prototype.elements, kf.Control.prototype.elements); 
    30 //    $.extend(DoubleSelectControl.prototype.elements, { 
    31 //        input : { 
    32 //            /* Kauri Forms needs an input-role element, but we don't, therefore 
    33 //               simply create a hidden div. */ 
    34 //            create : "<div style='display:none'/>" 
    35 //        }, 
    36 //        available : { 
    37 //            create : "<select size='5' multiple='multiple'/>" 
    38 //        }, 
    39 //        selected : { 
    40 //            create : "<select size='5' multiple='multiple'/>" 
    41 //        }, 
    42 //        add : { 
    43 //            create: "<button>></button>" 
    44 //        }, 
    45 //        remove : { 
    46 //            create: "<button>&lt;</button>" 
    47 //        } 
    48 //    }); 
    49 // 
    50 //    DoubleSelectControl.prototype.initType = function(conf) { 
    51 //        this["<super.call>"]("initType", [conf]); 
    52 //        // Force the field type to being multivalue 
    53 //        this.getType().multivalue = true; 
    54 //    } 
    55 // 
    56 //    DoubleSelectControl.prototype.initElements = function(create) { 
    57 //        $available = kf.ControlElements.lookup(this, "available", true); 
    58 //        $add = kf.ControlElements.lookup(this, "add", true); 
    59 //        $remove = kf.ControlElements.lookup(this, "remove", true); 
    60 //        $selected = kf.ControlElements.lookup(this, "selected", true); 
    61 //        $addAll = kf.ControlElements.lookup(this, "addAll", false); 
    62 //        $removeAll = kf.ControlElements.lookup(this, "removeAll", false); 
    63 //        $other = kf.ControlElements.lookup(this, "other", false); 
    64 //        $addOther = kf.ControlElements.lookup(this, "addOther", false); 
    65 // 
    66 //        var me = this; 
    67 // 
    68 //        $add.click(function(event) { 
    69 //            event.preventDefault(); 
    70 //            event.stopPropagation(); 
    71 //            me.handleAdd(); 
    72 //        }); 
    73 // 
    74 //        $available.keypress(function(event) { 
    75 //            // Ctrl + key right 
    76 //            if (event.ctrlKey && event.keyCode == 39) { 
    77 //                me.handleAdd(); 
    78 //            } 
    79 //        }); 
    80 // 
    81 //        $available.dblclick(function() { 
    82 //            me.handleAdd(); 
    83 //        }); 
    84 // 
    85 //        $remove.click(function(event) { 
    86 //            event.preventDefault(); 
    87 //            event.stopPropagation(); 
    88 //            me.handleRemove(); 
    89 //        }); 
    90 // 
    91 //        $selected.keypress(function(event) { 
    92 //            // Ctrl + key left 
    93 //            if (event.ctrlKey && event.keyCode == 37) { 
    94 //                me.handleRemove(); 
    95 //            } else if (event.keyCode == 46) { 
    96 //                // delete key 
    97 //                me.handleRemove(); 
    98 //            } 
    99 //        }) 
    100 // 
    101 //        $selected.dblclick(function() { 
    102 //            me.handleRemove(); 
    103 //        }); 
    104 // 
    105 //        if ($addAll) { 
    106 //            $addAll.click(function(event) { 
    107 //                event.preventDefault(); 
    108 //                event.stopPropagation(); 
    109 //                me.handleAddAll(); 
    110 //            }); 
    111 //        } 
    112 // 
    113 //        if ($removeAll) { 
    114 //            $removeAll.click(function(event) { 
    115 //                event.preventDefault(); 
    116 //                event.stopPropagation(); 
    117 //                me.handleRemoveAll(); 
    118 //            }); 
    119 //        } 
    120 // 
    121 //        $available.change(function() { 
    122 //            me.refreshButtonsState(); 
    123 //        }); 
    124 // 
    125 //        $selected.change(function() { 
    126 //            me.refreshButtonsState(); 
    127 //        }); 
    128 // 
    129 //        if ($other && $addOther) { 
    130 //            $addOther.click(function(event) { 
    131 //                event.preventDefault(); 
    132 //                event.stopPropagation(); 
    133 //                me.handleAddOther(); 
    134 //            }); 
    135 // 
    136 //            $other.keypress(function(event) { 
    137 //                if (event.keyCode == 13) { 
    138 //                    event.preventDefault(); 
    139 //                    event.stopPropagation(); 
    140 //                    me.handleAddOther(); 
    141 //                } 
    142 //            }) 
    143 // 
    144 //            $other.keyup(function(event) { 
    145 //                me.refreshAddOtherButtonState(); 
    146 //            }); 
    147 //        } 
    148 // 
    149 //        this.valueChanged(function() { 
     10    var kp = $.org.kauriproject; 
     11    var kf = $.org.kauriproject.forms; 
     12 
     13    kf.controlTypes.put("autocomplete-control", AutocompleteControl); 
     14 
     15    $.inherit(AutocompleteControl, kf.Control); 
     16 
     17    function AutocompleteControl(id, form, conf) { 
     18        this['<super.init>'](id, form, conf); 
     19         
     20        this.availableOptions = { 
     21            userValues: [], 
     22            labels: [] 
     23        } 
     24    } 
     25 
     26    AutocompleteControl.prototype.elements = {}; 
     27    $.extend(AutocompleteControl.prototype.elements, kf.Control.prototype.elements); 
     28    $.extend(AutocompleteControl.prototype.elements, { 
     29        input : { 
     30            /* Kauri Forms needs an input-role element, but we don't, therefore 
     31               simply create a hidden div. */ 
     32            create : "<div style='display:none'/>" 
     33        }, 
     34        acinput : { 
     35            create : "<input type='text'/>" 
     36        } 
     37    }); 
     38 
     39    AutocompleteControl.prototype.initType = function(conf) { 
     40        this["<super.call>"]("initType", [conf]); 
     41         
     42    } 
     43 
     44    AutocompleteControl.prototype.initElements = function(create) { 
     45        $acinput = kf.ControlElements.lookup(this, "acinput", true); 
     46 
     47        var me = this; 
     48         
     49        var inputTemplate = new kp.UriTemplate("{email}"); 
     50        var listTemplate  = new kp.UriTemplate("{id} - {email})"); 
     51        var valueTemplate = new kp.UriTemplate("{id}"); 
     52         
     53        $acinput.autocomplete(this.options.dataUri, { 
     54          dataType: "json",  
     55          parse: function(data) { 
     56            var parsed = []; 
     57            for (var i=0;i<data.length;i++) { 
     58              parsed.push({ data: data[i], value: valueTemplate.expand(data[i], true), result: inputTemplate.expand(data[i], true)}); 
     59            } 
     60            return parsed; 
     61          }, 
     62          formatItem: function(data, current, last) { 
     63            return listTemplate.expand(data, true); 
     64          } 
     65        }).bind("result", function(event, objData, valueData) { 
     66          alert('You selected ' + valueData); 
     67        }); 
     68         
     69        this.valueChanged(function() { 
    15070//            me.refreshSelectedSelect(); 
    151 //            me.refreshAvailableSelect(); 
    152 //            me.refreshButtonsState(); 
    153 //        }); 
    154 // 
     71        }); 
     72 
    15573//        this.refreshAvailableSelect(); 
    156 //        this.refreshButtonsState(); 
    157 //        this.refreshAddOtherButtonState(); 
    158 //    } 
    159 // 
    160 //    DoubleSelectControl.prototype.getUserValue = function() { 
    161 //        // Not needed, should never be called 
    162 //    } 
    163 // 
    164 //    DoubleSelectControl.prototype.setUserValue = function(value) { 
    165 //        // Not needed, should never be called 
    166 //    } 
    167 // 
    168 //    DoubleSelectControl.prototype.getUpdateElement = function() { 
    169 //        // There is no 'change' event to react to 
    170 //        return undefined; 
    171 //    } 
    172 // 
    173 //    DoubleSelectControl.prototype.updateOptions = function(userValues, labels) { 
    174 //        // This callback might be called before initElements() is complete, therefore 
    175 //        // the check if the 'available' binding does already exist. 
    176 //        var $available = this.getElement("available"); 
    177 //        if ($available) { 
    178 //            this.refreshAvailableSelect(); 
    179 //            this.refreshSelectedSelect(); 
    180 //            this.refreshButtonsState(); 
    181 //        } 
    182 //    } 
    183 // 
    184 //    DoubleSelectControl.prototype.refreshButtonsState = function() { 
    185 //        var $available = this.getElement("available"); 
    186 //        var $selected = this.getElement("selected"); 
    187 // 
    188 //        var buttons = [ 
    189 //            {role: "add", enabled: $available.val() !== null}, 
    190 //            {role: "addAll", enabled: $available[0].options.length > 0}, 
    191 //            {role: "remove", enabled: $selected.val() !== null}, 
    192 //            {role: "removeAll", enabled: $selected[0].options.length > 0} 
    193 //        ] 
    194 // 
    195 //        for (var i = 0; i < buttons.length; i++) { 
    196 //            var $el = this.getElement(buttons[i].role); 
    197 //            if ($el) { 
    198 //                $el.attr("disabled", !buttons[i].enabled); 
    199 //            } 
    200 //        } 
    201 //    } 
    202 // 
    203 //    DoubleSelectControl.prototype.refreshAddOtherButtonState = function() { 
    204 //        var $other = this.getElement("other"); 
    205 //        var $addOther = this.getElement("addOther"); 
    206 // 
    207 //        if ($other && $addOther) { 
    208 //            $addOther.attr('disabled', $.isEmpty($other.val())); 
    209 //        } 
    210 //    } 
    211 // 
    212 //    DoubleSelectControl.prototype.refreshAvailableSelect = function() { 
    213 //        var options = this.options || {}; 
    214 //        var values = options.values || []; 
    215 //        var userValues = options.userValues || []; 
    216 //        var labels = options.labels || userValues; 
    217 // 
    218 //        var $available = this.getElement("available"); 
    219 //        var availableSelect = $available[0]; 
    220 // 
    221 //        var selectOptions = availableSelect.options; 
    222 //        var prevSelectedIndex = selectOptions.selectedIndex; 
    223 //        selectOptions.length = 0; 
    224 // 
    225 //        var controlValue = this.getValue(); 
    226 // 
    227 //        var last = values.length; 
    228 //        for (var i = 0; i < last; i++) { 
    229 //            var isSelectedValue = false; 
    230 //            if (controlValue) { 
    231 //                // TODO make this more efficient? 
    232 //                for (var j = 0; j < controlValue.length; j++) { 
    233 //                    if ($.valueCompare(values[i], controlValue[j])) { 
    234 //                        isSelectedValue = true; 
    235 //                        break; 
    236 //                    } 
    237 //                } 
    238 //            } 
    239 // 
    240 //            if (!isSelectedValue) { 
    241 //                availableSelect.options[availableSelect.options.length] = new Option(labels[i], userValues[i]) 
    242 //            } 
    243 //        } 
    244 // 
    245 //        if (prevSelectedIndex >= 0) { 
    246 //            prevSelectedIndex = prevSelectedIndex >= selectOptions.length ? selectOptions.length - 1 : prevSelectedIndex; 
    247 //            availableSelect.options.selectedIndex = prevSelectedIndex; 
    248 //        } 
    249 //    } 
    250 // 
    251 //    DoubleSelectControl.prototype.refreshSelectedSelect = function() { 
    252 //        var $selected = this.getElement("selected"); 
    253 //        var selectedSelect = $selected[0]; 
    254 // 
    255 //        var selectOptions = selectedSelect.options; 
    256 //        var prevSelectedIndex = selectOptions.selectedIndex; 
    257 //        selectOptions.length = 0; 
    258 // 
    259 //        var values = this.getValue(); 
    260 //        if (!values) 
    261 //            return; 
    262 // 
    263 //        for (var i = 0; i < values.length; i++) { 
    264 //            var userValue = this.getType().toUserValue(values[i]); 
    265 //            var label = this.getLabel(userValue); 
    266 //            selectedSelect.options[selectedSelect.options.length] = new Option(label, userValue); 
    267 //        } 
    268 // 
    269 //        if (prevSelectedIndex >= 0) { 
    270 //            prevSelectedIndex = prevSelectedIndex >= selectOptions.length ? selectOptions.length - 1 : prevSelectedIndex; 
    271 //            selectedSelect.options.selectedIndex = prevSelectedIndex; 
    272 //        } 
    273 //    } 
    274 // 
    275 //    DoubleSelectControl.prototype.getLabel = function(userValue) { 
    276 //        var options = this.options || {}; 
    277 //        var userValues = options.userValues || []; 
    278 //        var labels = options.labels; 
    279 // 
    280 //        if (!labels) { 
    281 //            return userValue; 
    282 //        } 
    283 // 
    284 //        // TODO maybe we need hash-based lookup for performance? 
    285 //        for (var i = 0; i < userValues.length; i++) { 
    286 //            if ($.valueCompare(userValues[i], userValue)) { 
    287 //                var label = labels[i]; 
    288 //                return label || userValue; 
    289 //            } 
    290 //        } 
    291 // 
    292 //        return userValue; 
    293 //    } 
    294 // 
    295 //    /** 
    296 //     * Adds the value entered into the 'other' input to the list 
    297 //     * of selected values. 
    298 //     */ 
    299 //    DoubleSelectControl.prototype.handleAddOther = function() { 
    300 //        var value = this.getValue(); 
    301 //        var $other = this.getElement("other"); 
    302 //        var other = $other.val(); 
    303 // 
    304 //        if ($.isEmpty(other)) { 
    305 //            return; 
    306 //        } 
    307 // 
    308 //        try { 
    309 //            other = this.getType().parseUserValue(other); 
    310 //        } catch (e) { 
    311 //            var text = $.isFunction(e.getText) ? e.getText() : "Formatting error " + e; 
    312 //            alert(text); 
    313 //            return; 
    314 //        } 
    315 // 
    316 //        if (!value) { 
    317 //            value = []; 
    318 //        } 
    319 // 
    320 //        // Check that the value is not already among the selected values. 
    321 //        for (var i = 0; i < value.length; i++) { 
    322 //            if ($.valueCompare(value[i], other)) { 
    323 //                // TODO i18n 
    324 //                alert("This value is already in the list"); 
    325 //                return; 
    326 //            } 
    327 //        } 
    328 // 
    329 //        this.setValue([].concat(value, other)); 
    330 //        $other.val(""); 
    331 //        this.refreshAddOtherButtonState(); 
    332 //    } 
    333 // 
    334 //    DoubleSelectControl.prototype.handleAdd = function() { 
    335 //        var $available = this.getElement("available"); 
    336 // 
    337 //        var selectedValues = []; 
    338 //        var options = $available[0].options; 
    339 //        for (var i = 0; i < options.length; i++) { 
    340 //            if (options[i].selected) { 
    341 //                selectedValues.push(this.getType().parseUserValue(options[i].value)); 
    342 //            } 
    343 //        } 
    344 // 
    345 //        var values = this.getValue(); 
    346 //        if (!values) { 
    347 //            values = selectedValues; 
    348 //        } else { 
    349 //            values = values.concat(selectedValues); 
    350 //        } 
    351 // 
    352 //        this.setValue(values); 
    353 //    } 
    354 // 
    355 //    DoubleSelectControl.prototype.handleAddAll = function() { 
    356 //        // Note that we don't simply set the value to the complete list of option 
    357 //        // values, as to avoid that any custom-entered values would be lost 
    358 // 
    359 //        var $available = this.getElement("available"); 
    360 // 
    361 //        var selectedValues = []; 
    362 //        var options = $available[0].options; 
    363 //        for (var i = 0; i < options.length; i++) { 
    364 //            selectedValues.push(this.getType().parseUserValue(options[i].value)); 
    365 //        } 
    366 // 
    367 //        var values = this.getValue(); 
    368 //        if (!values) { 
    369 //            values = selectedValues; 
    370 //        } else { 
    371 //            values = [].concat(values, selectedValues); 
    372 //        } 
    373 // 
    374 //        this.setValue(values); 
    375 //    } 
    376 // 
    377 //    DoubleSelectControl.prototype.handleRemove = function() { 
    378 //        var $selected = this.getElement("selected"); 
    379 // 
    380 //        var values = this.getValue(); 
    381 //        if (!values) { 
    382 //            // nothing useful can have happened 
    383 //            return; 
    384 //        } 
    385 // 
    386 //        // make sure we don't modify the original array 
    387 //        values = [].concat(values); 
    388 // 
    389 //        var options = $selected[0].options; 
    390 //        for (var i = options.length - 1; i >= 0; i--) { 
    391 //            if (options[i].selected) { 
    392 //                values.splice(i, 1) 
    393 //            } 
    394 //        } 
    395 // 
    396 //        this.setValue(values); 
    397 //    } 
    398 // 
    399 //    DoubleSelectControl.prototype.handleRemoveAll = function() { 
    400 //        this.setValue(undefined); 
    401 //    } 
    402 // 
    403 //    DoubleSelectControl.prototype.setValue = function(value) { 
    404 //        if (value && value.constructor == Array) { 
    405 //            // TODO this sort is always alphabetically, let the field type provide an order function? 
    406 //            // TODO consider sorting on the labels (if any) rather than the value? 
    407 //            value.sort() 
    408 //        } 
    409 //        this["<super.call>"]("setValue", [value]); 
    410 //    } 
     74    } 
     75 
     76    AutocompleteControl.prototype.getUserValue = function() { 
     77        // Not needed, should never be called 
     78    } 
     79 
     80    AutocompleteControl.prototype.setUserValue = function(value) { 
     81        // Not needed, should never be called 
     82    } 
     83 
     84    AutocompleteControl.prototype.getUpdateElement = function() { 
     85        // There is no 'change' event to react to 
     86        return undefined; 
     87    } 
     88 
     89    AutocompleteControl.prototype.setValue = function(value) { 
     90        // FIXME: implement? 
     91        this["<super.call>"]("setValue", [value]); 
     92    } 
    41193 
    41294})(jQuery); 
  • trunk/samples/kauri-forms-sample/src/main/kauri/pages/autocomplete-control.html.xml

    r1368 r1369  
    1717                  "label": "Select a contact", 
    1818                  "control": { 
    19                       "base": "selection-control", 
     19                      "base": "autocomplete-control", 
    2020                      "options": { 
    21                           "uri": "${publicUri('service:/data/contact/')}", 
     21                          "dataUri": "${publicUri('service:/data/contact/')}", 
    2222                          "valueTemplate": "{id}", 
    2323                          "labelTemplate": "{name}", 
    24                           "nullable": true, 
    25                           "null-text": "--- please select ---" 
     24                          "nullable": true 
    2625                      } 
    2726                  } 
     
    4140        <h2>Autocomplete control</h2> 
    4241 
    43         <dl
    44           <dt><label kauri-idref="contact" kauri-role="label"/></dt> 
    45           <dd><select kauri-idref="contact"/></dd> 
     42        <dl kauri-idref="contact"
     43          <dt><label kauri-role="label"/></dt> 
     44          <dd><input type="text" kauri-role="acinput"/></dd> 
    4645        </dl> 
    4746 
    4847      </fieldset> 
    4948    </form> 
    50      
     49 
     50<!--      
    5151    <h3>jquery (no control)</h3> 
    5252     
     
    7474      }).bind("result", function(event, objData, valueData) { 
    7575        alert('You selected ' + valueData); 
    76       });; 
     76      }); 
    7777    }); 
    7878    </script> 
     79 --> 
    7980  </t:block> 
    8081