Mercurial > hg > dml-open-vis
comparison src/DML/MainVisBundle/Resources/assets/marionette/modules/MainRegionModule/MainRegionModule.50-cgpma.textfield.js @ 0:493bcb69166c
added public content
| author | Daniel Wolff |
|---|---|
| date | Tue, 09 Feb 2016 20:54:02 +0100 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:493bcb69166c |
|---|---|
| 1 "use strict"; | |
| 2 | |
| 3 (function($) { | |
| 4 $.widget("cgpma.textfield", { | |
| 5 | |
| 6 options: { | |
| 7 value: "", | |
| 8 baseValue: "", | |
| 9 autocompleteMaxItemCount: 15, | |
| 10 autocompleteSort: false, | |
| 11 autocompleteSuggestions: null, | |
| 12 autocompleteIsAdvisory: false, | |
| 13 autocompleteCSSClasses: "" | |
| 14 }, | |
| 15 | |
| 16 isFocused: function() { | |
| 17 var widget = this; | |
| 18 return widget.$input.is(":focus"); | |
| 19 }, | |
| 20 | |
| 21 focus: function() { | |
| 22 var widget = this; | |
| 23 return widget.$input.focus(); | |
| 24 }, | |
| 25 | |
| 26 getTextRange: function() { | |
| 27 var widget = this; | |
| 28 return widget.$input.textrange(); | |
| 29 }, | |
| 30 | |
| 31 setTextRange: function(textRange) { | |
| 32 var widget = this; | |
| 33 if (textRange.start != textRange.end) { | |
| 34 return widget.$input.textrange("set", textRange.start, textRange.end); | |
| 35 } | |
| 36 return widget.$input.textrange("setcursor", textRange.position); | |
| 37 }, | |
| 38 | |
| 39 _create : function() { | |
| 40 var widget = this; | |
| 41 widget.$element = this.element; | |
| 42 widget.$input = $.bem.generateElement("input", "cgpma", "textfield-input"); | |
| 43 widget.$input.appendTo(widget.$element); | |
| 44 | |
| 45 widget.$input.data("widget", widget); | |
| 46 | |
| 47 widget._applyAutocompleteSuggestions(); | |
| 48 | |
| 49 widget.$input.bind("input", widget.__handleInputChange); | |
| 50 widget.$input.bind("keydown", widget.__handleInputKeyDown); | |
| 51 widget.$input.bind("keyup", widget.__handleInputKeyUp); | |
| 52 widget.$input.bind("click", widget.__handleInputClick); | |
| 53 | |
| 54 }, | |
| 55 | |
| 56 _applyAutocompleteSuggestions: function() { | |
| 57 var widget = this; | |
| 58 | |
| 59 if (widget.$input.data("ui-autocomplete")) { | |
| 60 widget.$input.autocomplete("destroy"); | |
| 61 } | |
| 62 | |
| 63 var autocompleteSuggestions = widget.options.autocompleteSuggestions; | |
| 64 if (!autocompleteSuggestions) { | |
| 65 return; | |
| 66 delete widget._invertedAutocompleteSuggestions; | |
| 67 } | |
| 68 widget._invertedAutocompleteSuggestions = _.invert(autocompleteSuggestions); | |
| 69 | |
| 70 widget.$input.autocomplete({ | |
| 71 delay : 0, | |
| 72 minLength : 0, | |
| 73 source : $.proxy(widget, "_autocompleteSource") | |
| 74 }); | |
| 75 | |
| 76 widget.$input.autocomplete( | |
| 77 "widget").addClass(widget.options.autocompleteCSSClasses); | |
| 78 | |
| 79 widget._on(widget.$input, { | |
| 80 autocompleteselect : widget.__handleInputChange, | |
| 81 autocompleteopen : widget.__handleAutocompleteOpen, | |
| 82 autocompleteclose : widget.__handleAutocompleteClose, | |
| 83 //autocompletechange : widget.__handleInputChange | |
| 84 }); | |
| 85 }, | |
| 86 | |
| 87 _autocompleteSource: function(request, response) { | |
| 88 var widget = this; | |
| 89 | |
| 90 var matcher = new RegExp($.ui.autocomplete | |
| 91 .escapeRegex(_.str.trim(request.term)), "i"); | |
| 92 | |
| 93 var responseItems = []; | |
| 94 _.each(widget.options.autocompleteSuggestions, function(kindName, kind) { | |
| 95 if (widget.options.autocompleteAlwaysFull || !request.term || matcher.test(kindName)) { | |
| 96 responseItems.push({ | |
| 97 label : kindName, | |
| 98 value : kindName, | |
| 99 }); | |
| 100 }; | |
| 101 }); | |
| 102 | |
| 103 if (responseItems.length == 1 && responseItems[0].label === request.term) { | |
| 104 responseItems = []; | |
| 105 } | |
| 106 if (responseItems.length > widget.options.autocompleteMaxItemCount) { | |
| 107 responseItems = responseItems.slice(0, widget.options.autocompleteMaxItemCount); | |
| 108 } | |
| 109 if (widget.options.autocompleteSort) { | |
| 110 responseItems = _.sortBy(responseItems, "label"); | |
| 111 } | |
| 112 | |
| 113 response(responseItems); | |
| 114 }, | |
| 115 | |
| 116 _createShowAllButton : function() { | |
| 117 return; | |
| 118 var input = this.input, wasOpen = false; | |
| 119 $("<a>").attr("tabIndex", -1).attr("title", | |
| 120 "Show All Items").tooltip().appendTo( | |
| 121 this.wrapper).button({ | |
| 122 icons : { | |
| 123 primary : "ui-icon-triangle-1-s" | |
| 124 }, | |
| 125 text : false | |
| 126 }).removeClass("ui-corner-all").addClass( | |
| 127 "custom-combobox-toggle ui-corner-right") | |
| 128 .mousedown( | |
| 129 function() { | |
| 130 wasOpen = input.autocomplete( | |
| 131 "widget") | |
| 132 .is(":visible"); | |
| 133 }).click(function() { | |
| 134 input.focus(); | |
| 135 // Close if already visible | |
| 136 if (wasOpen) { | |
| 137 return; | |
| 138 } | |
| 139 // Pass empty string as value to search | |
| 140 // for, displaying all results | |
| 141 input.autocomplete("search", ""); | |
| 142 }); | |
| 143 }, | |
| 144 | |
| 145 _isAutocompleteVisible : function() { | |
| 146 var widget = this; | |
| 147 if (widget.$input.data("ui-autocomplete")) { | |
| 148 return widget.$input.autocomplete("widget").is(":visible"); | |
| 149 } else { | |
| 150 return false; | |
| 151 } | |
| 152 }, | |
| 153 | |
| 154 _destroy : function() { | |
| 155 this.$input.removeData(); | |
| 156 }, | |
| 157 | |
| 158 _setOption: function (key, value) { | |
| 159 var widget = this; | |
| 160 | |
| 161 // Check if such option exists, throw an error if not | |
| 162 if (!widget.options.hasOwnProperty(key)) { | |
| 163 throw "Option " + key + " does not exist"; | |
| 164 } | |
| 165 | |
| 166 // Check if value matches what it was, do nothing if yes | |
| 167 if (value === widget.options[key] || (_.isArray(value) && _.isEqual(value, widget.options[key]))) { | |
| 168 return; | |
| 169 } | |
| 170 | |
| 171 // Save old option value | |
| 172 var prev = widget.options[key]; | |
| 173 | |
| 174 // Apply the option | |
| 175 this._super(key, value); | |
| 176 | |
| 177 // Call corresponding update method depending on the option key | |
| 178 switch (key) { | |
| 179 | |
| 180 case "value": | |
| 181 this._applyValue(); | |
| 182 break; | |
| 183 | |
| 184 case "baseValue": | |
| 185 this._updateStatus(); | |
| 186 break; | |
| 187 | |
| 188 case "autocompleteSuggestions": | |
| 189 this._applyAutocompleteSuggestions(); | |
| 190 break; | |
| 191 } | |
| 192 widget._trigger("change" + key.toLowerCase(), null, {newValue: value, prevValue: prev}); | |
| 193 }, | |
| 194 | |
| 195 _realValueToInputValue: function(realValue) { | |
| 196 var widget = this; | |
| 197 | |
| 198 var value = realValue; | |
| 199 var valueInOptionsIsString = _.isString(value); | |
| 200 var trimmedValueInOptions = valueInOptionsIsString ? _.str.trim(value) : value; | |
| 201 var trimmedCharsOnLeft = valueInOptionsIsString ? value.indexOf(trimmedValueInOptions) : null; | |
| 202 var trimmedCharsOnRight = valueInOptionsIsString ? value.length - trimmedValueInOptions.length - trimmedCharsOnLeft : null; | |
| 203 | |
| 204 if (valueInOptionsIsString && widget.options.autocompleteSuggestions && widget.options.autocompleteSuggestions[trimmedValueInOptions] !== undefined) { | |
| 205 value = value.substring(0, trimmedCharsOnLeft) + widget.options.autocompleteSuggestions[trimmedValueInOptions] + value.substring(value.length - trimmedCharsOnRight); | |
| 206 } | |
| 207 if (valueInOptionsIsString && value.length >= 4 && value.substring(0, 2) == "__" && value.substring(value.length - 2) == "__") { | |
| 208 value = value.substring(2, value.length - 2); | |
| 209 } | |
| 210 | |
| 211 return value; | |
| 212 | |
| 213 }, | |
| 214 | |
| 215 _inputValueToRealValue: function(inputValue) { | |
| 216 var widget = this; | |
| 217 | |
| 218 var value = inputValue; | |
| 219 var trimmedValueInInput = _.str.trim(value); | |
| 220 var trimmedCharsOnLeft = value.indexOf(trimmedValueInInput); | |
| 221 var trimmedCharsOnRight = value.length - trimmedValueInInput.length - trimmedCharsOnLeft; | |
| 222 | |
| 223 if (widget.options.autocompleteSuggestions && widget.options.autocompleteSuggestions[trimmedValueInInput] && widget.options.autocompleteSuggestions[trimmedValueInInput] !== trimmedValueInInput) { | |
| 224 value = "__" + value + "__"; | |
| 225 } | |
| 226 if (widget._invertedAutocompleteSuggestions && widget._invertedAutocompleteSuggestions[trimmedValueInInput] !== undefined) { | |
| 227 value = value.substring(0, trimmedCharsOnLeft) + widget._invertedAutocompleteSuggestions[trimmedValueInInput] + value.substring(value.length - trimmedCharsOnRight); | |
| 228 } | |
| 229 | |
| 230 return value; | |
| 231 }, | |
| 232 | |
| 233 _applyValue: function() { | |
| 234 var widget = this; | |
| 235 | |
| 236 var inputValue = widget._realValueToInputValue(widget.options.value); | |
| 237 | |
| 238 if (inputValue !== widget.$input.val() && !widget._doNotUpdateInputOnValueChange) { | |
| 239 widget.$input.val(inputValue); | |
| 240 } | |
| 241 widget._updateStatus(); | |
| 242 }, | |
| 243 | |
| 244 _updateStatus: function() { | |
| 245 var widget = this; | |
| 246 widget.$element.toggleClass("cgpma__textfield_status_modified", widget.options.baseValue !== widget.options.value); | |
| 247 }, | |
| 248 | |
| 249 __handleInputChange: function() { | |
| 250 | |
| 251 // this can be an instance of the widget or the DOM node | |
| 252 var $input = null; | |
| 253 if (this.element) { | |
| 254 $input = this.$input; | |
| 255 } else { | |
| 256 $input = $(this); | |
| 257 } | |
| 258 var widget = $input.data("widget"); | |
| 259 var valueInInput = $input.val(); | |
| 260 | |
| 261 if (arguments[1] && arguments[1].item) { | |
| 262 valueInInput = arguments[1].item.value; | |
| 263 } | |
| 264 | |
| 265 var realValue = widget._inputValueToRealValue(valueInInput); | |
| 266 | |
| 267 widget._setOption("value", realValue); | |
| 268 }, | |
| 269 | |
| 270 __handleInputKeyDown: function(event) { | |
| 271 var $this = $(this); | |
| 272 var widget = $this.data("widget"); | |
| 273 if (event.keyCode == 13) { | |
| 274 //widget._lastInputChangeWasCausedByAutocomplete = widget.$nput.autocomplete("widget").is(":visible"); | |
| 275 } | |
| 276 if (event.keyCode == 38 || event.keyCode == 40) { // up or down | |
| 277 if (widget.$input.data("ui-autocomplete")) { | |
| 278 if (!widget._isAutocompleteVisible()) { | |
| 279 widget.$input.autocomplete("search", ""); | |
| 280 } else { | |
| 281 widget._doNotUpdateInputOnValueChange = true; | |
| 282 widget._setOption("value", widget._inputValueToRealValue(widget.$input.val())); | |
| 283 delete widget._doNotUpdateInputOnValueChange; | |
| 284 } | |
| 285 } | |
| 286 } | |
| 287 }, | |
| 288 | |
| 289 __handleInputKeyUp: function(event) { | |
| 290 var $this = $(this); | |
| 291 var widget = $this.data("widget"); | |
| 292 if (event.keyCode == 13) { | |
| 293 if (widget._lastInputChangeWasCausedByAutocomplete) { | |
| 294 widget._lastInputChangeWasCausedByAutocomplete = false; | |
| 295 } else { | |
| 296 widget._trigger("apply"); | |
| 297 if (widget.$input.data("ui-autocomplete")) { | |
| 298 widget.$input.autocomplete("close"); | |
| 299 } | |
| 300 } | |
| 301 } | |
| 302 if (event.keyCode == 27) { | |
| 303 if (!widget._isAutocompleteVisible()) { | |
| 304 widget._trigger("discard"); | |
| 305 } | |
| 306 event.preventDefault(); | |
| 307 } | |
| 308 }, | |
| 309 | |
| 310 __handleAutocompleteOpen: function(event) { | |
| 311 var widget = this; | |
| 312 widget.$element.addClass("cgpma__textfield_autocomplete-is-open"); | |
| 313 }, | |
| 314 | |
| 315 __handleAutocompleteClose: function(event) { | |
| 316 var widget = this; | |
| 317 widget.$element.removeClass("cgpma__textfield_autocomplete-is-open"); | |
| 318 }, | |
| 319 | |
| 320 __handleInputClick: function() { | |
| 321 var $this = $(this); | |
| 322 var widget = $this.data("widget"); | |
| 323 if (widget.$input.data("ui-autocomplete")) { | |
| 324 widget.$input.autocomplete("search", ""); | |
| 325 } | |
| 326 } | |
| 327 | |
| 328 }); | |
| 329 })(jQuery); |
