├── jquery.a-tools-1.4.1.js └── jquery.asuggest.js /jquery.a-tools-1.4.1.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * a-tools 1.4.1 3 | * 4 | * Copyright (c) 2009 Andrey Kramarev(andrey.kramarev[at]ampparit.com), Ampparit Inc. (www.ampparit.com) 5 | * Licensed under the MIT license. 6 | * http://www.ampparit.fi/a-tools/license.txt 7 | * 8 | * Basic usage: 9 | 10 | 11 | 12 | 13 | // Get current selection 14 | var sel = $("textarea").getSelection() 15 | 16 | // Replace current selection 17 | $("input").replaceSelection("foo"); 18 | 19 | // Count characters 20 | alert($("textarea").countCharacters()); 21 | 22 | // Set max length without callback function 23 | $("textarea").setMaxLength(7); 24 | 25 | // Set max length with callback function which will be called when limit is exceeded 26 | $("textarea").setMaxLength(10, function() { 27 | alert("hello") 28 | }); 29 | 30 | // Removing limit: 31 | $("textarea").setMaxLength(-1); 32 | 33 | // Insert text at current caret position 34 | $("#textarea").insertAtCaretPos("hello"); 35 | 36 | // Set caret position (1 = beginning, -1 = end) 37 | $("#textArea").setCaretPos(10); 38 | 39 | // Set Selection 40 | $("#textArea").setSelection(10,15); 41 | 42 | */ 43 | var caretPositionAmp; 44 | 45 | jQuery.fn.extend({ 46 | getSelection: function() { // function for getting selection, and position of the selected text 47 | var input = this.jquery ? this[0] : this; 48 | var start; 49 | var end; 50 | var part; 51 | var number = 0; 52 | input.onmousedown = function() { // for IE because it loses caret position when focus changed 53 | if (document.selection && typeof(input.selectionStart) != "number") { 54 | document.selection.empty(); 55 | } else { 56 | window.getSelection().removeAllRanges(); 57 | } 58 | } 59 | if (document.selection) { 60 | // part for IE and Opera 61 | var s = document.selection.createRange(); 62 | var minus = 0; 63 | var position = 0; 64 | var minusEnd = 0; 65 | var re; 66 | var rc; 67 | if (input.value.match(/\n/g) != null) { 68 | number = input.value.match(/\n/g).length;// number of EOL simbols 69 | } 70 | if (s.text) { 71 | part = s.text; 72 | // OPERA support 73 | if (typeof(input.selectionStart) == "number") { 74 | start = input.selectionStart; 75 | end = input.selectionEnd; 76 | // return null if the selected text not from the needed area 77 | if (start == end) { 78 | return { start: start, end: end, text: s.text, length: end - start }; 79 | } 80 | } else { 81 | // IE support 82 | var firstRe; 83 | var secondRe; 84 | re = input.createTextRange(); 85 | rc = re.duplicate(); 86 | firstRe = re.text; 87 | re.moveToBookmark(s.getBookmark()); 88 | secondRe = re.text; 89 | rc.setEndPoint("EndToStart", re); 90 | // return null if the selectyed text not from the needed area 91 | if (firstRe == secondRe && firstRe != s.text) { 92 | return this; 93 | } 94 | start = rc.text.length; 95 | end = rc.text.length + s.text.length; 96 | } 97 | // remove all EOL to have the same start and end positons as in MOZILLA 98 | if (number > 0) { 99 | for (var i = 0; i <= number; i++) { 100 | var w = input.value.indexOf("\n", position); 101 | if (w != -1 && w < start) { 102 | position = w + 1; 103 | minus++; 104 | minusEnd = minus; 105 | } else if (w != -1 && w >= start && w <= end) { 106 | if (w == start + 1) { 107 | minus--; 108 | minusEnd--; 109 | position = w + 1; 110 | continue; 111 | } 112 | position = w + 1; 113 | minusEnd++; 114 | } else { 115 | i = number; 116 | } 117 | } 118 | } 119 | if (s.text.indexOf("\n", 0) == 1) { 120 | minusEnd = minusEnd + 2; 121 | } 122 | start = start - minus; 123 | end = end - minusEnd; 124 | 125 | return { start: start, end: end, text: s.text, length: end - start }; 126 | } 127 | input.focus (); 128 | if (typeof(input.selectionStart) == "number") { 129 | start = input.selectionStart; 130 | } else { 131 | s = document.selection.createRange(); 132 | re = input.createTextRange(); 133 | rc = re.duplicate(); 134 | re.moveToBookmark(s.getBookmark()); 135 | rc.setEndPoint("EndToStart", re); 136 | start = rc.text.length; 137 | } 138 | if (number > 0) { 139 | for (var i = 0; i <= number; i++) { 140 | var w = input.value.indexOf("\n", position); 141 | if (w != -1 && w < start) { 142 | position = w + 1; 143 | minus++; 144 | } else { 145 | i = number; 146 | } 147 | } 148 | } 149 | start = start - minus; 150 | return { start: start, end: start, text: s.text, length: 0 }; 151 | } else if (typeof(input.selectionStart) == "number" ) { 152 | start = input.selectionStart; 153 | end = input.selectionEnd; 154 | part = input.value.substring(input.selectionStart, input.selectionEnd); 155 | return { start: start, end: end, text: part, length: end - start }; 156 | } else { return { start: undefined, end: undefined, text: undefined, length: undefined }; } 157 | }, 158 | 159 | // function for the replacement of the selected text 160 | replaceSelection: function(inputStr) { 161 | var input = this.jquery ? this[0] : this; 162 | //part for IE and Opera 163 | var start; 164 | var end; 165 | var position = 0; 166 | var rc; 167 | var re; 168 | var number = 0; 169 | var minus = 0; 170 | var mozScrollFix = ( input.scrollTop == undefined ) ? 0 : input.scrollTop; 171 | if (document.selection && typeof(input.selectionStart) != "number") { 172 | var s = document.selection.createRange(); 173 | 174 | // IE support 175 | if (typeof(input.selectionStart) != "number") { // return null if the selected text not from the needed area 176 | var firstRe; 177 | var secondRe; 178 | re = input.createTextRange(); 179 | rc = re.duplicate(); 180 | firstRe = re.text; 181 | re.moveToBookmark(s.getBookmark()); 182 | secondRe = re.text; 183 | rc.setEndPoint("EndToStart", re); 184 | if (firstRe == secondRe && firstRe != s.text) { 185 | return this; 186 | } 187 | } 188 | if (s.text) { 189 | part = s.text; 190 | if (input.value.match(/\n/g) != null) { 191 | number = input.value.match(/\n/g).length;// number of EOL simbols 192 | } 193 | // IE support 194 | start = rc.text.length; 195 | // remove all EOL to have the same start and end positons as in MOZILLA 196 | if (number > 0) { 197 | for (var i = 0; i <= number; i++) { 198 | var w = input.value.indexOf("\n", position); 199 | if (w != -1 && w < start) { 200 | position = w + 1; 201 | minus++; 202 | 203 | } else { 204 | i = number; 205 | } 206 | } 207 | } 208 | s.text = inputStr; 209 | caretPositionAmp = rc.text.length + inputStr.length; 210 | re.move("character", caretPositionAmp); 211 | document.selection.empty(); 212 | input.blur(); 213 | } 214 | return this; 215 | } else if (typeof(input.selectionStart) == "number" && // MOZILLA support 216 | input.selectionStart != input.selectionEnd) { 217 | 218 | start = input.selectionStart; 219 | end = input.selectionEnd; 220 | input.value = input.value.substr(0, start) + inputStr + input.value.substr(end); 221 | position = start + inputStr.length; 222 | input.setSelectionRange(position, position); 223 | input.scrollTop = mozScrollFix; 224 | return this; 225 | } 226 | return this; 227 | }, 228 | 229 | //Set Selection in text 230 | setSelection: function(startPosition, endPosition) { 231 | startPosition = parseInt(startPosition); 232 | endPosition = parseInt(endPosition); 233 | 234 | var input = this.jquery ? this[0] : this; 235 | input.focus (); 236 | if (typeof(input.selectionStart) != "number") { 237 | re = input.createTextRange(); 238 | if (re.text.length < endPosition) { 239 | endPosition = re.text.length+1; 240 | } 241 | } 242 | if (endPosition < startPosition) { 243 | return this; 244 | } 245 | if (document.selection) { 246 | var number = 0; 247 | var plus = 0; 248 | var position = 0; 249 | var plusEnd = 0; 250 | if (typeof(input.selectionStart) != "number") { // IE 251 | re.collapse(true); 252 | re.moveEnd('character', endPosition); 253 | re.moveStart('character', startPosition); 254 | re.select(); 255 | return this; 256 | } else if (typeof(input.selectionStart) == "number") { // Opera 257 | if (input.value.match(/\n/g) != null) { 258 | number = input.value.match(/\n/g).length;// number of EOL simbols 259 | } 260 | if (number > 0) { 261 | for (var i = 0; i <= number; i++) { 262 | var w = input.value.indexOf("\n", position); 263 | if (w != -1 && w < startPosition) { 264 | position = w + 1; 265 | plus++; 266 | plusEnd = plus; 267 | } else if (w != -1 && w >= startPosition && w <= endPosition) { 268 | if (w == startPosition + 1) { 269 | plus--; 270 | plusEnd--; 271 | position = w + 1; 272 | continue; 273 | } 274 | position = w + 1; 275 | plusEnd++; 276 | } else { 277 | i = number; 278 | } 279 | } 280 | } 281 | startPosition = startPosition +plus; 282 | endPosition = endPosition + plusEnd; 283 | input.selectionStart = startPosition; 284 | input.selectionEnd = endPosition; 285 | return this; 286 | } else { 287 | return this; 288 | } 289 | } 290 | else if (input.selectionStart) { // MOZILLA support 291 | input.focus (); 292 | input.selectionStart = startPosition; 293 | input.selectionEnd = endPosition; 294 | return this; 295 | } 296 | }, 297 | 298 | // insert text at current caret position 299 | insertAtCaretPos: function(inputStr) { 300 | var input = this.jquery ? this[0] : this; 301 | var start; 302 | var end; 303 | var position; 304 | var s; 305 | var re; 306 | var rc; 307 | var point; 308 | var minus = 0; 309 | var number = 0; 310 | var mozScrollFix = ( input.scrollTop == undefined ) ? 0 : input.scrollTop; 311 | input.focus(); 312 | if (document.selection && typeof(input.selectionStart) != "number") { 313 | if (input.value.match(/\n/g) != null) { 314 | number = input.value.match(/\n/g).length;// number of EOL simbols 315 | } 316 | point = parseInt(caretPositionAmp); 317 | if (number > 0) { 318 | for (var i = 0; i <= number; i++) { 319 | var w = input.value.indexOf("\n", position); 320 | if (w != -1 && w <= point) { 321 | position = w + 1; 322 | point = point - 1; 323 | minus++; 324 | } 325 | } 326 | } 327 | } 328 | caretPositionAmp = parseInt(caretPositionAmp); 329 | // IE 330 | input.onmouseup = function() { // for IE because it loses caret position when focus changed 331 | if (document.selection && typeof(input.selectionStart) != "number") { 332 | input.focus(); 333 | s = document.selection.createRange(); 334 | re = input.createTextRange(); 335 | rc = re.duplicate(); 336 | re.moveToBookmark(s.getBookmark()); 337 | rc.setEndPoint("EndToStart", re); 338 | caretPositionAmp = rc.text.length; 339 | } 340 | } 341 | 342 | if (document.selection && typeof(input.selectionStart) != "number") { 343 | s = document.selection.createRange(); 344 | if (s.text.length != 0) { 345 | return this; 346 | } 347 | re = input.createTextRange(); 348 | textLength = re.text.length; 349 | rc = re.duplicate(); 350 | re.moveToBookmark(s.getBookmark()); 351 | rc.setEndPoint("EndToStart", re); 352 | start = rc.text.length; 353 | if (caretPositionAmp > 0 && start ==0) { 354 | minus = caretPositionAmp - minus; 355 | re.move("character", minus); 356 | re.select(); 357 | s = document.selection.createRange(); 358 | caretPositionAmp += inputStr.length; 359 | } else if (!(caretPositionAmp >= 0) && textLength ==0) { 360 | s = document.selection.createRange(); 361 | caretPositionAmp = inputStr.length + textLength; 362 | } else if (!(caretPositionAmp >= 0) && start ==0) { 363 | re.move("character", textLength); 364 | re.select(); 365 | s = document.selection.createRange(); 366 | caretPositionAmp = inputStr.length + textLength; 367 | } else if (!(caretPositionAmp >= 0) && start > 0) { 368 | re.move("character", 0); 369 | document.selection.empty(); 370 | re.select(); 371 | s = document.selection.createRange(); 372 | caretPositionAmp = start + inputStr.length; 373 | } else if (caretPositionAmp >= 0 && caretPositionAmp == textLength) { 374 | if (textLength != 0) { 375 | re.move("character", textLength); 376 | re.select(); 377 | } else { 378 | re.move("character", 0); 379 | } 380 | s = document.selection.createRange(); 381 | caretPositionAmp = inputStr.length + textLength; 382 | } else if (caretPositionAmp >= 0 && start != 0 && caretPositionAmp >= start) { 383 | minus = caretPositionAmp - start; 384 | re.move("character", minus); 385 | document.selection.empty(); 386 | re.select(); 387 | s = document.selection.createRange(); 388 | caretPositionAmp = caretPositionAmp + inputStr.length; 389 | } else if (caretPositionAmp >= 0 && start != 0 && caretPositionAmp < start) { 390 | re.move("character", 0); 391 | document.selection.empty(); 392 | re.select(); 393 | s = document.selection.createRange(); 394 | caretPositionAmp = caretPositionAmp + inputStr.length; 395 | } else { 396 | document.selection.empty(); 397 | re.select(); 398 | s = document.selection.createRange(); 399 | caretPositionAmp = caretPositionAmp + inputStr.length; 400 | } 401 | s.text = inputStr; 402 | input.focus(); 403 | 404 | return this; 405 | } else if (typeof(input.selectionStart) == "number" && // MOZILLA support 406 | input.selectionStart == input.selectionEnd) { 407 | position = input.selectionStart + inputStr.length; 408 | start = input.selectionStart; 409 | end = input.selectionEnd; 410 | input.value = input.value.substr(0, start) + inputStr + input.value.substr(end); 411 | input.setSelectionRange(position, position); 412 | input.scrollTop = mozScrollFix; 413 | return this; 414 | } 415 | return this; 416 | }, 417 | 418 | 419 | // Set caret position 420 | setCaretPos: function(inputStr) { 421 | 422 | var input = this.jquery ? this[0] : this; 423 | var s; 424 | var re; 425 | var position; 426 | var number = 0; 427 | var minus = 0; 428 | var w; 429 | input.focus(); 430 | if (parseInt(inputStr) == 0) { 431 | return this; 432 | } 433 | //if (document.selection && typeof(input.selectionStart) == "number") { 434 | if (parseInt(inputStr) > 0) { 435 | inputStr = parseInt(inputStr) - 1; 436 | if (document.selection && typeof(input.selectionStart) == "number" && input.selectionStart == input.selectionEnd) { 437 | if (input.value.match(/\n/g) != null) { 438 | number = input.value.match(/\n/g).length;// number of EOL simbols 439 | } 440 | if (number > 0) { 441 | for (var i = 0; i <= number; i++) { 442 | w = input.value.indexOf("\n", position); 443 | if (w != -1 && w <= inputStr) { 444 | position = w + 1; 445 | inputStr = parseInt(inputStr) + 1; 446 | } 447 | } 448 | } 449 | } 450 | } 451 | else if (parseInt(inputStr) < 0) { 452 | inputStr = parseInt(inputStr) + 1; 453 | if (document.selection && typeof(input.selectionStart) != "number") { 454 | inputStr = input.value.length + parseInt(inputStr); 455 | if (input.value.match(/\n/g) != null) { 456 | number = input.value.match(/\n/g).length;// number of EOL simbols 457 | } 458 | if (number > 0) { 459 | for (var i = 0; i <= number; i++) { 460 | w = input.value.indexOf("\n", position); 461 | if (w != -1 && w <= inputStr) { 462 | position = w + 1; 463 | inputStr = parseInt(inputStr) - 1; 464 | minus += 1; 465 | } 466 | } 467 | inputStr = inputStr + minus - number; 468 | } 469 | } else if (document.selection && typeof(input.selectionStart) == "number") { 470 | inputStr = input.value.length + parseInt(inputStr); 471 | if (input.value.match(/\n/g) != null) { 472 | number = input.value.match(/\n/g).length;// number of EOL simbols 473 | } 474 | if (number > 0) { 475 | inputStr = parseInt(inputStr) - number; 476 | for (var i = 0; i <= number; i++) { 477 | w = input.value.indexOf("\n", position); 478 | if (w != -1 && w <= (inputStr)) { 479 | position = w + 1; 480 | inputStr = parseInt(inputStr) + 1; 481 | minus += 1; 482 | } 483 | } 484 | } 485 | } else { inputStr = input.value.length + parseInt(inputStr); } 486 | } else { return this; } 487 | // IE 488 | if (document.selection && typeof(input.selectionStart) != "number") { 489 | s = document.selection.createRange(); 490 | if (s.text != 0) { 491 | return this; 492 | } 493 | re = input.createTextRange(); 494 | re.collapse(true); 495 | re.moveEnd('character', inputStr); 496 | re.moveStart('character', inputStr); 497 | re.select(); 498 | caretPositionAmp = inputStr; 499 | 500 | return this; 501 | } else if (typeof(input.selectionStart) == "number" && // MOZILLA support 502 | input.selectionStart == input.selectionEnd) { 503 | input.setSelectionRange(inputStr, inputStr); 504 | return this; 505 | } 506 | return this; 507 | 508 | }, 509 | 510 | countCharacters: function(str) { 511 | var input = this.jquery ? this[0] : this; 512 | if (input.value.match(/\r/g) != null) { 513 | return input.value.length - input.value.match(/\r/g).length; 514 | } 515 | return input.value.length; 516 | }, 517 | 518 | setMaxLength: function(max, f) { 519 | this.each(function() { 520 | var input = this.jquery ? this[0] : this; 521 | var type = input.type; 522 | var isSelected; 523 | var maxCharacters; 524 | // remove limit if input is a negative number 525 | if (parseInt(max) < 0) { 526 | max=100000000; 527 | } 528 | if (type == "text") { 529 | input.maxLength = max; 530 | } 531 | if (type == "textarea" || type == "text") { 532 | input.onkeypress = function(e) { 533 | var spacesR = input.value.match(/\r/g); 534 | maxCharacters = max; 535 | if (spacesR != null) { 536 | maxCharacters = parseInt(maxCharacters) + spacesR.length; 537 | } 538 | // get event 539 | var key = e || event; 540 | var keyCode = key.keyCode; 541 | // check if any part of text is selected 542 | if (document.selection) { 543 | isSelected = document.selection.createRange().text.length > 0; 544 | } else { 545 | isSelected = input.selectionStart != input.selectionEnd; 546 | } 547 | if (input.value.length >= maxCharacters && (keyCode > 47 || keyCode == 32 || 548 | keyCode == 0 || keyCode == 13) && !key.ctrlKey && !key.altKey && !isSelected) { 549 | input.value = input.value.substring(0,maxCharacters); 550 | if (typeof(f) == "function") { f() } //callback function 551 | return false; 552 | } 553 | } 554 | input.onkeyup = function() { 555 | var spacesR = input.value.match(/\r/g); 556 | var plus = 0; 557 | var position = 0; 558 | maxCharacters = max; 559 | if (spacesR != null) { 560 | for (var i = 0; i <= spacesR.length; i++) { 561 | if (input.value.indexOf("\n", position) <= parseInt(max)) { 562 | plus++; 563 | position = input.value.indexOf("\n", position) + 1; 564 | } 565 | } 566 | maxCharacters = parseInt(max) + plus; 567 | } 568 | if (input.value.length > maxCharacters) { 569 | input.value = input.value.substring(0, maxCharacters); 570 | if (typeof(f) == "function") { f() } 571 | return this; 572 | } 573 | } 574 | } else { return this; } 575 | }) 576 | return this; 577 | } 578 | }); 579 | -------------------------------------------------------------------------------- /jquery.asuggest.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery textarea suggest plugin 3 | * 4 | * Copyright (c) 2009-2010 Roman Imankulov 5 | * 6 | * Dual licensed under the MIT and GPL licenses: 7 | * http://www.opensource.org/licenses/mit-license.php 8 | * http://www.gnu.org/licenses/gpl.html 9 | * 10 | * Requires: 11 | * - jQuery (tested with 1.3.x and 1.4.x) 12 | * - jquery.a-tools >= 1.4.1 (http://plugins.jquery.com/project/a-tools) 13 | */ 14 | 15 | /*globals jQuery,document */ 16 | 17 | (function ($) { 18 | // workaround for Opera browser 19 | if (navigator.userAgent.match(/opera/i)) { 20 | $(document).keypress(function (e) { 21 | if ($.asuggestFocused) { 22 | $.asuggestFocused.focus(); 23 | $.asuggestFocused = null; 24 | e.preventDefault(); 25 | e.stopPropagation(); 26 | } 27 | }); 28 | } 29 | 30 | $.asuggestKeys = { 31 | UNKNOWN: 0, 32 | SHIFT: 16, 33 | CTRL: 17, 34 | ALT: 18, 35 | LEFT: 37, 36 | UP: 38, 37 | RIGHT: 39, 38 | DOWN: 40, 39 | DEL: 46, 40 | TAB: 9, 41 | RETURN: 13, 42 | ESC: 27, 43 | COMMA: 188, 44 | PAGEUP: 33, 45 | PAGEDOWN: 34, 46 | BACKSPACE: 8, 47 | SPACE: 32 48 | }; 49 | $.asuggestFocused = null; 50 | 51 | $.fn.asuggest = function (suggests, options) { 52 | return this.each(function () { 53 | $.makeSuggest(this, suggests, options); 54 | }); 55 | }; 56 | 57 | $.fn.asuggest.defaults = { 58 | 'delimiters': '\n ', 59 | 'minChunkSize': 1, 60 | 'cycleOnTab': true, 61 | 'autoComplete': true, 62 | 'endingSymbols': ' ', 63 | 'stopSuggestionKeys': [$.asuggestKeys.RETURN, $.asuggestKeys.SPACE], 64 | 'ignoreCase': false 65 | }; 66 | 67 | /* Make suggest: 68 | * 69 | * create and return jQuery object on the top of DOM object 70 | * and store suggests as part of this object 71 | * 72 | * @param area: HTML DOM element to add suggests to 73 | * @param suggests: The array of suggest strings 74 | * @param options: The options object 75 | */ 76 | $.makeSuggest = function (area, suggests, options) { 77 | options = $.extend({}, $.fn.asuggest.defaults, options); 78 | 79 | var KEY = $.asuggestKeys, 80 | $area = $(area); 81 | $area.suggests = suggests; 82 | $area.options = options; 83 | 84 | /* Internal method: get the chunk of text before the cursor */ 85 | $area.getChunk = function () { 86 | var delimiters = this.options.delimiters.split(''), // array of chars 87 | textBeforeCursor = this.val().substr(0, this.getSelection().start), 88 | indexOfDelimiter = -1, 89 | i, 90 | d, 91 | idx; 92 | for (i = 0; i < delimiters.length; i++) { 93 | d = delimiters[i]; 94 | idx = textBeforeCursor.lastIndexOf(d); 95 | if (idx > indexOfDelimiter) { 96 | indexOfDelimiter = idx; 97 | } 98 | } 99 | if (indexOfDelimiter < 0) { 100 | return textBeforeCursor; 101 | } else { 102 | return textBeforeCursor.substr(indexOfDelimiter + 1); 103 | } 104 | }; 105 | 106 | /* Internal method: get completion. 107 | * If performCycle is true then analyze getChunk() and and getSelection() 108 | */ 109 | $area.getCompletion = function (performCycle) { 110 | var text = this.getChunk(), 111 | selectionText = this.getSelection().text, 112 | suggests = this.suggests, 113 | foundAlreadySelectedValue = false, 114 | firstMatchedValue = null, 115 | i, 116 | suggest; 117 | // search the variant 118 | for (i = 0; i < suggests.length; i++) { 119 | suggest = suggests[i]; 120 | if ($area.options.ignoreCase) { 121 | suggest = suggest.toLowerCase(); 122 | text = text.toLowerCase(); 123 | } 124 | // some variant is found 125 | if (suggest.indexOf(text) === 0) { 126 | if (performCycle) { 127 | if (text + selectionText === suggest) { 128 | foundAlreadySelectedValue = true; 129 | } else if (foundAlreadySelectedValue) { 130 | return suggest.substr(text.length); 131 | } else if (firstMatchedValue === null) { 132 | firstMatchedValue = suggest; 133 | } 134 | } else { 135 | return suggest.substr(text.length); 136 | } 137 | } 138 | } 139 | if (performCycle && firstMatchedValue) { 140 | return firstMatchedValue.substr(text.length); 141 | } else { 142 | return null; 143 | } 144 | }; 145 | 146 | $area.updateSelection = function (completion) { 147 | if (completion) { 148 | var _selectionStart = $area.getSelection().start, 149 | _selectionEnd = _selectionStart + completion.length; 150 | if ($area.getSelection().text === "") { 151 | if ($area.val().length === _selectionStart) { // Weird IE workaround, I really have no idea why it works 152 | $area.setCaretPos(_selectionStart + 10000); 153 | } 154 | $area.insertAtCaretPos(completion); 155 | } else { 156 | $area.replaceSelection(completion); 157 | } 158 | $area.setSelection(_selectionStart, _selectionEnd); 159 | } 160 | }; 161 | 162 | $area.unbind('keydown.asuggest').bind('keydown.asuggest', function (e) { 163 | if (e.keyCode === KEY.TAB) { 164 | if ($area.options.cycleOnTab) { 165 | var chunk = $area.getChunk(); 166 | if (chunk.length >= $area.options.minChunkSize) { 167 | $area.updateSelection($area.getCompletion(true)); 168 | } 169 | e.preventDefault(); 170 | e.stopPropagation(); 171 | $area.focus(); 172 | $.asuggestFocused = this; 173 | return false; 174 | } 175 | } 176 | // Check for conditions to stop suggestion 177 | if ($area.getSelection().length && 178 | $.inArray(e.keyCode, $area.options.stopSuggestionKeys) !== -1) { 179 | // apply suggestion. Clean up selection and insert a space 180 | var _selectionEnd = $area.getSelection().end + 181 | $area.options.endingSymbols.length; 182 | var _text = $area.getSelection().text + 183 | $area.options.endingSymbols; 184 | $area.replaceSelection(_text); 185 | $area.setSelection(_selectionEnd, _selectionEnd); 186 | e.preventDefault(); 187 | e.stopPropagation(); 188 | this.focus(); 189 | $.asuggestFocused = this; 190 | return false; 191 | } 192 | }); 193 | 194 | $area.unbind('keyup.asuggest').bind('keyup.asuggest', function (e) { 195 | var hasSpecialKeys = e.altKey || e.metaKey || e.ctrlKey, 196 | hasSpecialKeysOrShift = hasSpecialKeys || e.shiftKey; 197 | switch (e.keyCode) { 198 | case KEY.UNKNOWN: // Special key released 199 | case KEY.SHIFT: 200 | case KEY.CTRL: 201 | case KEY.ALT: 202 | case KEY.RETURN: // we don't want to suggest when RETURN key has pressed (another IE workaround) 203 | break; 204 | case KEY.TAB: 205 | if (!hasSpecialKeysOrShift && $area.options.cycleOnTab) { 206 | break; 207 | } 208 | case KEY.ESC: 209 | case KEY.BACKSPACE: 210 | case KEY.DEL: 211 | case KEY.UP: 212 | case KEY.DOWN: 213 | case KEY.LEFT: 214 | case KEY.RIGHT: 215 | if (!hasSpecialKeysOrShift && $area.options.autoComplete) { 216 | $area.replaceSelection(""); 217 | } 218 | break; 219 | default: 220 | if (!hasSpecialKeys && $area.options.autoComplete) { 221 | var chunk = $area.getChunk(); 222 | if (chunk.length >= $area.options.minChunkSize) { 223 | $area.updateSelection($area.getCompletion(false)); 224 | } 225 | } 226 | break; 227 | } 228 | }); 229 | return $area; 230 | }; 231 | }(jQuery)); 232 | --------------------------------------------------------------------------------