From 76d3f16ae8b5a0f2b1345d72d8b97b6c10f015fa Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 12 Jan 2015 23:33:37 -0600 Subject: [PATCH 1/2] Fixed a pasting issue that resulted in a target's value being cleared when no additional characters were being pasted (#72) Improved support for other scripts that utilize the key events so as to prevent conflicts from happening Added support drop events, which are handle just like paste events (#73) Added support for tabbing through fields using the left and right arrow keys (#74) Auto tabbing support added to several input types: tel, number, email, url and search (#75) --- CHANGELOG.md | 14 ++++ README.md | 7 +- bower.json | 2 +- index.html | 8 ++- js/jquery.autotab.js | 145 +++++++++++++++++++++++++++------------ js/jquery.autotab.min.js | 38 +++++----- 6 files changed, 144 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e270315..0c66ebd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## 1.9.0 (2015-01-13) + +Features: + +* improved support for other scripts that utilize the key events so as to prevent conflicts from happening +* added support `drop` events, which are handle just like `paste` events (#73) +* added support for tabbing through fields using the left and right arrow keys (#74) +* auto tabbing support added to several input types: tel, number, email, url and search (#75) + +Bug fixes: + +* fixed a pasting issue that resulted in a target's value being cleared when no additional characters were being pasted (#72) + + ## 1.8.1 (2014-11-01) Features: diff --git a/README.md b/README.md index 161aa1c..f7fb880 100644 --- a/README.md +++ b/README.md @@ -493,8 +493,9 @@ Autotab has several filter formats available, all passed into the `format` key. ## Known Issues -Due to security measures placed in iOS, Autotab cannot achieve auto tabbing functionality when hitting a field's character limit. The problem stems from the `focus` event not being triggered manually. As a workaround, Autotab works with iOS by keeping the keyboard open, allowing you to navigate using the arrow shortcuts. - +* Due to security measures placed in iOS, Autotab cannot achieve auto tabbing functionality when hitting a field's character limit. The problem stems from the `focus` event not being triggered manually. As a workaround, Autotab works with iOS by keeping the keyboard open, allowing you to navigate using the arrow shortcuts. +* Any script that uses the `keydown` and `keypress` events may conflict with Autotab, or vice versa. As of 1.9.0, Autotab uses event extensions in an attempt to prevent this from happening. +* With limitations of `selection` in most text field types, only `text`, `password` and `textarea` fields support auto tabbing and filtering, while `tel`, `number`, `email`, `url` and `search` support auto tabbing only. ## Minify @@ -509,6 +510,6 @@ You can also reach out to me on twitter: [@mathachew](http://www.twitter.com/mat ## Copyright and license -© 2014 Matthew Miller +© 2015 Matthew Miller Licensed under the MIT licensing: http://www.opensource.org/licenses/mit-license.php diff --git a/bower.json b/bower.json index 1d855eb..94f9aad 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "jquery.autotab", - "version": "1.8.1", + "version": "1.9.0", "description": "A jQuery plugin that provides auto-tabbing and filtering on text fields in a form.", "main": [ "./js/jquery.autotab.min.js" ], "homepage": "https://github.com/Mathachew/jquery-autotab", diff --git a/index.html b/index.html index 38fe18e..d149f82 100644 --- a/index.html +++ b/index.html @@ -314,11 +314,13 @@

jQuery Autotab Demo


Email:
- Number: + Number:
- Range: + Tel:
- URL: + Range: +
+ URL:
 // Note: This call is not necessary as 'all' is the default format
diff --git a/js/jquery.autotab.js b/js/jquery.autotab.js
index 032337c..5b63151 100644
--- a/js/jquery.autotab.js
+++ b/js/jquery.autotab.js
@@ -1,8 +1,8 @@
 /**
- * Autotab - jQuery plugin 1.8.1
+ * Autotab - jQuery plugin 1.9.0
  * https://github.com/Mathachew/jquery-autotab
  * 
- * Copyright (c) 2008, 2014 Matthew Miller
+ * Copyright (c) 2008, 2015 Matthew Miller
  * 
  * Licensed under the MIT licensing:
  *   http://www.opensource.org/licenses/mit-license.php
@@ -29,6 +29,7 @@
 
     var getSettings = function (e) {
         var settings = {
+            arrowKey: false,
             format: 'all',
             loaded: false,
             disabled: false,
@@ -42,7 +43,8 @@
             trigger: null,
             originalValue: '',
             changed: false,
-            editable: (e.type == 'text' || e.type == 'password' || e.type == 'textarea'),
+            editable: (e.type === 'text' || e.type === 'password' || e.type === 'textarea' || e.type === 'tel' || e.type === 'number' || e.type === 'email' || e.type === 'search' || e.type === 'url'),
+            filterable: (e.type === 'text' || e.type === 'password' || e.type === 'textarea'),
             tabOnSelect: false
         };
 
@@ -81,6 +83,39 @@
         return (typeof e !== 'undefined' && (typeof e === 'string' || !(e instanceof jQuery)));
     };
 
+    var getSelection = function (e) {
+        var start = 0,
+            end = 0,
+            selectionType = 0;
+
+        if (e.type === 'text' || e.type === 'password' || e.type === 'textarea') {
+            if (typeof e.selectionStart === 'number' && typeof e.selectionEnd === 'number') {
+                // Non-IE browsers and IE 9+
+                start = e.selectionStart;
+                end = e.selectionEnd;
+                selectionType = 1;
+            }
+            else if (document.selection && document.selection.createRange) {
+                // For IE up to version 8
+                var selectionRange = document.selection.createRange(),
+                    textInputRange = e.createTextRange(),
+                    precedingRange = e.createTextRange(),
+                    bookmark = selectionRange.getBookmark();
+                textInputRange.moveToBookmark(bookmark);
+                precedingRange.setEndPoint("EndToStart", textInputRange);
+                start = precedingRange.text.length;
+                end = start + selectionRange.text.length;
+                selectionType = 2;
+            }
+        }
+
+        return {
+            start: start,
+            end: end,
+            selectionType: selectionType
+        };
+    };
+
     $.autotab = function (options) {
         if (typeof options !== 'object') {
             options = {};
@@ -424,7 +459,13 @@
                             target.trigger('autotab-next');
                         }
                         else {
-                            target.focus().select();
+                            // Allows the user to navigate between each charater with arrow keys
+                            if (defaults.arrowKey) {
+                                target.focus();
+                            }
+                            else {
+                                target.focus().select();
+                            }
                         }
 
                         settings.focusChange = new Date();
@@ -447,11 +488,15 @@
                     if (previous.prop('disabled') || previous.prop('readonly')) {
                         previous.trigger('autotab-previous');
                     }
-                    else if (value.length && previous.data('autotab-editable')) {
+                    else if (value.length && previous.data('autotab-editable') && !defaults.arrowKey) {
                         previous.focus().val(value.substring(0, value.length - 1));
                         setSettings(previous, { changed: true });
                     }
                     else {
+                        if (defaults.arrowKey) {
+                            setSettings(this, { arrowKey: false });
+                        }
+
                         previous.focus();
                     }
 
@@ -467,30 +512,33 @@
                 setSettings(this, { changed: false });
                 $(this).change();
             }
-        }).on('keydown', function (e) {
+        }).on('keydown.autotab', function (e) {
             var defaults = getSettings(this);
 
             if (!defaults || defaults.disabled) {
                 return true;
             }
 
-            var keyCode = e.which || e.charCode;
+            var selection = getSelection(this),
+                keyCode = e.which || e.charCode;
 
             // Go to the previous element when backspace
             // is pressed in an empty input field
             if (keyCode == 8) {
+                defaults.arrowKey = false;
+
                 // Prevent the browser from of navigating to the previous page
-                if (this.type === 'select-one' || this.type === 'checkbox' || this.type === 'radio' || this.type === 'button' || this.type === 'submit' || this.type === 'range') {
+                if (this.type === 'select-one' || this.type === 'select-multiple' || this.type === 'checkbox' || this.type === 'radio' || this.type === 'button' || this.type === 'submit' || this.type === 'range') {
                     $(this).trigger('autotab-previous', defaults);
                     return false;
                 }
 
+                setSettings(this, { changed: (this.value !== defaults.originalValue) });
+
                 if (this.value.length === 0) {
                     $(this).trigger('autotab-previous', defaults);
                     return;
                 }
-
-                setSettings(this, { changed: (this.value !== defaults.originalValue) });
             }
             else if (keyCode == 9 && settings.focusChange !== null) {
                 // Tab backwards
@@ -504,23 +552,46 @@
                     return false;
                 }
             }
-        }).on('keypress', function (e) {
+            else if (this.type !== 'range' && this.type !== 'select-one' && this.type !== 'select-multiple') {
+                if ((this.type !== 'tel' && this.type !== 'number') || ((this.type === 'tel' || this.type === 'number') && this.value.length == 0)) {
+                    if (keyCode == 37 && (!defaults.editable || selection.start == 0)) {
+                        defaults.arrowKey = true;
+                        $(this).trigger('autotab-previous', defaults);
+                    }
+                    else if (keyCode == 39 && (!defaults.editable || !defaults.filterable || selection.end == this.value.length || this.value.length == 0)) {
+                        defaults.arrowKey = true;
+                        $(this).trigger('autotab-next', defaults);
+                    }
+                }
+            }
+        }).on('keypress.autotab', function (e) {
             var defaults = getSettings(this),
                 keyCode = e.which || e.keyCode;
 
             // e.charCode == 0 indicates a special key has been pressed, which only Firefox triggers
-            if (!defaults || defaults.disabled || (settings.firefox && e.charCode === 0) || e.ctrlKey || e.altKey || keyCode == 13 || (this.type != 'text' && this.type != 'password' && this.type != 'textarea') || this.disabled) {
+            if (!defaults || defaults.disabled || (settings.firefox && e.charCode === 0) || e.ctrlKey || e.altKey || keyCode == 13 || this.disabled) {
                 return true;
             }
 
             var keyChar = String.fromCharCode(keyCode);
 
+            if (this.type != 'text' && this.type != 'password' && this.type != 'textarea') {
+                // this.value.length is the length before the keypress event was trigged
+                if ((this.value.length + 1) >= defaults.maxlength) {
+                    defaults.arrowKey = false;
+                    $(this).trigger('autotab-next', defaults);
+                }
+
+                return !(this.value.length == defaults.maxlength);
+            }
+
             // Prevents auto tabbing when defaults.trigger is pressed
             if (defaults.trigger !== null && defaults.trigger.indexOf(keyChar) >= 0) {
                 if (settings.focusChange !== null && (new Date().getTime() - settings.focusChange.getTime()) < settings.tabPause) {
                     settings.focusChange = null;
                 }
                 else {
+                    defaults.arrowKey = false;
                     $(this).trigger('autotab-next', defaults);
                 }
 
@@ -529,7 +600,7 @@
 
             settings.focusChange = null;
 
-            var hasValue = document.selection && document.selection.createRange ? true : (e.charCode > 0);
+            var hasValue = document.selection && document.selection.createRange ? true : (keyCode > 0);
 
             keyChar = filterValue(this, keyChar, defaults);
 
@@ -539,67 +610,50 @@
 
             // Many, many thanks to Tim Down for this solution: http://stackoverflow.com/a/3923320/94656
             if (hasValue && (this.value.length <= this.maxLength)) {
-                var start, end,
-                    selectionType = 0;
-
-                if (typeof this.selectionStart === 'number' && typeof this.selectionEnd === 'number') {
-                    // Non-IE browsers and IE 9
-                    start = this.selectionStart;
-                    end = this.selectionEnd;
-                    selectionType = 1;
-                }
-                else if (document.selection && document.selection.createRange) {
-                    // For IE up to version 8
-                    var selectionRange = document.selection.createRange(),
-                        textInputRange = this.createTextRange(),
-                        precedingRange = this.createTextRange(),
-                        bookmark = selectionRange.getBookmark();
-                    textInputRange.moveToBookmark(bookmark);
-                    precedingRange.setEndPoint("EndToStart", textInputRange);
-                    start = precedingRange.text.length;
-                    end = start + selectionRange.text.length;
-                    selectionType = 2;
-                }
+                var selection = getSelection(this);
 
                 // Text is fully selected, so it needs to be replaced
-                if (start === 0 && end == this.value.length) {
+                if (selection.start === 0 && selection.end == this.value.length) {
                     this.value = keyChar;
                     setSettings(this, { changed: (this.value != defaults.originalValue) });
                 }
                 else {
-                    if (this.value.length == this.maxLength && start === end) {
+                    if (this.value.length == this.maxLength && selection.start === selection.end) {
+                        defaults.arrowKey = false;
                         $(this).trigger('autotab-next', defaults);
                         return false;
                     }
 
-                    this.value = this.value.slice(0, start) + keyChar + this.value.slice(end);
+                    this.value = this.value.slice(0, selection.start) + keyChar + this.value.slice(selection.end);
                     setSettings(this, { changed: (this.value != defaults.originalValue) });
                 }
 
                 // Prevents the cursor position from being set to the end of the text box
                 // This is called even if the text is fully selected and replaced due to an unexpected behavior in IE6 and up (#32)
                 if (this.value.length != defaults.maxlength) {
-                    start++;
+                    selection.start++;
 
-                    if (selectionType == 1) {
-                        this.selectionStart = this.selectionEnd = start;
+                    if (selection.selectionType == 1) {
+                        this.selectionStart = this.selectionEnd = selection.start;
                     }
-                    else if (selectionType == 2) {
+                    else if (selection.selectionType == 2) {
                         var range = this.createTextRange();
                         range.collapse(true);
-                        range.moveEnd('character', start);
-                        range.moveStart('character', start);
+                        range.moveEnd('character', selection.start);
+                        range.moveStart('character', selection.start);
                         range.select();
                     }
                 }
             }
 
+
             if (this.value.length == defaults.maxlength) {
+                defaults.arrowKey = false;
                 $(this).trigger('autotab-next', defaults);
             }
 
             return false;
-        }).on('paste', function (e) {
+        }).on('drop paste', function (e) {
             var defaults = getSettings(this);
 
             if (!defaults) {
@@ -643,13 +697,13 @@
                             filteredValue = filterValue(e, trimmedValue, defaults).substr(0, defaults.maxlength);
 
                         if (!filteredValue) {
-                            e.value = '';
                             return;
                         }
 
                         e.value = filteredValue;
 
                         if (filteredValue.length == defaults.maxlength) {
+                            defaults.arrowKey = false;
                             $(e).trigger('autotab-next', defaults);
 
                             if (!settings.iOS) {
@@ -660,6 +714,7 @@
                     };
 
                     if (e.value.length == originDefaults.maxlength) {
+                        defaults.arrowKey = false;
                         $(e).trigger('autotab-next', defaults);
 
                         if (!settings.iOS) {
diff --git a/js/jquery.autotab.min.js b/js/jquery.autotab.min.js
index 8517801..96e5a31 100644
--- a/js/jquery.autotab.min.js
+++ b/js/jquery.autotab.min.js
@@ -1,26 +1,28 @@
 /**
- * Autotab - jQuery plugin 1.8.1
+ * Autotab - jQuery plugin 1.9.0
  * https://github.com/Mathachew/jquery-autotab
  * 
- * Copyright (c) 2008, 2014 Matthew Miller
+ * Copyright (c) 2008, 2015 Matthew Miller
  * 
  * Licensed under the MIT licensing:
  *   http://www.opensource.org/licenses/mit-license.php
  */
 
-(function(e){var t=navigator.platform,g=null,r="iPad"===t||"iPhone"===t||"iPod"===t,v="undefined"!==typeof InstallTrigger,k=function(a,f){if(null!==f&&"undefined"!==typeof f)for(var b in f)e(a).data("autotab-"+b,f[b])},l=function(a){var f={format:"all",loaded:!1,disabled:!1,pattern:null,uppercase:!1,lowercase:!1,nospace:!1,maxlength:2147483647,target:null,previous:null,trigger:null,originalValue:"",changed:!1,editable:"text"==a.type||"password"==a.type||"textarea"==a.type,tabOnSelect:!1};if(!0===
-e.autotab.selectFilterByClass&&"undefined"===typeof e(a).data("autotab-format")){var b="all text alpha number numeric alphanumeric hex hexadecimal custom".split(" "),c;for(c in b)if(e(a).hasClass(b[c])){f.format=b[c];break}}for(c in f)"undefined"!==typeof e(a).data("autotab-"+c)&&(f[c]=e(a).data("autotab-"+c));f.loaded||(null!==f.trigger&&"string"===typeof f.trigger&&(f.trigger=f.trigger.toString()),k(a,f));return f},n=function(a){return"undefined"!==typeof a&&("string"===typeof a||!(a instanceof
-jQuery))};e.autotab=function(a){"object"!==typeof a&&(a={});e(":input").autotab(a)};e.autotab.selectFilterByClass=!1;e.autotab.next=function(){var a=e(document.activeElement);a.length&&a.trigger("autotab-next")};e.autotab.previous=function(){var a=e(document.activeElement);a.length&&a.trigger("autotab-previous")};e.autotab.remove=function(a){n(a)?e(a).autotab("remove"):e(":input").autotab("remove")};e.autotab.restore=function(a){n(a)?e(a).autotab("restore"):e(":input").autotab("restore")};e.autotab.refresh=
-function(a){n(a)?e(a).autotab("refresh"):e(":input").autotab("refresh")};e.fn.autotab=function(a,f){if(!this.length)return this;var b=e.grep(this,function(a,d){return"hidden"!=a.type});if("filter"==a){if("string"===typeof f||"function"===typeof f)f={format:f};for(var c=0,m=b.length;c(new Date).getTime()-g.getTime())return g=null,!1}).on("keypress",function(a){var d=l(this),
-b=a.which||a.keyCode;if(!d||d.disabled||v&&0===a.charCode||a.ctrlKey||a.altKey||13==b||"text"!=this.type&&"password"!=this.type&&"textarea"!=this.type||this.disabled)return!0;b=String.fromCharCode(b);if(null!==d.trigger&&0<=d.trigger.indexOf(b))return null!==g&&800>(new Date).getTime()-g.getTime()?g=null:e(this).trigger("autotab-next",d),!1;g=null;a=document.selection&&document.selection.createRange?!0:0(new Date).getTime()-g.getTime())return g=null,!1}else"range"!==this.type&&"select-one"!==this.type&&"select-multiple"!==this.type&&("tel"!==this.type&&"number"!==this.type||("tel"===this.type||"number"===this.type)&&0==this.value.length)&&(37!=e||c.editable&&0!=b.start?39!=e||c.editable&&c.filterable&&b.end!=this.value.length&&0!=this.value.length||(c.arrowKey=!0,d(this).trigger("autotab-next",
+c)):(c.arrowKey=!0,d(this).trigger("autotab-previous",c)))}).on("keypress.autotab",function(a){var c=l(this),b=a.which||a.keyCode;if(!c||c.disabled||x&&0===a.charCode||a.ctrlKey||a.altKey||13==b||this.disabled)return!0;a=String.fromCharCode(b);if("text"!=this.type&&"password"!=this.type&&"textarea"!=this.type)return this.value.length+1>=c.maxlength&&(c.arrowKey=!1,d(this).trigger("autotab-next",c)),this.value.length!=c.maxlength;if(null!==c.trigger&&0<=c.trigger.indexOf(a))return null!==g&&800>(new Date).getTime()-
+g.getTime()?g=null:(c.arrowKey=!1,d(this).trigger("autotab-next",c)),!1;g=null;b=document.selection&&document.selection.createRange?!0:0
Date: Thu, 29 Jan 2015 23:25:40 -0600
Subject: [PATCH 2/2] Improved support for using the arrow key to navigate
 through elements

Fixed a pasting issue in IE11 where backspacing into a previous element caused the cursor to be placed at the front of the element's value instead of at the end
Changed the behavior of using maxLength so that drop support works properly in IE11, but this may be reverted in a future release
---
 CHANGELOG.md             |  2 +-
 js/jquery.autotab.js     | 47 +++++++++++++++++++++++++++++-----------
 js/jquery.autotab.min.js | 37 ++++++++++++++++---------------
 3 files changed, 54 insertions(+), 32 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0c66ebd..8539566 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,7 +10,7 @@ Features:
 Bug fixes:
 
 * fixed a pasting issue that resulted in a target's value being cleared when no additional characters were being pasted (#72)
-
+* fixed a pasting issue in IE11 where backspacing into a previous element caused the cursor to be placed at the front of the element's value instead of at the end
 
 ## 1.8.1 (2014-11-01)
 
diff --git a/js/jquery.autotab.js b/js/jquery.autotab.js
index 5b63151..7cba3ea 100644
--- a/js/jquery.autotab.js
+++ b/js/jquery.autotab.js
@@ -14,7 +14,8 @@
             tabPause: 800,
             focusChange: null,
             iOS: (platform === 'iPad' || platform === 'iPhone' || platform === 'iPod'),
-            firefox: (typeof InstallTrigger !== 'undefined')
+            firefox: (typeof InstallTrigger !== 'undefined'),
+            ie11: !(window.ActiveXObject) && "ActiveXObject" in window
         };
 
     var setSettings = function (e, settings) {
@@ -428,6 +429,8 @@
             return;
         }
 
+        element.maxLength = 2147483647;
+
         // Add a change event to select lists only so that we can auto tab when a value is selected
         if (element.type == 'select-one') {
             $(element).on('change', function (e) {
@@ -489,7 +492,13 @@
                         previous.trigger('autotab-previous');
                     }
                     else if (value.length && previous.data('autotab-editable') && !defaults.arrowKey) {
-                        previous.focus().val(value.substring(0, value.length - 1));
+                        if (settings.ie11) {
+                            previous.val(value.substring(0, value.length - 1)).focus();
+                        }
+                        else {
+                            previous.focus().val(value.substring(0, value.length - 1));
+                        }
+
                         setSettings(previous, { changed: true });
                     }
                     else {
@@ -497,7 +506,12 @@
                             setSettings(this, { arrowKey: false });
                         }
 
-                        previous.focus();
+                        if (settings.ie11) {
+                            previous.val(value).focus();
+                        }
+                        else {
+                            previous.focus().val(value);
+                        }
                     }
 
                     settings.focusChange = null;
@@ -654,23 +668,22 @@
 
             return false;
         }).on('drop paste', function (e) {
-            var defaults = getSettings(this);
+            var self = this;
 
-            if (!defaults) {
-                return true;
-            }
+            setTimeout(function () {
+                var defaults = getSettings(self);
 
-            this.maxLength = 2147483647;
+                if (!defaults) {
+                    return true;
+                }
 
-            (function (e, originDefaults) {
-                setTimeout(function () {
+                (function (e, originDefaults) {
                     var lastIndex = -1,
                         hiddenInput = document.createElement('input');
                     hiddenInput.type = 'hidden';
                     hiddenInput.value = e.value.toLowerCase();
                     hiddenInput.originalValue = e.value;
 
-                    e.maxLength = originDefaults.maxlength;
                     e.value = filterValue(e, e.value, originDefaults).substr(0, originDefaults.maxlength);
 
                     var handlePaste = function (e, previousValue) {
@@ -706,6 +719,14 @@
                             defaults.arrowKey = false;
                             $(e).trigger('autotab-next', defaults);
 
+                            // Firefox causes all but the first and last elements to retain a select all state, so in order to
+                            // effectively support arrow keys, the starting point of the selection is to the last possible cursor
+                            if (settings.firefox) {
+                                setTimeout(function () {
+                                    e.selectionStart = e.value.length;
+                                }, 1);
+                            }
+
                             if (!settings.iOS) {
                                 handlePaste(defaults.target[0], filteredValue);
                             }
@@ -721,8 +742,8 @@
                             handlePaste(originDefaults.target[0], e.value.toLowerCase());
                         }
                     }
-                }, 1);
-            })(this, defaults);
+                })(self, defaults);
+            }, 1);
         });
     };
 
