annotate src/DML/MainVisBundle/Resources/assets/marionette/modules/MainRegionModule/MainRegionModule.50-cgpma.textfield.js @ 1:f38015048f48 tip

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