PluginProbe
QuadMenu – Mega Menu / 1.8.9
QuadMenu – Mega Menu v1.8.9
3.3.8 3.3.7 3.3.6 trunk 1.8.4 1.8.5 1.8.7 1.8.8 1.8.9 1.9.0 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 88 releases
quadmenu / lib / ReduxCore / assets / js / vendor / jquery.alphanum.js

jquery.alphanum.js in QuadMenu – Mega Menu 1.8.9, at lib/ReduxCore/assets/js/vendor/jquery.alphanum.js

786 lines 22.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /********************************************************************
2 * Limit the characters that may be entered in a text field
3 * Common options: alphanumeric, alphabetic or numeric
4 * Kevin Sheedy, 2012
5 * http://github.com/KevinSheedy/jquery.alphanum
6 *********************************************************************/
7 (function( $ ){
8
9 // API ///////////////////////////////////////////////////////////////////
10 $.fn.alphanum = function(settings) {
11
12 var combinedSettings = getCombinedSettingsAlphaNum(settings);
13
14 var $collection = this;
15
16 setupEventHandlers($collection, trimAlphaNum, combinedSettings);
17
18 return this;
19 };
20
21 $.fn.alpha = function(settings) {
22
23 var defaultAlphaSettings = getCombinedSettingsAlphaNum("alpha");
24 var combinedSettings = getCombinedSettingsAlphaNum(settings, defaultAlphaSettings);
25
26 var $collection = this;
27
28 setupEventHandlers($collection, trimAlphaNum, combinedSettings);
29
30 return this;
31 };
32
33 $.fn.numeric = function(settings) {
34
35 var combinedSettings = getCombinedSettingsNum(settings);
36 var $collection = this;
37
38 setupEventHandlers($collection, trimNum, combinedSettings);
39
40 $collection.blur(function(){
41 numericField_Blur(this, settings);
42 });
43
44 return this;
45 };
46
47 // End of API /////////////////////////////////////////////////////////////
48
49
50 // Start Settings ////////////////////////////////////////////////////////
51
52 var DEFAULT_SETTINGS_ALPHANUM = {
53 allow : '', // Allow extra characters
54 disallow : '', // Disallow extra characters
55 allowSpace : true, // Allow the space character
56 allowNumeric : true, // Allow digits 0-9
57 allowUpper : true, // Allow upper case characters
58 allowLower : true, // Allow lower case characters
59 allowCaseless : true, // Allow characters that don't have both upper & lower variants - eg Arabic or Chinese
60 allowLatin : true, // a-z A-Z
61 allowOtherCharSets : true, // eg �, �, Arabic, Chinese etc
62 maxLength : NaN // eg Max Length
63 }
64
65 var DEFAULT_SETTINGS_NUM = {
66 allowPlus : false, // Allow the + sign
67 allowMinus : true, // Allow the - sign
68 allowThouSep : true, // Allow the thousands separator, default is the comma eg 12,000
69 allowDecSep : true, // Allow the decimal separator, default is the fullstop eg 3.141
70 allowLeadingSpaces : false,
71 maxDigits : NaN, // The max number of digits
72 maxDecimalPlaces : NaN, // The max number of decimal places
73 maxPreDecimalPlaces : NaN, // The max number digits before the decimal point
74 max : NaN, // The max numeric value allowed
75 min : NaN // The min numeric value allowed
76 }
77
78 // Some pre-defined groups of settings for convenience
79 var CONVENIENCE_SETTINGS_ALPHANUM = {
80 "alpha" : {
81 allowNumeric : false
82 },
83 "upper" : {
84 allowNumeric : false,
85 allowUpper : true,
86 allowLower : false,
87 allowCaseless : true
88 },
89 "lower" : {
90 allowNumeric : false,
91 allowUpper : false,
92 allowLower : true,
93 allowCaseless : true
94 }
95 };
96
97 // Some pre-defined groups of settings for convenience
98 var CONVENIENCE_SETTINGS_NUMERIC = {
99 "integer" : {
100 allowPlus : false,
101 allowMinus : true,
102 allowThouSep : false,
103 allowDecSep : false
104 },
105 "positiveInteger" : {
106 allowPlus : false,
107 allowMinus : false,
108 allowThouSep : false,
109 allowDecSep : false
110 }
111 };
112
113
114 var BLACKLIST = getBlacklistAscii() + getBlacklistNonAscii();
115 var THOU_SEP = ",";
116 var DEC_SEP = ".";
117 var DIGITS = getDigitsMap();
118 var LATIN_CHARS = getLatinCharsSet();
119
120 // Return the blacklisted special chars that are encodable using 7-bit ascii
121 function getBlacklistAscii(){
122 var blacklist = '!@#$%^&*()+=[]\\\';,/{}|":<>?~`.-_';
123 blacklist += " "; // 'Space' is on the blacklist but can be enabled using the 'allowSpace' config entry
124 return blacklist;
125 }
126
127 // Return the blacklisted special chars that are NOT encodable using 7-bit ascii
128 // We want this .js file to be encoded using 7-bit ascii so it can reach the widest possible audience
129 // Higher order chars must be escaped eg "\xAC"
130 // Not too worried about comments containing higher order characters for now (let's wait and see if it becomes a problem)
131 function getBlacklistNonAscii(){
132 var blacklist =
133 "\xAC" // �
134 + "\u20AC" // �
135 + "\xA3" // �
136 + "\xA6" // �
137 ;
138 return blacklist;
139 }
140
141 // End Settings ////////////////////////////////////////////////////////
142
143
144 // Implementation details go here ////////////////////////////////////////////////////////
145
146 function setupEventHandlers($textboxes, trimFunction, settings) {
147
148 $textboxes.each(function(){
149
150 var $textbox = $(this);
151
152 $textbox.bind("keyup change paste", function(e){
153
154 var pastedText = "";
155
156 if(e.originalEvent && e.originalEvent.clipboardData && e.originalEvent.clipboardData.getData)
157 pastedText = e.originalEvent.clipboardData.getData("text/plain")
158
159 // setTimeout is necessary for handling the 'paste' event
160 setTimeout(function(){
161 trimTextbox($textbox, trimFunction, settings, pastedText);
162 }, 0);
163 });
164
165 $textbox.bind("keypress", function(e){
166
167 // Determine which key is pressed.
168 // If it's a control key, then allow the event's default action to occur eg backspace, tab
169 var charCode = !e.charCode ? e.which : e.charCode;
170 if(isControlKey(charCode)
171 || e.ctrlKey
172 || e.metaKey ) // cmd on MacOS
173 return;
174
175 var newChar = String.fromCharCode(charCode);
176
177 // Determine if some text was selected / highlighted when the key was pressed
178 var selectionObject = $textbox.selection();
179 var start = selectionObject.start;
180 var end = selectionObject.end;
181
182 var textBeforeKeypress = $textbox.val();
183
184 // The new char may be inserted:
185 // 1) At the start
186 // 2) In the middle
187 // 3) At the end
188 // 4) User highlights some text and then presses a key which would replace the highlighted text
189 //
190 // Here we build the string that would result after the keypress.
191 // If the resulting string is invalid, we cancel the event.
192 // Unfortunately, it isn't enough to just check if the new char is valid because some chars
193 // are position sensitive eg the decimal point '.'' or the minus sign '-'' are only valid in certain positions.
194 var potentialTextAfterKeypress = textBeforeKeypress.substring(0, start) + newChar + textBeforeKeypress.substring(end);
195 var validatedText = trimFunction(potentialTextAfterKeypress, settings);
196
197 // If the keypress would cause the textbox to contain invalid characters, then cancel the keypress event
198 if(validatedText != potentialTextAfterKeypress)
199 e.preventDefault();
200 });
201 });
202
203 }
204
205 // Ensure the text is a valid number when focus leaves the textbox
206 // This catches the case where a user enters '-' or '.' without entering any digits
207 function numericField_Blur(inputBox, settings) {
208 var fieldValueNumeric = parseFloat($(inputBox).val());
209 var $inputBox = $(inputBox);
210
211 if(isNaN(fieldValueNumeric)) {
212 $inputBox.val("");
213 return;
214 }
215
216 if(isNumeric(settings.min) && fieldValueNumeric < settings.min)
217 $inputBox.val("");
218
219 if(isNumeric(settings.max) && fieldValueNumeric > settings.max)
220 $inputBox.val("");
221 }
222
223 function isNumeric(value) {
224 return !isNaN(value);
225 }
226
227 function isControlKey(charCode) {
228
229 if(charCode >= 32)
230 return false;
231 if(charCode == 10)
232 return false;
233 if(charCode == 13)
234 return false;
235
236 return true;
237 }
238
239 // One way to prevent a character being entered is to cancel the keypress event.
240 // However, this gets messy when you have to deal with things like copy paste which isn't a keypress.
241 // Which event gets fired first, keypress or keyup? What about IE6 etc etc?
242 // Instead, it's easier to allow the 'bad' character to be entered and then to delete it immediately after.
243
244 function trimTextbox($textBox, trimFunction, settings, pastedText){
245
246 var inputString = $textBox.val();
247
248 if(inputString == "" && pastedText.length > 0)
249 inputString = pastedText;
250
251 var outputString = trimFunction(inputString, settings);
252
253 if(inputString == outputString)
254 return;
255
256 var caretPos = $textBox.alphanum_caret();
257
258 $textBox.val(outputString);
259
260 //Reset the caret position
261 if(inputString.length ==(outputString.length + 1))
262 $textBox.alphanum_caret(caretPos - 1);
263 else
264 $textBox.alphanum_caret(caretPos);
265 }
266
267 function getCombinedSettingsAlphaNum(settings, defaultSettings){
268 if(typeof defaultSettings == "undefined")
269 defaultSettings = DEFAULT_SETTINGS_ALPHANUM;
270 var userSettings, combinedSettings = {};
271 if(typeof settings === "string")
272 userSettings = CONVENIENCE_SETTINGS_ALPHANUM[settings];
273 else if(typeof settings == "undefined")
274 userSettings = {};
275 else
276 userSettings = settings;
277
278 $.extend(combinedSettings, defaultSettings, userSettings);
279
280 if(typeof combinedSettings.blacklist == 'undefined')
281 combinedSettings.blacklistSet = getBlacklistSet(combinedSettings.allow, combinedSettings.disallow);
282
283 return combinedSettings;
284 }
285
286 function getCombinedSettingsNum(settings){
287 var userSettings, combinedSettings = {};
288 if(typeof settings === "string")
289 userSettings = CONVENIENCE_SETTINGS_NUMERIC[settings];
290 else if(typeof settings == "undefined")
291 userSettings = {};
292 else
293 userSettings = settings;
294
295 $.extend(combinedSettings, DEFAULT_SETTINGS_NUM, userSettings);
296
297 return combinedSettings;
298 }
299
300
301 // This is the heart of the algorithm
302 function alphanum_allowChar(validatedStringFragment, Char, settings){
303
304 if(settings.maxLength && validatedStringFragment.length >= settings.maxLength)
305 return false;
306
307 if(settings.allow.indexOf(Char) >=0 )
308 return true;
309
310 if(settings.allowSpace && (Char == " "))
311 return true;
312
313 if(settings.blacklistSet.contains(Char))
314 return false;
315
316 if(!settings.allowNumeric && DIGITS[Char])
317 return false;
318
319 if(!settings.allowUpper && isUpper(Char))
320 return false;
321
322 if(!settings.allowLower && isLower(Char))
323 return false;
324
325 if(!settings.allowCaseless && isCaseless(Char))
326 return false;
327
328 if(!settings.allowLatin && LATIN_CHARS.contains(Char))
329 return false;
330
331 if(!settings.allowOtherCharSets){
332 if(DIGITS[Char] || LATIN_CHARS.contains(Char))
333 return true;
334 else
335 return false;
336 }
337
338 return true;
339 }
340
341 function numeric_allowChar(validatedStringFragment, Char, settings){
342
343 if(DIGITS[Char]) {
344
345 if(isMaxDigitsReached(validatedStringFragment, settings))
346 return false;
347
348 if(isMaxPreDecimalsReached(validatedStringFragment, settings))
349 return false;
350
351 if(isMaxDecimalsReached(validatedStringFragment, settings))
352 return false;
353
354 if(isGreaterThanMax(validatedStringFragment + Char, settings))
355 return false;
356
357 if(isLessThanMin(validatedStringFragment + Char, settings))
358 return false;
359
360 return true;
361 }
362
363 if(settings.allowPlus && Char == '+' && validatedStringFragment == '')
364 return true;
365
366 if(settings.allowMinus && Char == '-' && validatedStringFragment == '')
367 return true;
368
369 if(Char == THOU_SEP && settings.allowThouSep && allowThouSep(validatedStringFragment, Char))
370 return true;
371
372 if(Char == DEC_SEP) {
373 // Only one decimal separator allowed
374 if(validatedStringFragment.indexOf(DEC_SEP) >= 0)
375 return false;
376 if(settings.allowDecSep)
377 return true;
378 }
379
380 return false;
381 }
382
383 function countDigits(string) {
384
385 // Error handling, nulls etc
386 string = string + "";
387
388 // Count the digits
389 return string.replace(/[^0-9]/g,"").length;
390 }
391
392 function isMaxDigitsReached(string, settings) {
393
394 var maxDigits = settings.maxDigits;
395
396 if(maxDigits == "" || isNaN(maxDigits))
397 return false; // In this case, there is no maximum
398
399 var numDigits = countDigits(string);
400
401 if(numDigits >= maxDigits)
402 return true;
403
404 return false;
405 }
406
407 function isMaxDecimalsReached(string, settings) {
408
409 var maxDecimalPlaces = settings.maxDecimalPlaces;
410
411 if(maxDecimalPlaces == "" || isNaN(maxDecimalPlaces))
412 return false; // In this case, there is no maximum
413
414 var indexOfDecimalPoint = string.indexOf(DEC_SEP);
415
416 if(indexOfDecimalPoint == -1)
417 return false;
418
419 var decimalSubstring = string.substring(indexOfDecimalPoint);
420 var numDecimals = countDigits(decimalSubstring);
421
422 if(numDecimals >= maxDecimalPlaces)
423 return true;
424
425 return false;
426 }
427
428 function isMaxPreDecimalsReached(string, settings) {
429
430 var maxPreDecimalPlaces = settings.maxPreDecimalPlaces;
431
432 if(maxPreDecimalPlaces == "" || isNaN(maxPreDecimalPlaces))
433 return false; // In this case, there is no maximum
434
435 var indexOfDecimalPoint = string.indexOf(DEC_SEP);
436
437 if(indexOfDecimalPoint >= 0)
438 return false;
439
440 var numPreDecimalDigits = countDigits(string);
441
442 if(numPreDecimalDigits >= maxPreDecimalPlaces)
443 return true;
444
445 return false;
446 }
447
448 function isGreaterThanMax(numericString, settings) {
449
450 if(!settings.max || settings.max < 0)
451 return false;
452
453 var outputNumber = parseFloat(numericString);
454 if(outputNumber > settings.max)
455 return true;
456
457 return false;
458 }
459
460 function isLessThanMin(numericString, settings) {
461
462 if(!settings.min || settings.min > 0)
463 return false;
464
465 var outputNumber = parseFloat(numericString);
466 if(outputNumber < settings.min)
467 return true;
468
469 return false;
470 }
471
472 /********************************
473 * Trims a string according to the settings provided
474 ********************************/
475 function trimAlphaNum(inputString, settings){
476
477 if(typeof inputString != "string")
478 return inputString;
479
480 var inChars = inputString.split("");
481 var outChars = [];
482 var i = 0;
483 var Char;
484
485 for(i=0; i<inChars.length; i++){
486 Char = inChars[i];
487 var validatedStringFragment = outChars.join("");
488 if(alphanum_allowChar(validatedStringFragment, Char, settings))
489 outChars.push(Char);
490 }
491
492 return outChars.join("");
493 }
494
495 function trimNum(inputString, settings){
496 if(typeof inputString != "string")
497 return inputString;
498
499 var inChars = inputString.split("");
500 var outChars = [];
501 var i = 0;
502 var Char;
503
504 for(i=0; i<inChars.length; i++){
505 Char = inChars[i];
506 var validatedStringFragment = outChars.join("");
507 if(numeric_allowChar(validatedStringFragment, Char, settings))
508 outChars.push(Char);
509 }
510
511 return outChars.join("");
512 }
513
514 function removeUpperCase(inputString){
515 var charArray = inputString.split('');
516 var i = 0;
517 var outputArray = [];
518 var Char;
519
520 for(i=0; i<charArray.length; i++){
521 Char = charArray[i];
522 }
523 }
524
525 function removeLowerCase(inputString){
526
527 }
528
529 function isUpper(Char){
530 var upper = Char.toUpperCase();
531 var lower = Char.toLowerCase();
532
533 if( (Char == upper) && (upper != lower))
534 return true;
535 else
536 return false;
537 }
538
539 function isLower(Char){
540 var upper = Char.toUpperCase();
541 var lower = Char.toLowerCase();
542
543 if( (Char == lower) && (upper != lower))
544 return true;
545 else
546 return false;
547 }
548
549 function isCaseless(Char){
550 if(Char.toUpperCase() == Char.toLowerCase())
551 return true;
552 else
553 return false;
554 }
555
556 function getBlacklistSet(allow, disallow){
557
558 var setOfBadChars = new Set(BLACKLIST + disallow);
559 var setOfGoodChars = new Set(allow);
560
561 var blacklistSet = setOfBadChars.subtract(setOfGoodChars);
562
563 return blacklistSet;
564 }
565
566 function getDigitsMap(){
567 var array = "0123456789".split("");
568 var map = {};
569 var i = 0;
570 var digit;
571
572 for(i=0; i<array.length; i++){
573 digit = array[i];
574 map[digit] = true;
575 }
576
577 return map;
578 }
579
580 function getLatinCharsSet(){
581 var lower = "abcdefghijklmnopqrstuvwxyz";
582 var upper = lower.toUpperCase();
583 var azAZ = new Set(lower + upper);
584
585 return azAZ;
586 }
587
588 function allowThouSep(currentString, Char) {
589
590 // Can't start with a THOU_SEP
591 if(currentString.length == 0)
592 return false;
593
594 // Can't have a THOU_SEP anywhere after a DEC_SEP
595 var posOfDecSep = currentString.indexOf(DEC_SEP);
596 if(posOfDecSep >= 0)
597 return false;
598
599 var posOfFirstThouSep = currentString.indexOf(THOU_SEP);
600
601 // Check if this is the first occurrence of a THOU_SEP
602 if(posOfFirstThouSep < 0)
603 return true;
604
605 var posOfLastThouSep = currentString.lastIndexOf(THOU_SEP);
606 var charsSinceLastThouSep = currentString.length - posOfLastThouSep - 1;
607
608 // Check if there has been 3 digits since the last THOU_SEP
609 if(charsSinceLastThouSep < 3)
610 return false;
611
612 var digitsSinceFirstThouSep = countDigits(currentString.substring(posOfFirstThouSep));
613
614 // Check if there has been a multiple of 3 digits since the first THOU_SEP
615 if((digitsSinceFirstThouSep % 3) > 0)
616 return false;
617
618 return true;
619 }
620
621 ////////////////////////////////////////////////////////////////////////////////////
622 // Implementation of a Set
623 ////////////////////////////////////////////////////////////////////////////////////
624 function Set(elems){
625 if(typeof elems == "string")
626 this.map = stringToMap(elems);
627 else
628 this.map = {};
629 }
630
631 Set.prototype.add = function(set){
632
633 var newSet = this.clone();
634
635 for(var key in set.map)
636 newSet.map[key] = true;
637
638 return newSet;
639 }
640
641 Set.prototype.subtract = function(set){
642
643 var newSet = this.clone();
644
645 for(var key in set.map)
646 delete newSet.map[key];
647
648 return newSet;
649 }
650
651 Set.prototype.contains = function(key){
652 if(this.map[key])
653 return true;
654 else
655 return false;
656 }
657
658 Set.prototype.clone = function(){
659 var newSet = new Set();
660
661 for(var key in this.map)
662 newSet.map[key] = true;
663
664 return newSet;
665 }
666 ////////////////////////////////////////////////////////////////////////////////////
667
668 function stringToMap(string){
669 var map = {};
670 var array = string.split("");
671 var i=0;
672 var Char;
673
674 for(i=0; i<array.length; i++){
675 Char = array[i];
676 map[Char] = true;
677 }
678
679 return map;
680 }
681
682 // Backdoor for testing
683 $.fn.alphanum.backdoorAlphaNum = function(inputString, settings){
684 var combinedSettings = getCombinedSettingsAlphaNum(settings);
685
686 return trimAlphaNum(inputString, combinedSettings);
687 };
688
689 $.fn.alphanum.backdoorNumeric = function(inputString, settings){
690 var combinedSettings = getCombinedSettingsNum(settings);
691
692 return trimNum(inputString, combinedSettings);
693 };
694
695 $.fn.alphanum.setNumericSeparators = function(settings) {
696
697 if(settings.thousandsSeparator.length != 1)
698 return;
699
700 if(settings.decimalSeparator.length != 1)
701 return;
702
703 THOU_SEP = settings.thousandsSeparator;
704 DEC_SEP = settings.decimalSeparator;
705 }
706
707 })( jQuery );
708
709
710 //Include the 3rd party lib: jquery.caret.js
711
712
713 // Set caret position easily in jQuery
714 // Written by and Copyright of Luke Morton, 2011
715 // Licensed under MIT
716 (function ($) {
717 // Behind the scenes method deals with browser
718 // idiosyncrasies and such
719 function caretTo(el, index) {
720 if (el.createTextRange) {
721 var range = el.createTextRange();
722 range.move("character", index);
723 range.select();
724 } else if (el.selectionStart != null) {
725 el.focus();
726 el.setSelectionRange(index, index);
727 }
728 };
729
730 // Another behind the scenes that collects the
731 // current caret position for an element
732
733 // TODO: Get working with Opera
734 function caretPos(el) {
735 if ("selection" in document) {
736 var range = el.createTextRange();
737 try {
738 range.setEndPoint("EndToStart", document.selection.createRange());
739 } catch (e) {
740 // Catch IE failure here, return 0 like
741 // other browsers
742 return 0;
743 }
744 return range.text.length;
745 } else if (el.selectionStart != null) {
746 return el.selectionStart;
747 }
748 };
749
750 // The following methods are queued under fx for more
751 // flexibility when combining with $.fn.delay() and
752 // jQuery effects.
753
754 // Set caret to a particular index
755 $.fn.alphanum_caret = function (index, offset) {
756 if (typeof(index) === "undefined") {
757 return caretPos(this.get(0));
758 }
759
760 return this.queue(function (next) {
761 if (isNaN(index)) {
762 var i = $(this).val().indexOf(index);
763
764 if (offset === true) {
765 i += index.length;
766 } else if (typeof(offset) !== "undefined") {
767 i += offset;
768 }
769
770 caretTo(this, i);
771 } else {
772 caretTo(this, index);
773 }
774
775 next();
776 });
777 };
778 }(jQuery));
779
780 /**********************************************************
781 * Selection Library
782 * Used to determine what text is highlighted in the textbox before a key is pressed.
783 * http://donejs.com/docs.html#!jQuery.fn.selection
784 * https://github.com/jupiterjs/jquerymx/blob/master/dom/selection/selection.js
785 ***********************************************************/
786 (function(e){var t=function(e){return e.replace(/([a-z])([a-z]+)/gi,function(e,t,n){return t+n.toLowerCase()}).replace(/_/g,"")},n=function(e){return e.replace(/^([a-z]+)_TO_([a-z]+)/i,function(e,t,n){return n+"_TO_"+t})},r=function(e){return e?e.ownerDocument.defaultView||e.ownerDocument.parentWindow:window},i=function(t,n){var r=e.Range.current(t).clone(),i=e.Range(t).select(t);if(!r.overlaps(i)){return null}if(r.compare("START_TO_START",i)<1){startPos=0;r.move("START_TO_START",i)}else{fromElementToCurrent=i.clone();fromElementToCurrent.move("END_TO_START",r);startPos=fromElementToCurrent.toString().length}if(r.compare("END_TO_END",i)>=0){endPos=i.toString().length}else{endPos=startPos+r.toString().length}return{start:startPos,end:endPos}},s=function(t){var n=r(t);if(t.selectionStart!==undefined){if(document.activeElement&&document.activeElement!=t&&t.selectionStart==t.selectionEnd&&t.selectionStart==0){return{start:t.value.length,end:t.value.length}}return{start:t.selectionStart,end:t.selectionEnd}}else if(n.getSelection){return i(t,n)}else{try{if(t.nodeName.toLowerCase()=="input"){var s=r(t).document.selection.createRange(),o=t.createTextRange();o.setEndPoint("EndToStart",s);var u=o.text.length;return{start:u,end:u+s.text.length}}else{var a=i(t,n);if(!a){return a}var f=e.Range.current().clone(),l=f.clone().collapse().range,c=f.clone().collapse(false).range;l.moveStart("character",-1);c.moveStart("character",-1);if(a.startPos!=0&&l.text==""){a.startPos+=2}if(a.endPos!=0&&c.text==""){a.endPos+=2}return a}}catch(h){return{start:t.value.length,end:t.value.length}}}},o=function(e,t,n){var i=r(e);if(e.setSelectionRange){if(n===undefined){e.focus();e.setSelectionRange(t,t)}else{e.select();e.selectionStart=t;e.selectionEnd=n}}else if(e.createTextRange){var s=e.createTextRange();s.moveStart("character",t);n=n||t;s.moveEnd("character",n-e.value.length);s.select()}else if(i.getSelection){var o=i.document,u=i.getSelection(),f=o.createRange(),l=[t,n!==undefined?n:t];a([e],l);f.setStart(l[0].el,l[0].count);f.setEnd(l[1].el,l[1].count);u.removeAllRanges();u.addRange(f)}else if(i.document.body.createTextRange){var f=document.body.createTextRange();f.moveToElementText(e);f.collapse();f.moveStart("character",t);f.moveEnd("character",n!==undefined?n:t);f.select()}},u=function(e,t,n,r){if(typeof n[0]==="number"&&n[0]<t){n[0]={el:r,count:n[0]-e}}if(typeof n[1]==="number"&&n[1]<=t){n[1]={el:r,count:n[1]-e};}},a=function(e,t,n){var r,i;n=n||0;for(var s=0;e[s];s++){r=e[s];if(r.nodeType===3||r.nodeType===4){i=n;n+=r.nodeValue.length;u(i,n,t,r)}else if(r.nodeType!==8){n=a(r.childNodes,t,n)}}return n};jQuery.fn.selection=function(e,t){if(e!==undefined){return this.each(function(){o(this,e,t)})}else{return s(this[0])}};e.fn.selection.getCharElement=a})(jQuery)