diff --git a/js/jquery.autotab.min.js b/js/jquery.autotab.min.js
index 96e5a31..45f31da 100644
--- a/js/jquery.autotab.min.js
+++ b/js/jquery.autotab.min.js
@@ -8,21 +8,22 @@
  *   http://www.opensource.org/licenses/mit-license.php
  */
 
-(function(d){var u=navigator.platform,g=null,r="iPad"===u||"iPhone"===u||"iPod"===u,x="undefined"!==typeof InstallTrigger,h=function(a,f){if(null!==f&&"undefined"!==typeof f)for(var b in f)d(a).data("autotab-"+b,f[b])},l=function(a){var f={arrowKey:!1,format:"all",loaded:!1,disabled:!1,pattern:null,uppercase:!1,lowercase:!1,nospace:!1,maxlength:2147483647,target:null,previous:null,trigger:null,originalValue:"",changed:!1,editable:"text"===a.type||"password"===a.type||"textarea"===a.type||"tel"===
-a.type||"number"===a.type||"email"===a.type||"search"===a.type||"url"===a.type,filterable:"text"===a.type||"password"===a.type||"textarea"===a.type,tabOnSelect:!1};if(!0===d.autotab.selectFilterByClass&&"undefined"===typeof d(a).data("autotab-format")){var b="all text alpha number numeric alphanumeric hex hexadecimal custom".split(" "),e;for(e in b)if(d(a).hasClass(b[e])){f.format=b[e];break}}for(e in f)"undefined"!==typeof d(a).data("autotab-"+e)&&(f[e]=d(a).data("autotab-"+e));f.loaded||(null!==
-f.trigger&&"string"===typeof f.trigger&&(f.trigger=f.trigger.toString()),h(a,f));return f},p=function(a){return"undefined"!==typeof a&&("string"===typeof a||!(a instanceof jQuery))},w=function(a){var d=0,b=0,e=0;if("text"===a.type||"password"===a.type||"textarea"===a.type)"number"===typeof a.selectionStart&&"number"===typeof a.selectionEnd?(d=a.selectionStart,b=a.selectionEnd,e=1):document.selection&&document.selection.createRange&&(b=document.selection.createRange(),d=a.createTextRange(),a=a.createTextRange(),
-e=b.getBookmark(),d.moveToBookmark(e),a.setEndPoint("EndToStart",d),d=a.text.length,b=d+b.text.length,e=2);return{start:d,end:b,selectionType:e}};d.autotab=function(a){"object"!==typeof a&&(a={});d(":input").autotab(a)};d.autotab.selectFilterByClass=!1;d.autotab.next=function(){var a=d(document.activeElement);a.length&&a.trigger("autotab-next")};d.autotab.previous=function(){var a=d(document.activeElement);a.length&&a.trigger("autotab-previous")};d.autotab.remove=function(a){p(a)?d(a).autotab("remove"):
-d(":input").autotab("remove")};d.autotab.restore=function(a){p(a)?d(a).autotab("restore"):d(":input").autotab("restore")};d.autotab.refresh=function(a){p(a)?d(a).autotab("refresh"):d(":input").autotab("refresh")};d.fn.autotab=function(a,f){if(!this.length)return this;var b=d.grep(this,function(a,c){return"hidden"!=a.type});if("filter"==a){if("string"===typeof f||"function"===typeof f)f={format:f};for(var e=0,m=b.length;e(new Date).getTime()-g.getTime())return g=null,!1}else"range"!==this.type&&"select-one"!==this.type&&"select-multiple"!==this.type&&("tel"!==this.type&&"number"!==this.type||("tel"===this.type||"number"===this.type)&&0==this.value.length)&&(37!=e||c.editable&&0!=b.start?39!=e||c.editable&&c.filterable&&b.end!=this.value.length&&0!=this.value.length||(c.arrowKey=!0,d(this).trigger("autotab-next",
-c)):(c.arrowKey=!0,d(this).trigger("autotab-previous",c)))}).on("keypress.autotab",function(a){var c=l(this),b=a.which||a.keyCode;if(!c||c.disabled||x&&0===a.charCode||a.ctrlKey||a.altKey||13==b||this.disabled)return!0;a=String.fromCharCode(b);if("text"!=this.type&&"password"!=this.type&&"textarea"!=this.type)return this.value.length+1>=c.maxlength&&(c.arrowKey=!1,d(this).trigger("autotab-next",c)),this.value.length!=c.maxlength;if(null!==c.trigger&&0<=c.trigger.indexOf(a))return null!==g&&800>(new Date).getTime()-
-g.getTime()?g=null:(c.arrowKey=!1,d(this).trigger("autotab-next",c)),!1;g=null;b=document.selection&&document.selection.createRange?!0:0(new Date).getTime()-h.getTime())return h=null,!1}else"range"!==this.type&&"select-one"!==this.type&&"select-multiple"!==this.type&&("tel"!==this.type&&"number"!==this.type||("tel"===this.type||"number"===this.type)&&
+0==this.value.length)&&(37!=e||c.editable&&0!=b.start?39!=e||c.editable&&c.filterable&&b.end!=this.value.length&&0!=this.value.length||(c.arrowKey=!0,d(this).trigger("autotab-next",c)):(c.arrowKey=!0,d(this).trigger("autotab-previous",c)))}).on("keypress.autotab",function(a){var c=l(this),b=a.which||a.keyCode;if(!c||c.disabled||w&&0===a.charCode||a.ctrlKey||a.altKey||13==b||this.disabled)return!0;a=String.fromCharCode(b);if("text"!=this.type&&"password"!=this.type&&"textarea"!=this.type)return this.value.length+
+1>=c.maxlength&&(c.arrowKey=!1,d(this).trigger("autotab-next",c)),this.value.length!=c.maxlength;if(null!==c.trigger&&0<=c.trigger.indexOf(a))return null!==h&&800>(new Date).getTime()-h.getTime()?h=null:(c.arrowKey=!1,d(this).trigger("autotab-next",c)),!1;h=null;b=document.selection&&document.selection.createRange?!0:0