├── CHANGELOG.md
├── README.md
├── angular.html
├── bower.json
├── css
└── screen.css
├── index.html
├── js
├── jquery.autotab.js
└── jquery.autotab.min.js
└── knockout.html
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 1.9.2 (2015-02-20)
2 |
3 | Bug fixes:
4 |
5 | * fixed an issue with input elements that are a button type having their text being overwritten when pasting and modified the demo to test against the bug (#79)
6 | * included a pull request that restores an element's original maxlength value
7 |
8 |
9 | ## 1.9.1 (2015-02-04)
10 |
11 | Bug fixes:
12 |
13 | * reverted a change that caused odd results with an element's maxlength property changed
14 |
15 |
16 | ## 1.9.0 (2015-01-31)
17 |
18 | Features:
19 |
20 | * improved support for other scripts that utilize the key events so as to prevent conflicts from happening
21 | * added support `drop` events, which are handle just like `paste` events (#73)
22 | * added support for tabbing through fields using the left and right arrow keys (#74)
23 | * auto tabbing support added to several input types: tel, number, email, url and search (#75)
24 |
25 | Bug fixes:
26 |
27 | * fixed a pasting issue that resulted in a target's value being cleared when no additional characters were being pasted (#72)
28 | * 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
29 |
30 |
31 | ## 1.8.1 (2014-11-01)
32 |
33 | Features:
34 |
35 | * added support for reusing predefined target/previous selectors for elements
36 |
37 | Bug fixes:
38 |
39 | * fixed the Angular and Knockout demos by properly applying the uppercase filter requirement on the product key example
40 | * removed debugging code
41 |
42 |
43 | ## 1.8.0 (2014-10-28)
44 |
45 | Features:
46 |
47 | * added refresh global method
48 | * updated demo to support removing examples in order to showcase the new refresh feature
49 | * added support for readonly fields
50 | * added support for specifying the filter format through class names based on the value of `$.autotab.selectFilterByClass`
51 | * added demos for Knockout and Angular
52 |
53 | Bug fixes:
54 |
55 | * fixes several issues with handling a pasted value that contained capital letters (#41, #65)
56 | * fixes an issue that caused disabled/readonly fields to be altered when pasting
57 |
58 |
59 | ## 1.7.1 (2014-08-21)
60 |
61 | Bug fixes:
62 |
63 | * fixes an issue when using deprecated methods `autotab_magic` and `autotab_filter` in a method chain
64 |
65 |
66 | ## 1.7 (2014-07-26)
67 |
68 | Features:
69 |
70 | * added support for additional fields and removed hidden fields from the selected elements, including maxlength support for textarea (#14)
71 | * added option to auto tab on single value select lists when selecting a value
72 | * added global methods to setup, remove and restore Autotab
73 | * elements passed to Autotab now filter out hidden form fields
74 |
75 | Bug fixes:
76 |
77 | * fixes an issue with tabbing to a previous field that is disabled, resulting in the value being modified (#47)
78 |
79 |
80 | ## 1.6 (2014-04-30)
81 |
82 | Features:
83 |
84 | * restores the ability to apply a filter only (#36)
85 | * added support to filter and tab on password fields (#36)
86 |
87 |
88 | ## 1.5.5 (2014-01-31)
89 |
90 | Bug fixes:
91 |
92 | * fixes a cursor position issue in IE6+ when replacing the value of a text box that is currently selected (#32)
93 |
94 |
95 | ## 1.5.4 (2014-01-15)
96 |
97 | Features:
98 |
99 | * added a check to apply filtering only to text fields, as support for other input types varies and may not support selection, while preserving auto tabbing functionality
100 |
101 | Bug fixes:
102 |
103 | * fixes an issue with multiple characters appearing after typing one when applying a filter rule more than once
104 | * fixes an issue with maxLength and Firefox, which defaults to -1
105 |
106 |
107 | ## 1.5.3 (2014-01-13)
108 |
109 | Bug fixes:
110 |
111 | * addresses an issue with forms not submitting from the on-screen keyboard (#22)
112 |
113 |
114 | ## 1.5.2 (2014-01-13)
115 |
116 | Bug fixes:
117 |
118 | * refactoring caused filtering rules, like uppercase or lowercase, to not work correctly (#23)
119 |
120 |
121 | ## 1.5.1 (2013-12-17)
122 |
123 | Bug fixes:
124 |
125 | * in Internet Explorer, reaching the max length caused the last character to appear in the target element after auto tabbing (#19)
126 |
127 |
128 | ## 1.5 (2013-12-12)
129 |
130 | Features:
131 |
132 | * added support for auto tabbing by specific keys
133 | * refactored various areas dealing with boolean evaulations and checking for iOS and Firefox
134 |
135 | Bug fixes:
136 |
137 | * fixed a bug that prevented the `change` event from triggering (#17)
138 |
139 |
140 | ## 1.4 (2013-11-12)
141 |
142 | Features:
143 |
144 | * pasting support has been greatly improved and behaves more intelligently
145 | * improved support in Firefox so that special keys no longer have to be tracked in order to be allowed
146 |
147 | Bug fixes:
148 |
149 | * fixed a bug where the `del` key would do nothing in Firefox (introduced in 1.3)
150 | * fixed several instances of bad evaluations of boolean values as a result of browsers storing data-* differently (introduced in 1.3)
151 |
152 |
153 | ## 1.3 (2013-11-09)
154 |
155 | Features:
156 |
157 | * added a 1ms timer to `$.autotab.next()` and `$.autotab.previous()` so that the calls perform as expected when the keypress event is complete
158 | * added the ability to turn auto tab and filtering on or off at will (#4)
159 | * added Firefox detection so that code specific to it can run separate from everything else
160 | * improved support for using a function as the format
161 | * refactored how Autotab's settings are stored as the previous method caused issues with turning it off and on again
162 | * added support for loading filter formats using `data-autotab-format`
163 | * added support for hexadecimal filtering
164 |
165 | Bug fixes:
166 |
167 | * if a selector has no matches, but `.autotab()` is still called, an error would occur
168 | * if allowing periods in a text box, Firefox would display two periods when only one was typed
169 |
170 |
171 | ## 1.2 (2013-11-02)
172 |
173 | Features:
174 |
175 | * updated `autotab()` to be the primary means of setting up auto tabbing and filtering (see documentation for more details)
176 | * greatly improved filtering by preventing illegal characters from appearing by changing `keyup` to `keypress`
177 | * improved functionality when making multiple calls for auto tab and/or filtering that prevents multiple triggers of the auto tabbing and filtering from occuring
178 | * added `$.autotab.next()` and `$.autotab.previous()`, which can be used to manually trigger the `autotab-next` and `autotab-previous` events respectively
179 | * added support to prevent double tabbing using a timer, ie. pressing tab immediately after auto tabbing has occurred
180 | * added basic support for pasting
181 | * improved auto tabbing by moving to the next element when the current one reaches its maxlength while holding down a key
182 | * auto tabbing forward will select the target element's value (#1)
183 | * while auto tabbing does not work on iOS devices, the behavior of the script has improved, including input validation
184 | * fully backwards compatible with Autotab 1.1b
185 |
186 | Bug fixes:
187 |
188 | * if rapidly typing illegal characters, the next element received focused despite the previous element not reaching it's maxlength
189 | * addressed sevearl behavioral issues in some of the latest versions of Firefox
190 |
191 |
192 | ## 1.1b (2008-09-10)
193 |
194 | Features:
195 |
196 | * refactored auto tabbing and filtering functionality so that one or the other could be applied
197 | * added `autotab_magic()`, simplifying the setup of `target` and `previous` elements
198 | * added `custom` format option, which requires a regular expression to be passed in the `pattern` field
199 | * updated `format` to support functions
200 |
201 | Bug fixes:
202 |
203 | * in Safari, pressing backspace in an empty text box would not focus on the `previous` element
204 | * in IE, pressing the left arrow key would force the cursor to the end of the field's content
205 |
206 |
207 | ## 1.0 (2008-05-22)
208 |
209 | Initial Release
210 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | jQuery Autotab
2 | ==============
3 | Autotab is a jQuery plugin that provides auto tabbing and filtering on text fields in a form. Once the maximum number of characters has been reached within a text field, the focus is automatically set to a defined element. Likewise, clearing out the text field's content by pressing backspace eventually places the focus on a previous element.
4 |
5 |
6 | ## Why jQuery Autotab?
7 | * Auto tabbing behaves logically, in both tabbing forward and tabbing backwards.
8 | * Allow your users to easily modify your text in a tab that would otherwise auto tab away.
9 | * Reduce the amount of bad data submitted in a form by filtering text fields.
10 | * Populate multiple text fields by pasting into one.
11 | * Enhance text fields by auto tabbing when a specific character is pressed.
12 | * It is small, fast, easy to load and built on the powerful jQuery library.
13 |
14 |
15 | ## Demo
16 |
17 | Always running the latest and greatest version of Autotab: http://autotab.mathachew.com/
18 |
19 | [Angular](http://autotab.mathachew.com/angular.html) and [Knockout](http://autotab.mathachew.com/knockout.html) demos are also available.
20 |
21 | ## Table of Contents
22 | * [Requirements](#requirements)
23 | * [Installation](#installation)
24 | * [Setup and Usage](#setup-and-usage)
25 | * [Auto Tabbing](#auto-tabbing)
26 | * [Examples](#examples)
27 | * [Remove and Restore](#remove-and-restore)
28 | * [Examples](#examples-1)
29 | * [Filtering](#filtering)
30 | * [Examples](#examples-2)
31 | * [Global Methods](#global-methods)
32 | * [Options](#options)
33 | * [Filter Formats](#filter-formats)
34 | * [Known Issues](#known-issues)
35 | * [Minify](#minify)
36 | * [Feedback](#feedback)
37 | * [Copyright and License](#copyright-and-license)
38 |
39 |
40 | ## Requirements
41 |
42 | Autotab works in both jQuery 1.7+ and 2.x. If your site supports Internet Explorer 6, 7, and/or 8, use jQuery 1.7+ since 2.x drops support for these browsers.
43 |
44 |
45 | ## Installation
46 |
47 | Add a reference to jquery.autotab.js.
48 |
49 | ```html
50 |
51 | ```
52 |
53 |
54 | ## Setup and Usage
55 |
56 | Autotab can be setup in several different ways within jQuery's `$(document).ready()` event. The two components that make up Autotab, auto tabbing and filtering, can be managed independently from one another, providing numerous ways of achieving the same result, depending on how indepth you want to setup your form.
57 |
58 |
59 | ### Auto Tabbing
60 |
61 | __Note:__ If the selector matches multiple elements, the target and previous fields will be overwritten if previously set.
62 |
63 |
64 |
65 |
.autotab()
66 |
Accepts no arguments and applies auto tabbing rules only.
67 |
68 |
69 |
.autotab(string)
70 |
71 | string: Can be a filter format or a value that tells the script to remove or restore auto tab and filtering functionality.
72 |
73 | Note: Previous auto tabbing order will be overwritten. To change the filter only, call .autotab('filter', '')
74 |
75 |
76 |
77 |
.autotab(object)
78 |
object: Applies the specified options to all matched elements.
79 |
80 |
81 |
82 |
83 | #### Examples
84 |
85 | Establishes auto tabbing rules only and forces each field to have a `maxlength` of 1.
86 |
87 | ```js
88 | $('.answer').autotab({ maxlength: 1 });
89 | ```
90 | ```html
91 |
92 |
93 | -
94 |
95 | -
96 |
97 | -
98 |
99 | ```
100 |
101 | Automatically establishes auto tabbing order and number filtering.
102 |
103 | ```js
104 | $('.number').autotab('number');
105 | ```
106 | ```html
107 |
144 | string: Disables auto tab and filtering functionality on all matched elements.
145 |
146 | Note: Both destroy and remove will disable auto tab and filtering. Standard and custom event bindings persist as they check the status of an element when called. Removing the keydown and keypress can have a negative impact in both user and developer experience if the same events have been bound in other areas.
147 |
148 |
149 |
150 |
.autotab('restore|enable')
151 |
152 | string: Restores auto tab and filtering functionality on all matched elements.
153 |
154 |
155 |
156 |
157 |
158 | #### Examples
159 |
160 | Manually turn off auto tab and filtering functionality on all text boxes.
161 |
162 | ```js
163 | $('#remove-autotab').on('click', function () {
164 | $('input[type=text]').autotab('remove');
165 | });
166 | ```
167 | ```html
168 |
169 | ```
170 |
171 | Manually turn on auto tab and filtering functionality on all text boxes.
172 |
173 | ```js
174 | $('#restore-autotab').on('click', function () {
175 | $('input[type=text]').autotab('restore');
176 | });
177 | ```
178 | ```html
179 |
180 | ```
181 |
182 |
183 | ### Filtering
184 |
185 | __Note:__ If passing an object, the target and previous fields are ignored, if included, to preserve previously established auto tab rules. Use `.autotab(object)` to modify the target and previous fields.
186 |
187 |
188 |
189 |
.autotab('filter', string)
190 |
string: Applies the specified filter format to all matched elements.
191 |
192 |
193 |
.autotab('filter', object)
194 |
195 | object: Applies the specified filter options to all matched elements. The target and previous fields are ignored.
196 |
197 |
198 |
199 |
200 | Because of how Autotab's settings are stored, it is possible to define the filter format using `data-autotab-format`. If using `custom`, place your regular expression in `data-autotab-pattern`.
201 |
202 | It is possible to specify the filter through an element's class, using the same names that are available when calling the filter. In order to use this feature, `$.autotab.selectFilterByClass` must be set to true before initializing Autotab.
203 |
204 |
205 | #### Examples
206 |
207 | Manually defines text filtering.
208 |
209 | ```js
210 | $('#salt').autotab('filter', 'text');
211 | ```
212 | ```html
213 |
233 | ```
234 |
235 | Manually defines number filtering via `data-autotab-format`. In this example, `$(selector).autotab()` will take the attribute into account.
236 |
237 | ```html
238 |
239 |
240 | -
241 | -
242 |
243 |
244 | ```
245 |
246 | Other random JavaScript examples
247 |
248 | ```js
249 | $(':input').autotab();
250 | $('#username').autotab({ format: 'alphanumeric', target: '#password' });
251 | $('#password').autotab({ previous: '#username', target: '#confirm' });
252 | $('#product-key').autotab('filter', { format: 'alphanumeric', uppercase: true });
253 | $('#ip-address').autotab('filter', { format: 'custom', pattern: '[^0-9\.]' });
254 | $('#function').autotab('filter', function (text) { alert(text); });
255 | $('#number1, #number2, #number3').autotab('filter', 'number');
256 | $('.ipv6').autotab('filter', 'hexadecimal');
257 | ```
258 |
259 |
260 | ### Global Methods
261 |
262 | Autotab comes with several global methods, which are probably most useful in edge cases.
263 |
264 |
265 |
266 |
$.autotab()
267 |
Initializes Autotab on all elements matching the :input selector.
268 |
269 |
270 |
$.autotab(object)
271 |
object: Applies the specified options to all matched elements.
272 |
273 |
274 |
275 |
276 |
277 |
$.autotab.next()
278 |
279 | Triggers the `autotab-next` event, which sets the focus on the target element, if it exists.
280 |
281 | Note: This method is only useful if an element setup with Autotab has focus.
282 |
283 |
284 |
285 |
$.autotab.previous()
286 |
287 | Triggers the `autotab-previous` event, which sets the focus on the previous element, if it exists.
288 |
289 | Note: This method is only useful if an element setup with Autotab has focus.
290 |
291 |
292 |
293 |
294 |
295 |
$.autotab.remove()
296 |
Removes Autotab from all matched elements.
297 |
298 |
299 |
$.autotab.remove(string)
300 |
string: A selector identifying the matched element(s).
301 |
302 |
303 |
$.autotab.remove(object)
304 |
object: Applies the removal to all matched elements.
305 |
306 |
307 |
308 |
309 |
$.autotab.restore()
310 |
Restores Autotab to all matched elements.
311 |
312 |
313 |
$.autotab.restore(string)
314 |
string: A selector identifying the matched element(s).
315 |
316 |
317 |
$.autotab.restore(object)
318 |
object: Applies restoration to all matched elements.
319 |
320 |
321 |
322 |
323 |
$.autotab.refresh()
324 |
Refreshes the tabbing order on all elements matching the :input selector.
325 |
326 |
327 |
$.autotab.refresh(string)
328 |
string: A selector identifying the matched element(s)
329 |
330 |
331 |
$.autotab.refresh(object)
332 |
object: Refreshes the target/previous values for all matched elements.
333 |
334 |
335 |
336 | Under certain conditions, using refresh may cause an unexpected tabbing order, so the :input selector is recommended.
337 |
362 | string: Speficies which format rule to use on a text box's value.
363 |
364 | function(value, element): If a single regular expression is insufficient, a function can be used for custom formatting. The parameter value is the typed character and element is the focused JavaScript element.
365 |
366 | Note: Go to Filter Formats to see each available format option.
367 |
368 |
369 |
370 |
pattern
371 |
372 | string: Used only when the custom format is specified, and it must be a string.
373 |
374 |
375 |
376 |
uppercase
377 |
378 | boolean: Forces all alpha characters to uppercase format.
379 |
380 |
381 |
382 |
lowercase
383 |
384 | boolean: Forces all alpha characters to lowercase format.
385 |
386 |
387 |
388 |
nospace
389 |
390 | boolean: Determines if spaces are allowed or not.
391 |
392 | Note: Space and underscore are not alpha characters and are not included in the alpha and alphanumeric format options. Use the custom format to allow these characters.
393 |
394 |
395 |
396 |
maxlength
397 |
398 | integer: The maximum number of characters allowed in a text box. Maxlength can be specified with the HTML attribute maxlength.
399 |
400 | Note: The maxlength attribute value can be overwritten if the maxlength field is passed to autotab().
401 |
402 |
403 |
404 |
target
405 |
406 | When auto tabbing occurs, target is the element that will gain focus.
407 |
408 | string: A selector identifying the next element.
409 |
410 | element: The JavaScript or jQuery element.
411 |
412 |
413 |
414 |
previous
415 |
416 | When backspacing or reverse tabbing, previous is the element that will gain focus.
417 |
418 | string: A selector identifying the next element.
419 |
420 | element: The JavaScript or jQuery element.
421 |
422 |
423 |
424 |
425 |
trigger
426 |
427 | Triggers autotab-next when the specified characters are pressed.
428 |
429 | string: A string of one or more characters
430 |
431 | element: An array of one or more strings
432 |
433 |
434 |
435 |
436 |
tabOnSelect
437 |
438 | boolean: Adds auto tabbing to all matched single value select lists.
439 |
440 |
441 |
442 |
443 |
444 | ## Filter Formats
445 |
446 | Autotab has several filter formats available, all passed into the `format` key. If none of the formats meet your needs, Autotab also supports a passing a function or specifying `custom` option where you can pass a regular expression.
447 |
448 |
449 |
450 |
all
451 |
Allows any and all characters.
452 |
453 |
454 |
text
455 |
Allows all characters, including special characters, except numbers.
456 |
457 |
458 |
alpha
459 |
Allows only letters.
460 |
461 |
462 |
number|numeric
463 |
Allows only numbers.
464 |
465 |
466 |
alphanumeric
467 |
Allows only letters and numbers.
468 |
469 |
470 |
hex|hexadecimal
471 |
Allows only letters A-F, a-f and numbers.
472 |
473 |
474 |
475 | custom
476 |
477 |
478 | Allows a developer to provide a custom regular expression: new RegExp(pattern, 'g');
479 |
480 | Note: Requires pattern: string, ie: pattern: "[^0-9\.]"
481 |
482 |
483 |
484 |
function(value, element)
485 |
486 | Allows a developer to provide a their own function in case a regular expression is insufficient.
487 |
488 | Note: value is the typed character, element is the focused JavaScript element.
489 |
Autotab's full documentation can be found in ReadMe.md on GitHub.
78 |
79 |
The purpose of this demo is to provide a proof of concept for dynamically adding or removing fields that are handled through Autotab. Click here to see this using Knockout.
330 | // Note: This call is not necessary as 'all' is the default format
331 | $('.all').autotab('filter', 'all');
332 |
333 |
334 |
335 |
336 |
350 |
351 |
352 |
--------------------------------------------------------------------------------
/js/jquery.autotab.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Autotab - jQuery plugin 1.9.2
3 | * https://github.com/Mathachew/jquery-autotab
4 | *
5 | * Copyright (c) 2008, 2015 Matthew Miller
6 | *
7 | * Licensed under the MIT licensing:
8 | * http://www.opensource.org/licenses/mit-license.php
9 | */
10 |
11 | (function ($) {
12 | var platform = navigator.platform,
13 | settings = {
14 | tabPause: 800,
15 | focusChange: null,
16 | iOS: (platform === 'iPad' || platform === 'iPhone' || platform === 'iPod'),
17 | firefox: (typeof InstallTrigger !== 'undefined'),
18 | ie11: !(window.ActiveXObject) && "ActiveXObject" in window
19 | };
20 |
21 | var setSettings = function (e, settings) {
22 | if (settings === null || typeof settings === 'undefined') {
23 | return;
24 | }
25 |
26 | for (var key in settings) {
27 | $(e).data('autotab-' + key, settings[key]);
28 | }
29 | };
30 |
31 | var getSettings = function (e) {
32 | var settings = {
33 | arrowKey: false,
34 | format: 'all',
35 | loaded: false,
36 | disabled: false,
37 | pattern: null,
38 | uppercase: false,
39 | lowercase: false,
40 | nospace: false,
41 | maxlength: 2147483647,
42 | target: null,
43 | previous: null,
44 | trigger: null,
45 | originalValue: '',
46 | changed: false,
47 | 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'),
48 | filterable: (e.type === 'text' || e.type === 'password' || e.type === 'textarea'),
49 | tabOnSelect: false
50 | };
51 |
52 | // If $.autotab.selectFilterByClas is true and the format not specified, automatically select an element's format based on a matching class name.
53 | // The first matched element becomes the selected format for the filter.
54 | if ($.autotab.selectFilterByClass === true && typeof $(e).data('autotab-format') === 'undefined') {
55 | var classes = ['all', 'text', 'alpha', 'number', 'numeric', 'alphanumeric', 'hex', 'hexadecimal', 'custom'];
56 |
57 | for (var key in classes) {
58 | if ($(e).hasClass(classes[key])) {
59 | settings.format = classes[key];
60 | break;
61 | }
62 | }
63 | }
64 |
65 | for (var key in settings) {
66 | if (typeof $(e).data('autotab-' + key) !== 'undefined') {
67 | settings[key] = $(e).data('autotab-' + key);
68 | }
69 | }
70 |
71 | // Save settings on first run
72 | if (!settings.loaded) {
73 | if (settings.trigger !== null && typeof settings.trigger === 'string') {
74 | settings.trigger = settings.trigger.toString();
75 | }
76 |
77 | setSettings(e, settings);
78 | }
79 |
80 | return settings;
81 | };
82 |
83 | var queryObject = function (e) {
84 | return (typeof e !== 'undefined' && (typeof e === 'string' || !(e instanceof jQuery)));
85 | };
86 |
87 | var getSelection = function (e) {
88 | var start = 0,
89 | end = 0,
90 | selectionType = 0;
91 |
92 | if (e.type === 'text' || e.type === 'password' || e.type === 'textarea') {
93 | if (typeof e.selectionStart === 'number' && typeof e.selectionEnd === 'number') {
94 | // Non-IE browsers and IE 9+
95 | start = e.selectionStart;
96 | end = e.selectionEnd;
97 | selectionType = 1;
98 | }
99 | else if (document.selection && document.selection.createRange) {
100 | // For IE up to version 8
101 | var selectionRange = document.selection.createRange(),
102 | textInputRange = e.createTextRange(),
103 | precedingRange = e.createTextRange(),
104 | bookmark = selectionRange.getBookmark();
105 | textInputRange.moveToBookmark(bookmark);
106 | precedingRange.setEndPoint("EndToStart", textInputRange);
107 | start = precedingRange.text.length;
108 | end = start + selectionRange.text.length;
109 | selectionType = 2;
110 | }
111 | }
112 |
113 | return {
114 | start: start,
115 | end: end,
116 | selectionType: selectionType
117 | };
118 | };
119 |
120 | $.autotab = function (options) {
121 | if (typeof options !== 'object') {
122 | options = {};
123 | }
124 |
125 | $(':input').autotab(options);
126 | };
127 |
128 | $.autotab.selectFilterByClass = false;
129 |
130 | $.autotab.next = function () {
131 | var e = $(document.activeElement);
132 |
133 | if (e.length) {
134 | e.trigger('autotab-next');
135 | }
136 | };
137 |
138 | $.autotab.previous = function () {
139 | var e = $(document.activeElement);
140 |
141 | if (e.length) {
142 | e.trigger('autotab-previous');
143 | }
144 | };
145 |
146 | $.autotab.remove = function (e) {
147 | queryObject(e) ? $(e).autotab('remove') : $(':input').autotab('remove');
148 | };
149 |
150 | $.autotab.restore = function (e) {
151 | queryObject(e) ? $(e).autotab('restore') : $(':input').autotab('restore');
152 | };
153 |
154 | $.autotab.refresh = function (e) {
155 | queryObject(e) ? $(e).autotab('refresh') : $(':input').autotab('refresh');
156 | };
157 |
158 | $.fn.autotab = function (method, options) {
159 | if (!this.length) {
160 | return this;
161 | }
162 |
163 | // Remove hidden fields since tabbing backwards is supported on different form elements
164 | var filtered = $.grep(this, function (e, i) {
165 | return e.type != 'hidden';
166 | });
167 |
168 | // Apply filter options
169 | if (method == 'filter') {
170 | if (typeof options === 'string' || typeof options === 'function') {
171 | options = { format: options };
172 | }
173 |
174 | for (var i = 0, length = filtered.length; i < length; i++) {
175 | var defaults = getSettings(filtered[i]),
176 | newOptions = options;
177 |
178 | // Retain the established target/previous values as this area is for filtering only
179 | newOptions.target = defaults.target;
180 | newOptions.previous = defaults.previous;
181 |
182 | $.extend(defaults, newOptions);
183 |
184 | if (!defaults.loaded) {
185 | defaults.disabled = true;
186 | autotabBind(filtered[i], newOptions);
187 | }
188 | else {
189 | setSettings(filtered[i], defaults);
190 | }
191 | }
192 | }
193 | // Disable auto tab and filtering
194 | else if (method == 'remove' || method == 'destroy' || method == 'disable') {
195 | for (var i = 0, length = filtered.length; i < length; i++) {
196 | var defaults = getSettings(filtered[i]);
197 |
198 | defaults.disabled = true;
199 |
200 | setSettings(filtered[i], defaults);
201 | }
202 | }
203 | // Re-enable auto tab and filtering
204 | else if (method == 'restore' || method == 'enable') {
205 | for (var i = 0, length = filtered.length; i < length; i++) {
206 | var defaults = getSettings(filtered[i]);
207 |
208 | defaults.disabled = false;
209 |
210 | setSettings(filtered[i], defaults);
211 | }
212 | }
213 | // Refresh target/previous elements
214 | else if (method == 'refresh') {
215 | for (var i = 0, length = filtered.length; i < length; i++) {
216 | var defaults = getSettings(filtered[i]),
217 | n = i + 1,
218 | p = i - 1,
219 | selectTarget = function () {
220 | if (i > 0 && n < length) {
221 | defaults.target = filtered[n];
222 | }
223 | else if (i > 0) {
224 | defaults.target = null;
225 | }
226 | else {
227 | defaults.target = filtered[n];
228 | }
229 | },
230 | selectPrevious = function () {
231 | if (i > 0 && n < length) {
232 | defaults.previous = filtered[p];
233 | }
234 | else if (i > 0) {
235 | defaults.previous = filtered[p];
236 | }
237 | else {
238 | defaults.previous = null;
239 | }
240 | };
241 |
242 | // Nothing was specified for the target element, so automatically set it
243 | if (defaults.target === null || defaults.target.selector === '') {
244 | selectTarget();
245 | }
246 | else if (typeof defaults.target === 'string' || defaults.target.selector) {
247 | defaults.target = $(typeof defaults.target === 'string' ? defaults.target : defaults.target.selector);
248 |
249 | if (defaults.target.length === 0) {
250 | selectTarget();
251 | }
252 | }
253 |
254 | // Nothing was specified for the previous element, so automatically set it
255 | if (defaults.previous === null || defaults.previous.selector === '') {
256 | selectPrevious();
257 | }
258 | else if (typeof defaults.previous === 'string' || defaults.previous.selector) {
259 | defaults.previous = $(typeof defaults.previous === 'string' ? defaults.previous : defaults.previous.selector);
260 |
261 | if (defaults.previous.length === 0) {
262 | selectPrevious();
263 | }
264 | }
265 |
266 | if (!defaults.loaded) {
267 | autotabBind(filtered[i], defaults);
268 | }
269 | else {
270 | if (queryObject(defaults.target)) {
271 | defaults.target = $(defaults.target);
272 | }
273 |
274 | if (queryObject(defaults.previous)) {
275 | defaults.previous = $(defaults.previous);
276 | }
277 |
278 | setSettings(filtered[i], defaults);
279 | }
280 | }
281 | }
282 | else {
283 | if (method === null || typeof method === 'undefined') {
284 | options = {};
285 | }
286 | else if (typeof method === 'string' || typeof method === 'function') {
287 | options = { format: method };
288 | }
289 | else if (typeof method === 'object') {
290 | options = method;
291 | }
292 |
293 | // Bind key events to element(s) passed
294 | if (filtered.length > 1) {
295 | for (var i = 0, length = filtered.length; i < length; i++) {
296 | var n = i + 1,
297 | p = i - 1,
298 | newOptions = options;
299 |
300 | if (i > 0 && n < length) {
301 | newOptions.target = filtered[n];
302 | newOptions.previous = filtered[p];
303 | }
304 | else if (i > 0) {
305 | newOptions.target = null;
306 | newOptions.previous = filtered[p];
307 | }
308 | else {
309 | newOptions.target = filtered[n];
310 | newOptions.previous = null;
311 | }
312 |
313 | autotabBind(filtered[i], newOptions);
314 | }
315 | }
316 | else {
317 | autotabBind(filtered[0], options);
318 | }
319 | }
320 |
321 | return this;
322 | };
323 |
324 | var filterValue = function (e, value, defaults) {
325 | if (typeof defaults.format === 'function') {
326 | return defaults.format(value, e);
327 | }
328 |
329 | var pattern = null;
330 |
331 | switch (defaults.format) {
332 | case 'text':
333 | pattern = new RegExp('[0-9]+', 'g');
334 | break;
335 |
336 | case 'alpha':
337 | pattern = new RegExp('[^a-zA-Z]+', 'g');
338 | break;
339 |
340 | case 'number':
341 | case 'numeric':
342 | pattern = new RegExp('[^0-9]+', 'g');
343 | break;
344 |
345 | case 'alphanumeric':
346 | pattern = new RegExp('[^0-9a-zA-Z]+', 'g');
347 | break;
348 |
349 | case 'hex':
350 | case 'hexadecimal':
351 | pattern = new RegExp('[^0-9A-Fa-f]+', 'g');
352 | break;
353 |
354 | case 'custom':
355 | pattern = new RegExp(defaults.pattern, 'g');
356 | break;
357 |
358 | case 'all':
359 | default:
360 | break;
361 | }
362 |
363 | if (pattern !== null) {
364 | value = value.replace(pattern, '');
365 | }
366 |
367 | if (defaults.nospace) {
368 | pattern = new RegExp('[ ]+', 'g');
369 | value = value.replace(pattern, '');
370 | }
371 |
372 | if (defaults.uppercase) {
373 | value = value.toUpperCase();
374 | }
375 |
376 | if (defaults.lowercase) {
377 | value = value.toLowerCase();
378 | }
379 |
380 | return value;
381 | };
382 |
383 | var autotabBind = function (element, options) {
384 | var defaults = getSettings(element);
385 |
386 | if (defaults.disabled) {
387 | defaults.disabled = false;
388 | defaults.target = null;
389 | defaults.previous = null;
390 | }
391 |
392 | $.extend(defaults, options);
393 |
394 | // Sets targets to element based on the name or ID passed if they are not currently objects
395 | if (queryObject(defaults.target)) {
396 | defaults.target = $(defaults.target);
397 | }
398 |
399 | if (queryObject(defaults.previous)) {
400 | defaults.previous = $(defaults.previous);
401 | }
402 |
403 | var oldMaxlength = element.maxLength;
404 |
405 | if (typeof element.maxLength === 'undefined' && element.type == 'textarea') {
406 | oldMaxlength = element.maxLength = element.getAttribute('maxlength');
407 | }
408 |
409 | // defaults.maxlength has not changed and maxlength was specified
410 | if (defaults.maxlength == 2147483647 && oldMaxlength != 2147483647 && oldMaxlength != -1) {
411 | defaults.maxlength = oldMaxlength;
412 | }
413 | // defaults.maxlength overrides maxlength
414 | else if (defaults.maxlength > 0) {
415 | element.maxLength = defaults.maxlength;
416 | }
417 | // defaults.maxlength and maxlength have not been specified
418 | // A target cannot be used since there is no defined maxlength
419 | else {
420 | defaults.target = null;
421 | }
422 |
423 | if (!defaults.loaded) {
424 | defaults.loaded = true;
425 | setSettings(element, defaults);
426 | }
427 | else {
428 | setSettings(element, defaults);
429 | return;
430 | }
431 |
432 | // Add a change event to select lists only so that we can auto tab when a value is selected
433 | if (element.type == 'select-one') {
434 | $(element).on('change', function (e) {
435 | var defaults = getSettings(this);
436 |
437 | if (defaults.tabOnSelect) {
438 | $(this).trigger('autotab-next');
439 | }
440 | });
441 | }
442 |
443 | // The 1ms timeouts allow for keypress events to complete in case a
444 | // custom function or exterior method calls for a manual auto tab
445 | $(element).on('autotab-next', function (event, defaults) {
446 | var self = this;
447 | setTimeout(function () {
448 | if (!defaults) {
449 | defaults = getSettings(self);
450 | }
451 |
452 | var target = defaults.target;
453 |
454 | if (!defaults.disabled && target.length) {
455 | // Using focus on iOS devices is a pain, so use the browser's next/previous buttons to proceed
456 | if (!settings.iOS) {
457 |
458 | // Field is disabled/readonly, so tab to next element
459 | if (target.prop('disabled') || target.prop('readonly')) {
460 | target.trigger('autotab-next');
461 | }
462 | else {
463 | // Allows the user to navigate between each charater with arrow keys
464 | if (defaults.arrowKey) {
465 | target.focus();
466 | }
467 | else {
468 | target.focus().select();
469 | }
470 | }
471 |
472 | settings.focusChange = new Date();
473 | }
474 | }
475 | }, 1);
476 | }).on('autotab-previous', function (event, defaults) {
477 | var self = this;
478 | setTimeout(function () {
479 | if (!defaults) {
480 | defaults = getSettings(self);
481 | }
482 |
483 | var previous = defaults.previous;
484 |
485 | if (!defaults.disabled && previous.length) {
486 | var value = previous.val();
487 |
488 | // Field is disabled/readonly, so tab to previous element
489 | if (previous.prop('disabled') || previous.prop('readonly')) {
490 | previous.trigger('autotab-previous');
491 | }
492 | else if (value.length && previous.data('autotab-editable') && !defaults.arrowKey) {
493 | if (settings.ie11) {
494 | previous.val(value.substring(0, value.length - 1)).focus();
495 | }
496 | else {
497 | previous.focus().val(value.substring(0, value.length - 1));
498 | }
499 |
500 | setSettings(previous, { changed: true });
501 | }
502 | else {
503 | if (defaults.arrowKey) {
504 | setSettings(this, { arrowKey: false });
505 | }
506 |
507 | if (settings.ie11) {
508 | previous.val(value).focus();
509 | }
510 | else {
511 | previous.focus().val(value);
512 | }
513 | }
514 |
515 | settings.focusChange = null;
516 | }
517 | }, 1);
518 | }).on('focus', function () {
519 | setSettings(this, { originalValue: this.value });
520 | }).on('blur', function () {
521 | var defaults = getSettings(this);
522 |
523 | if (defaults.changed && this.value != defaults.originalValue) {
524 | setSettings(this, { changed: false });
525 | $(this).change();
526 | }
527 | }).on('keydown.autotab', function (e) {
528 | var defaults = getSettings(this);
529 |
530 | if (!defaults || defaults.disabled) {
531 | return true;
532 | }
533 |
534 | var selection = getSelection(this),
535 | keyCode = e.which || e.charCode;
536 |
537 | // Go to the previous element when backspace
538 | // is pressed in an empty input field
539 | if (keyCode == 8) {
540 | defaults.arrowKey = false;
541 |
542 | // Prevent the browser from of navigating to the previous page
543 | if (!defaults.editable) {
544 | $(this).trigger('autotab-previous', defaults);
545 | return false;
546 | }
547 |
548 | setSettings(this, { changed: (this.value !== defaults.originalValue) });
549 |
550 | if (this.value.length === 0) {
551 | $(this).trigger('autotab-previous', defaults);
552 | return;
553 | }
554 | }
555 | else if (keyCode == 9 && settings.focusChange !== null) {
556 | // Tab backwards
557 | if (e.shiftKey) {
558 | settings.focusChange = null;
559 | return;
560 | }
561 |
562 | if ((new Date().getTime() - settings.focusChange.getTime()) < settings.tabPause) {
563 | settings.focusChange = null;
564 | return false;
565 | }
566 | }
567 | else if (this.type !== 'range' && this.type !== 'select-one' && this.type !== 'select-multiple') {
568 | if ((this.type !== 'tel' && this.type !== 'number') || ((this.type === 'tel' || this.type === 'number') && this.value.length == 0)) {
569 | if (keyCode == 37 && (!defaults.editable || selection.start == 0)) {
570 | defaults.arrowKey = true;
571 | $(this).trigger('autotab-previous', defaults);
572 | }
573 | else if (keyCode == 39 && (!defaults.editable || !defaults.filterable || selection.end == this.value.length || this.value.length == 0)) {
574 | defaults.arrowKey = true;
575 | $(this).trigger('autotab-next', defaults);
576 | }
577 | }
578 | }
579 | }).on('keypress.autotab', function (e) {
580 | var defaults = getSettings(this),
581 | keyCode = e.which || e.keyCode;
582 |
583 | // e.charCode == 0 indicates a special key has been pressed, which only Firefox triggers
584 | if (!defaults || defaults.disabled || (settings.firefox && e.charCode === 0) || e.ctrlKey || e.altKey || keyCode == 13 || this.disabled) {
585 | return true;
586 | }
587 |
588 | var keyChar = String.fromCharCode(keyCode);
589 |
590 | if (this.type != 'text' && this.type != 'password' && this.type != 'textarea') {
591 | // this.value.length is the length before the keypress event was trigged
592 | if ((this.value.length + 1) >= defaults.maxlength) {
593 | defaults.arrowKey = false;
594 | $(this).trigger('autotab-next', defaults);
595 | }
596 |
597 | return !(this.value.length == defaults.maxlength);
598 | }
599 |
600 | // Prevents auto tabbing when defaults.trigger is pressed
601 | if (defaults.trigger !== null && defaults.trigger.indexOf(keyChar) >= 0) {
602 | if (settings.focusChange !== null && (new Date().getTime() - settings.focusChange.getTime()) < settings.tabPause) {
603 | settings.focusChange = null;
604 | }
605 | else {
606 | defaults.arrowKey = false;
607 | $(this).trigger('autotab-next', defaults);
608 | }
609 |
610 | return false;
611 | }
612 |
613 | settings.focusChange = null;
614 |
615 | var hasValue = document.selection && document.selection.createRange ? true : (keyCode > 0);
616 |
617 | keyChar = filterValue(this, keyChar, defaults);
618 |
619 | if (hasValue && (keyChar === null || keyChar === '')) {
620 | return false;
621 | }
622 |
623 | // Many, many thanks to Tim Down for this solution: http://stackoverflow.com/a/3923320/94656
624 | if (hasValue && (this.value.length <= this.maxLength)) {
625 | var selection = getSelection(this);
626 |
627 | // Text is fully selected, so it needs to be replaced
628 | if (selection.start === 0 && selection.end == this.value.length) {
629 | this.value = keyChar;
630 | setSettings(this, { changed: (this.value != defaults.originalValue) });
631 | }
632 | else {
633 | if (this.value.length == this.maxLength && selection.start === selection.end) {
634 | defaults.arrowKey = false;
635 | $(this).trigger('autotab-next', defaults);
636 | return false;
637 | }
638 |
639 | this.value = this.value.slice(0, selection.start) + keyChar + this.value.slice(selection.end);
640 | setSettings(this, { changed: (this.value != defaults.originalValue) });
641 | }
642 |
643 | // Prevents the cursor position from being set to the end of the text box
644 | // This is called even if the text is fully selected and replaced due to an unexpected behavior in IE6 and up (#32)
645 | if (this.value.length != defaults.maxlength) {
646 | selection.start++;
647 |
648 | if (selection.selectionType == 1) {
649 | this.selectionStart = this.selectionEnd = selection.start;
650 | }
651 | else if (selection.selectionType == 2) {
652 | var range = this.createTextRange();
653 | range.collapse(true);
654 | range.moveEnd('character', selection.start);
655 | range.moveStart('character', selection.start);
656 | range.select();
657 | }
658 | }
659 | }
660 |
661 |
662 | if (this.value.length == defaults.maxlength) {
663 | defaults.arrowKey = false;
664 | $(this).trigger('autotab-next', defaults);
665 | }
666 |
667 | return false;
668 | }).on('drop paste', function (e) {
669 | var defaults = getSettings(this);
670 |
671 | if (!defaults) {
672 | return true;
673 | }
674 |
675 | this.maxLength = 2147483647;
676 |
677 | (function (e, originDefaults) {
678 | setTimeout(function () {
679 | var lastIndex = -1,
680 | hiddenInput = document.createElement('input');
681 | hiddenInput.type = 'hidden';
682 | hiddenInput.value = e.value.toLowerCase();
683 | hiddenInput.originalValue = e.value;
684 |
685 | e.value = filterValue(e, e.value, originDefaults).substr(0, originDefaults.maxlength);
686 |
687 | var handlePaste = function (e, previousValue) {
688 | if (!e) {
689 | return;
690 | }
691 |
692 | var defaults = getSettings(e);
693 |
694 | if ($(e).prop('disabled') || $(e).prop('readonly') || !defaults.editable) {
695 | $(e).trigger('autotab-next');
696 |
697 | if (!settings.iOS) {
698 | handlePaste(defaults.target[0], previousValue);
699 | }
700 | return;
701 | }
702 |
703 | for (var i = 0, count = previousValue.length; i < count; i++) {
704 | lastIndex = hiddenInput.value.indexOf(previousValue.charAt(i).toLowerCase(), lastIndex) + 1;
705 | }
706 |
707 | var trimmedValue = hiddenInput.originalValue.substr(lastIndex),
708 | filteredValue = filterValue(e, trimmedValue, defaults).substr(0, defaults.maxlength);
709 |
710 | if (!filteredValue) {
711 | return;
712 | }
713 |
714 | e.value = filteredValue;
715 |
716 | if (filteredValue.length == defaults.maxlength) {
717 | defaults.arrowKey = false;
718 | $(e).trigger('autotab-next', defaults);
719 |
720 | // Firefox causes all but the first and last elements to retain a select all state, so in order to
721 | // effectively support arrow keys, the starting point of the selection is to the last possible cursor
722 | if (settings.firefox) {
723 | setTimeout(function () {
724 | e.selectionStart = e.value.length;
725 | }, 1);
726 | }
727 |
728 | if (!settings.iOS) {
729 | handlePaste(defaults.target[0], filteredValue);
730 | }
731 | }
732 |
733 | };
734 |
735 | if (e.value.length == originDefaults.maxlength) {
736 | defaults.arrowKey = false;
737 | $(e).trigger('autotab-next', defaults);
738 |
739 | if (!settings.iOS) {
740 | handlePaste(originDefaults.target[0], e.value.toLowerCase());
741 | }
742 | }
743 |
744 | e.maxLength = originDefaults.maxlength;
745 | }, 1);
746 | })(this, defaults);
747 | });
748 | };
749 |
750 | // Deprecated, here for backwards compatibility
751 | $.fn.autotab_magic = function (focus) {
752 | return $(this).autotab();
753 | };
754 | $.fn.autotab_filter = function (options) {
755 | var defaults = {};
756 |
757 | if (typeof options === 'string' || typeof options === 'function') {
758 | defaults.format = options;
759 | }
760 | else {
761 | $.extend(defaults, options);
762 | }
763 |
764 | return $(this).autotab('filter', defaults);
765 | };
766 |
767 | })(jQuery);
--------------------------------------------------------------------------------
/js/jquery.autotab.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Autotab - jQuery plugin 1.9.2
3 | * https://github.com/Mathachew/jquery-autotab
4 | *
5 | * Copyright (c) 2008, 2015 Matthew Miller
6 | *
7 | * Licensed under the MIT licensing:
8 | * http://www.opensource.org/licenses/mit-license.php
9 | */
10 |
11 | (function(d){var u=navigator.platform,g=null,r="iPad"===u||"iPhone"===u||"iPod"===u,w="undefined"!==typeof InstallTrigger,x=!window.ActiveXObject&&"ActiveXObject"in window,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||
12 | "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)&&
13 | (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))},y=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(),
14 | 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=
15 | 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=
24 | !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!==g&&800>(new Date).getTime()-
25 | g.getTime()?g=null:(c.arrowKey=!1,d(this).trigger("autotab-next",c)),!1;g=null;b=document.selection&&document.selection.createRange?!0:0
2 |
3 |
4 |
5 | jQuery Autotab Demo with Knockout
6 |
7 |
8 |
9 |
10 |
11 |
95 |
96 |
97 |
98 |
99 |
jQuery Autotab Demo with Knockout
100 |
Autotab's full documentation can be found in ReadMe.md on GitHub.
101 |
102 |
The purpose of this demo is to provide a proof of concept for dynamically adding or removing fields that are handled through Autotab. Click here to see this using Angular.
103 |
104 |
Note: There is the possibility of having an unexpected tabbing order if you specify the target/previous elements with Knockout, so it is recommended that you use the default :input selector instead.