jquery-inputmask-rails 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,93 @@
1
+ /*
2
+ Input Mask plugin extensions
3
+ http://github.com/RobinHerbots/jquery.inputmask
4
+ Copyright (c) 2010 - 2013 Robin Herbots
5
+ Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
6
+ Version: 1.2.3
7
+
8
+ Optional extensions on the jquery.inputmask base
9
+ */
10
+ (function ($) {
11
+ //extra definitions
12
+ $.extend($.inputmask.defaults.definitions, {
13
+ 'A': { //auto uppercasing
14
+ validator: "[A-Za-z]",
15
+ cardinality: 1,
16
+ casing: "upper"
17
+ }
18
+ });
19
+ $.extend($.inputmask.defaults.aliases, {
20
+ 'url': {
21
+ mask: "ir",
22
+ placeholder: "",
23
+ separator: "",
24
+ defaultPrefix: "http://",
25
+ regex: {
26
+ urlpre1: new RegExp("[fh]"),
27
+ urlpre2: new RegExp("(ft|ht)"),
28
+ urlpre3: new RegExp("(ftp|htt)"),
29
+ urlpre4: new RegExp("(ftp:|http|ftps)"),
30
+ urlpre5: new RegExp("(ftp:/|ftps:|http:|https)"),
31
+ urlpre6: new RegExp("(ftp://|ftps:/|http:/|https:)"),
32
+ urlpre7: new RegExp("(ftp://|ftps://|http://|https:/)"),
33
+ urlpre8: new RegExp("(ftp://|ftps://|http://|https://)")
34
+ },
35
+ definitions: {
36
+ 'i': {
37
+ validator: function (chrs, buffer, pos, strict, opts) {
38
+ return true;
39
+ },
40
+ cardinality: 8,
41
+ prevalidator: (function () {
42
+ var result = [], prefixLimit = 8;
43
+ for (var i = 0; i < prefixLimit; i++) {
44
+ result[i] = (function () {
45
+ var j = i;
46
+ return {
47
+ validator: function (chrs, buffer, pos, strict, opts) {
48
+ if (opts.regex["urlpre" + (j + 1)]) {
49
+ var tmp = chrs, k;
50
+ if (((j + 1) - chrs.length) > 0) {
51
+ tmp = buffer.join('').substring(0, ((j + 1) - chrs.length)) + "" + tmp;
52
+ }
53
+ var isValid = opts.regex["urlpre" + (j + 1)].test(tmp);
54
+ if (!strict && !isValid) {
55
+ pos = pos - j;
56
+ for (k = 0; k < opts.defaultPrefix.length; k++) {
57
+ buffer[pos] = opts.defaultPrefix[k]; pos++;
58
+ }
59
+ for (k = 0; k < tmp.length - 1; k++) {
60
+ buffer[pos] = tmp[k]; pos++;
61
+ }
62
+ return { "pos": pos };
63
+ }
64
+ return isValid;
65
+ } else {
66
+ return false;
67
+ }
68
+ }, cardinality: j
69
+ };
70
+ })();
71
+ }
72
+ return result;
73
+ })()
74
+ }
75
+ },
76
+ insertMode: false,
77
+ autoUnmask: false
78
+ },
79
+ "ip": {
80
+ mask: "i.i.i.i",
81
+ definitions: {
82
+ 'i': {
83
+ validator: "25[0-5]|2[0-4][0-9]|[01][0-9][0-9]",
84
+ cardinality: 3,
85
+ prevalidator: [
86
+ { validator: "[0-2]", cardinality: 1 },
87
+ { validator: "2[0-5]|[01][0-9]", cardinality: 2 },
88
+ ]
89
+ }
90
+ }
91
+ }
92
+ });
93
+ })(jQuery);
@@ -0,0 +1,1202 @@
1
+ /**
2
+ * @license Input Mask plugin for jquery
3
+ * http://github.com/RobinHerbots/jquery.inputmask
4
+ * Copyright (c) 2010 - 2013 Robin Herbots
5
+ * Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
6
+ * Version: 2.1.0
7
+ */
8
+
9
+ (function ($) {
10
+ if ($.fn.inputmask == undefined) {
11
+ $.inputmask = {
12
+ //options default
13
+ defaults: {
14
+ placeholder: "_",
15
+ optionalmarker: {
16
+ start: "[",
17
+ end: "]"
18
+ },
19
+ escapeChar: "\\",
20
+ mask: null,
21
+ oncomplete: $.noop, //executes when the mask is complete
22
+ onincomplete: $.noop, //executes when the mask is incomplete and focus is lost
23
+ oncleared: $.noop, //executes when the mask is cleared
24
+ repeat: 0, //repetitions of the mask
25
+ greedy: true, //true: allocated buffer for the mask and repetitions - false: allocate only if needed
26
+ autoUnmask: false, //automatically unmask when retrieving the value with $.fn.val or value if the browser supports __lookupGetter__ or getOwnPropertyDescriptor
27
+ clearMaskOnLostFocus: true,
28
+ insertMode: true, //insert the input or overwrite the input
29
+ clearIncomplete: false, //clear the incomplete input on blur
30
+ aliases: {}, //aliases definitions => see jquery.inputmask.extensions.js
31
+ onKeyUp: $.noop, //override to implement autocomplete on certain keys for example
32
+ onKeyDown: $.noop, //override to implement autocomplete on certain keys for example
33
+ showMaskOnHover: true, //show the mask-placeholder when hovering the empty input
34
+ onKeyValidation: $.noop, //executes on every key-press with the result of isValid
35
+ skipOptionalPartCharacter: " ", //a character which can be used to skip an optional part of a mask
36
+ //numeric basic properties
37
+ numericInput: false, //numericInput input direction style (input shifts to the left while holding the caret position)
38
+ radixPoint: ".", // | ","
39
+ //numeric basic properties
40
+ definitions: {
41
+ '9': {
42
+ validator: "[0-9]",
43
+ cardinality: 1
44
+ },
45
+ 'a': {
46
+ validator: "[A-Za-z\u0410-\u044F\u0401\u0451]",
47
+ cardinality: 1
48
+ },
49
+ '*': {
50
+ validator: "[A-Za-z\u0410-\u044F\u0401\u04510-9]",
51
+ cardinality: 1
52
+ }
53
+ },
54
+ keyCode: {
55
+ ALT: 18, BACKSPACE: 8, CAPS_LOCK: 20, COMMA: 188, COMMAND: 91, COMMAND_LEFT: 91, COMMAND_RIGHT: 93, CONTROL: 17, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, INSERT: 45, LEFT: 37, MENU: 93, NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, NUMPAD_ENTER: 108,
56
+ NUMPAD_MULTIPLY: 106, NUMPAD_SUBTRACT: 109, PAGE_DOWN: 34, PAGE_UP: 33, PERIOD: 190, RIGHT: 39, SHIFT: 16, SPACE: 32, TAB: 9, UP: 38, WINDOWS: 91
57
+ }
58
+ },
59
+ val: $.fn.val, //store the original jquery val function
60
+ escapeRegex: function (str) {
61
+ var specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'];
62
+ return str.replace(new RegExp('(\\' + specials.join('|\\') + ')', 'gim'), '\\$1');
63
+ }
64
+ };
65
+
66
+ $.fn.inputmask = function (fn, options) {
67
+ var opts = $.extend(true, {}, $.inputmask.defaults, options);
68
+ var pasteEvent = isInputEventSupported('paste') ? 'paste' : 'input';
69
+
70
+ var iphone = navigator.userAgent.match(/iphone/i) != null;
71
+ var android = navigator.userAgent.match(/android.*mobile safari.*/i) != null;
72
+ if (android) {
73
+ var browser = navigator.userAgent.match(/mobile safari.*/i);
74
+ var version = parseInt(new RegExp(/[0-9]+/).exec(browser));
75
+ android = version <= 533;
76
+ }
77
+ var caretposCorrection = null;
78
+ var masksets,
79
+ activeMasksetIndex = 0;
80
+
81
+ if (typeof fn == "string") {
82
+ switch (fn) {
83
+ case "mask":
84
+ masksets = generateMaskSets();
85
+
86
+ return this.each(function () {
87
+ mask(this);
88
+ });
89
+ break;
90
+ case "unmaskedvalue":
91
+ masksets = this.data('inputmask')['masksets'];
92
+ activeMasksetIndex = this.data('inputmask')['activeMasksetIndex'];
93
+ opts.greedy = this.data('inputmask')['greedy'];
94
+ opts.repeat = this.data('inputmask')['repeat'];
95
+ opts.definitions = this.data('inputmask')['definitions'];
96
+ return unmaskedvalue(this);
97
+ break;
98
+ case "remove":
99
+ return this.each(function () {
100
+ var $input = $(this), input = this;
101
+ setTimeout(function () {
102
+ if ($input.data('inputmask')) {
103
+ masksets = $input.data('inputmask')['masksets'];
104
+ activeMasksetIndex = $input.data('inputmask')['activeMasksetIndex'];
105
+ opts.greedy = $input.data('inputmask')['greedy'];
106
+ opts.repeat = $input.data('inputmask')['repeat'];
107
+ opts.definitions = $input.data('inputmask')['definitions'];
108
+ //writeout the unmaskedvalue
109
+ input._valueSet(unmaskedvalue($input, true));
110
+ //clear data
111
+ $input.removeData('inputmask');
112
+ //unbind all events
113
+ $input.unbind(".inputmask");
114
+ $input.removeClass('focus.inputmask');
115
+ //restore the value property
116
+ var valueProperty;
117
+ if (Object.getOwnPropertyDescriptor)
118
+ valueProperty = Object.getOwnPropertyDescriptor(input, "value");
119
+ if (valueProperty && valueProperty.get) {
120
+ if (input._valueGet) {
121
+ Object.defineProperty(input, "value", {
122
+ get: input._valueGet,
123
+ set: input._valueSet
124
+ });
125
+ }
126
+ } else if (document.__lookupGetter__ && input.__lookupGetter__("value")) {
127
+ if (input._valueGet) {
128
+ input.__defineGetter__("value", input._valueGet);
129
+ input.__defineSetter__("value", input._valueSet);
130
+ }
131
+ }
132
+ delete input._valueGet;
133
+ delete input._valueSet;
134
+ }
135
+ }, 0);
136
+ });
137
+ break;
138
+ case "getemptymask": //return the default (empty) mask value, usefull for setting the default value in validation
139
+ if (this.data('inputmask')) {
140
+ masksets = this.data('inputmask')['masksets'];
141
+ activeMasksetIndex = this.data('inputmask')['activeMasksetIndex'];
142
+ return masksets[activeMasksetIndex]['_buffer'].join('');
143
+ }
144
+ else return "";
145
+ case "hasMaskedValue": //check wheter the returned value is masked or not; currently only works reliable when using jquery.val fn to retrieve the value
146
+ return this.data('inputmask') ? !this.data('inputmask')['autoUnmask'] : false;
147
+ case "isComplete":
148
+ masksets = this.data('inputmask')['masksets'];
149
+ activeMasksetIndex = this.data('inputmask')['activeMasksetIndex'];
150
+ opts.greedy = this.data('inputmask')['greedy'];
151
+ opts.repeat = this.data('inputmask')['repeat'];
152
+ opts.definitions = this.data('inputmask')['definitions'];
153
+ return isComplete(this[0]);
154
+ default:
155
+ //check if the fn is an alias
156
+ if (!resolveAlias(fn)) {
157
+ //maybe fn is a mask so we try
158
+ //set mask
159
+ opts.mask = fn;
160
+ }
161
+ masksets = generateMaskSets();
162
+
163
+ return this.each(function () {
164
+ mask(this);
165
+ });
166
+
167
+ break;
168
+ }
169
+ } if (typeof fn == "object") {
170
+ opts = $.extend(true, {}, $.inputmask.defaults, fn);
171
+ resolveAlias(opts.alias); //resolve aliases
172
+ masksets = generateMaskSets();
173
+
174
+ return this.each(function () {
175
+ mask(this);
176
+ });
177
+ }
178
+
179
+ //helper functions
180
+ function isInputEventSupported(eventName) {
181
+ var el = document.createElement('input'),
182
+ eventName = 'on' + eventName,
183
+ isSupported = (eventName in el);
184
+ if (!isSupported) {
185
+ el.setAttribute(eventName, 'return;');
186
+ isSupported = typeof el[eventName] == 'function';
187
+ }
188
+ el = null;
189
+ return isSupported;
190
+ }
191
+
192
+ function resolveAlias(aliasStr) {
193
+ var aliasDefinition = opts.aliases[aliasStr];
194
+ if (aliasDefinition) {
195
+ if (aliasDefinition.alias) resolveAlias(aliasDefinition.alias); //alias is another alias
196
+ $.extend(true, opts, aliasDefinition); //merge alias definition in the options
197
+ $.extend(true, opts, options); //reapply extra given options
198
+ return true;
199
+ }
200
+ return false;
201
+ }
202
+
203
+ function getMaskTemplate(mask) {
204
+ var escaped = false, outCount = 0;
205
+ if (mask.length == 1 && opts.greedy == false) { opts.placeholder = ""; } //hide placeholder with single non-greedy mask
206
+ var singleMask = $.map(mask.split(""), function (element, index) {
207
+ var outElem = [];
208
+ if (element == opts.escapeChar) {
209
+ escaped = true;
210
+ }
211
+ else if ((element != opts.optionalmarker.start && element != opts.optionalmarker.end) || escaped) {
212
+ var maskdef = opts.definitions[element];
213
+ if (maskdef && !escaped) {
214
+ for (var i = 0; i < maskdef.cardinality; i++) {
215
+ outElem.push(getPlaceHolder(outCount + i));
216
+ }
217
+ } else {
218
+ outElem.push(element);
219
+ escaped = false;
220
+ }
221
+ outCount += outElem.length;
222
+ return outElem;
223
+ }
224
+ });
225
+
226
+ //allocate repetitions
227
+ var repeatedMask = singleMask.slice();
228
+ for (var i = 1; i < opts.repeat && opts.greedy; i++) {
229
+ repeatedMask = repeatedMask.concat(singleMask.slice());
230
+ }
231
+
232
+ return repeatedMask;
233
+ }
234
+
235
+ //test definition => {fn: RegExp/function, cardinality: int, optionality: bool, newBlockMarker: bool, offset: int, casing: null/upper/lower, def: definitionSymbol}
236
+ function getTestingChain(mask) {
237
+ var isOptional = false, escaped = false;
238
+ var newBlockMarker = false; //indicates wheter the begin/ending of a block should be indicated
239
+
240
+ return $.map(mask.split(""), function (element, index) {
241
+ var outElem = [];
242
+
243
+ if (element == opts.escapeChar) {
244
+ escaped = true;
245
+ } else if (element == opts.optionalmarker.start && !escaped) {
246
+ isOptional = true;
247
+ newBlockMarker = true;
248
+ }
249
+ else if (element == opts.optionalmarker.end && !escaped) {
250
+ isOptional = false;
251
+ newBlockMarker = true;
252
+ }
253
+ else {
254
+ var maskdef = opts.definitions[element];
255
+ if (maskdef && !escaped) {
256
+ var prevalidators = maskdef["prevalidator"], prevalidatorsL = prevalidators ? prevalidators.length : 0;
257
+ for (var i = 1; i < maskdef.cardinality; i++) {
258
+ var prevalidator = prevalidatorsL >= i ? prevalidators[i - 1] : [], validator = prevalidator["validator"], cardinality = prevalidator["cardinality"];
259
+ outElem.push({ fn: validator ? typeof validator == 'string' ? new RegExp(validator) : new function () { this.test = validator; } : new RegExp("."), cardinality: cardinality ? cardinality : 1, optionality: isOptional, newBlockMarker: isOptional == true ? newBlockMarker : false, offset: 0, casing: maskdef["casing"], def: element });
260
+ if (isOptional == true) //reset newBlockMarker
261
+ newBlockMarker = false;
262
+ }
263
+ outElem.push({ fn: maskdef.validator ? typeof maskdef.validator == 'string' ? new RegExp(maskdef.validator) : new function () { this.test = maskdef.validator; } : new RegExp("."), cardinality: maskdef.cardinality, optionality: isOptional, newBlockMarker: newBlockMarker, offset: 0, casing: maskdef["casing"], def: element });
264
+ } else {
265
+ outElem.push({ fn: null, cardinality: 0, optionality: isOptional, newBlockMarker: newBlockMarker, offset: 0, casing: null, def: element });
266
+ escaped = false;
267
+ }
268
+ //reset newBlockMarker
269
+ newBlockMarker = false;
270
+ return outElem;
271
+ }
272
+ });
273
+ }
274
+
275
+ function generateMaskSets() { //TODO improve generate masksets
276
+ var ms = [];
277
+ function markOptional(maskPart) { //needed for the clearOptionalTail functionality
278
+ return opts.optionalmarker.start + maskPart + opts.optionalmarker.end;
279
+ }
280
+ function generateMask(maskPrefix, maskPart) {
281
+ var maskParts = maskPart.split(opts.optionalmarker.end, 2);
282
+ var newMask;
283
+
284
+
285
+ var masks = maskParts[0].split(opts.optionalmarker.start);
286
+ if (masks.length > 1) {
287
+ newMask = maskPrefix + masks[0] + markOptional(masks[1]) + (maskParts.length > 1 ? maskParts[1] : "");
288
+ ms.push({
289
+ "_buffer": getMaskTemplate(newMask),
290
+ "tests": getTestingChain(newMask),
291
+ "lastValidPosition": 0
292
+ });
293
+ newMask = maskPrefix + masks[0] + (maskParts.length > 1 ? maskParts[1] : "");
294
+ ms.push({
295
+ "_buffer": getMaskTemplate(newMask),
296
+ "tests": getTestingChain(newMask),
297
+ "lastValidPosition": 0
298
+ });
299
+ if (maskParts.length > 1 && maskParts[1].split(opts.optionalmarker.start).length > 1) {
300
+ generateMask(maskPrefix + masks[0] + markOptional(masks[1]), maskParts[1]);
301
+ generateMask(maskPrefix + masks[0], maskParts[1]);
302
+ }
303
+ }
304
+ else {
305
+ newMask = maskPrefix + maskParts;
306
+ ms.push({
307
+ "_buffer": getMaskTemplate(newMask),
308
+ "tests": getTestingChain(newMask),
309
+ "lastValidPosition": 0
310
+ });
311
+ }
312
+
313
+ }
314
+
315
+ generateMask("", opts.mask);
316
+ return ms;
317
+ }
318
+
319
+ function getActiveMaskSet() {
320
+ return masksets[activeMasksetIndex];
321
+ }
322
+
323
+ function getActiveTests() {
324
+ return getActiveMaskSet()['tests'];
325
+ }
326
+
327
+ function getActiveBuffer() {
328
+ return getActiveMaskSet()['_buffer'];
329
+ }
330
+
331
+ function isValid(pos, c, buffer, strict, isRTL) { //strict true ~ no correction or autofill
332
+ function _isValid(position, activeMaskset) {
333
+ var testPos = determineTestPosition(position), loopend = c ? 1 : 0, chrs = '';
334
+ for (var i = activeMaskset['tests'][testPos].cardinality; i > loopend; i--) {
335
+ chrs += getBufferElement(buffer, testPos - (i - 1));
336
+ }
337
+
338
+ if (c) {
339
+ chrs += c;
340
+ }
341
+ //return is false or a json object => { pos: ??, c: ??} or true
342
+ return activeMaskset['tests'][testPos].fn != null ? activeMaskset['tests'][testPos].fn.test(chrs, buffer, position, strict, opts) : false;
343
+ }
344
+
345
+ if (strict) return _isValid(pos, getActiveMaskSet()); //only check validity in current mask when validating strict
346
+
347
+ var results = [], result = false, currentActiveMasksetIndex = activeMasksetIndex;
348
+ $.each(masksets, function (index, value) {
349
+ var activeMaskset = this;
350
+ activeMasksetIndex = index;
351
+
352
+ var maskPos = pos;
353
+ if (currentActiveMasksetIndex != activeMasksetIndex && !isMask(pos)) {
354
+ if (c == activeMaskset['_buffer'][maskPos] || c == opts.skipOptionalPartCharacter) { //match non-mask item
355
+ results[index] = { "refresh": true }; //new command hack only rewrite buffer
356
+ activeMaskset['lastValidPosition'] = maskPos;
357
+ return false;
358
+ }
359
+
360
+ maskPos = isRTL ? seekPrevious(buffer, pos) : seekNext(buffer, pos);
361
+ }
362
+ if (isRTL ? activeMaskset['lastValidPosition'] <= opts.numericInput ? getMaskLength() : seekNext(buffer, maskPos) : activeMaskset['lastValidPosition'] >= seekPrevious(buffer, maskPos)) {
363
+ if (maskPos >= 0 && maskPos < getMaskLength()) {
364
+ results[index] = _isValid(maskPos, activeMaskset);
365
+ if (results[index] !== false) {
366
+ if (results[index] === true) {
367
+ results[index] = { "pos": maskPos }; //always take a possible corrected maskposition into account
368
+ }
369
+ activeMaskset['lastValidPosition'] = results[index].pos || maskPos; //set new position from isValid
370
+ } else activeMaskset['lastValidPosition'] = isRTL ? seekNext(buffer, pos) : seekPrevious(buffer, pos); //autocorrect validposition from backspace etc
371
+ }
372
+ }
373
+ });
374
+ activeMasksetIndex = currentActiveMasksetIndex; //reset activeMasksetIndex
375
+ determineActiveMasksetIndex(buffer, pos, currentActiveMasksetIndex, isRTL);
376
+ result = results[activeMasksetIndex] || result;
377
+ setTimeout(function () { opts.onKeyValidation.call(this, result, opts); }, 0); //extra stuff to execute on keydown
378
+ return result;
379
+ }
380
+
381
+ function determineActiveMasksetIndex(buffer, pos, currentActiveMasksetIndex, isRTL) {
382
+ $.each(masksets, function (index, value) {
383
+ var activeMaskset = this;
384
+ if (isRTL ? activeMaskset['lastValidPosition'] <= pos : activeMaskset['lastValidPosition'] >= pos) {
385
+ activeMasksetIndex = index;
386
+ //reset to correct masktemplate
387
+ if (activeMasksetIndex != currentActiveMasksetIndex) {
388
+ var abl = getMaskLength(), bufTemplate = getActiveBuffer();
389
+ if (isRTL) {
390
+ buffer.reverse();
391
+ bufTemplate.reverse();
392
+ }
393
+ buffer.length = pos; //clearout beyond the current
394
+ for (var i = pos; i < abl; i++) {
395
+ var testPos = determineTestPosition(i);
396
+ setBufferElement(buffer, i, getBufferElement(bufTemplate, testPos));
397
+ }
398
+ if (isRTL) {
399
+ buffer.reverse();
400
+ }
401
+ }
402
+ return false; //breaks
403
+ }
404
+ });
405
+ }
406
+
407
+ function isMask(pos) {
408
+ var testPos = determineTestPosition(pos);
409
+ var test = getActiveTests()[testPos];
410
+
411
+ return test != undefined ? test.fn : false;
412
+ }
413
+
414
+ function determineTestPosition(pos) {
415
+ return pos % getActiveTests().length;
416
+ }
417
+
418
+ function getPlaceHolder(pos) {
419
+ return opts.placeholder.charAt(pos % opts.placeholder.length);
420
+ }
421
+
422
+ function getMaskLength() {
423
+ var calculatedLength = getActiveBuffer().length;
424
+ if (!opts.greedy && opts.repeat > 1) {
425
+ calculatedLength += (getActiveBuffer().length * (opts.repeat - 1));
426
+ }
427
+ return calculatedLength;
428
+ }
429
+
430
+ //pos: from position
431
+ function seekNext(buffer, pos) {
432
+ var maskL = getMaskLength();
433
+ if (pos >= maskL) return maskL;
434
+ var position = pos;
435
+ while (++position < maskL && !isMask(position)) { };
436
+ return position;
437
+ }
438
+ //pos: from position
439
+ function seekPrevious(buffer, pos) {
440
+ var position = pos;
441
+ if (position <= 0) return 0;
442
+
443
+ while (--position > 0 && !isMask(position)) { };
444
+ return position;
445
+ }
446
+
447
+ function setBufferElement(buffer, position, element) {
448
+ //position = prepareBuffer(buffer, position);
449
+
450
+ var test = getActiveTests()[determineTestPosition(position)];
451
+ var elem = element;
452
+ if (elem != undefined) {
453
+ switch (test.casing) {
454
+ case "upper":
455
+ elem = element.toUpperCase();
456
+ break;
457
+ case "lower":
458
+ elem = element.toLowerCase();
459
+ break;
460
+ }
461
+ }
462
+
463
+ buffer[position] = elem;
464
+ }
465
+ function getBufferElement(buffer, position, autoPrepare) {
466
+ if (autoPrepare) position = prepareBuffer(buffer, position);
467
+ return buffer[position];
468
+ }
469
+
470
+ //needed to handle the non-greedy mask repetitions
471
+ function prepareBuffer(buffer, position, isRTL) {
472
+ var j;
473
+ if (isRTL) {
474
+ while (position < 0 && buffer.length < getMaskLength()) {
475
+ j = getActiveBuffer().length - 1;
476
+ position = getActiveBuffer().length;
477
+ while (getActiveBuffer()[j] !== undefined) {
478
+ buffer.unshift(getActiveBuffer()[j--]);
479
+ }
480
+ }
481
+ } else {
482
+ while (buffer[position] == undefined && buffer.length < getMaskLength()) {
483
+ j = 0;
484
+ while (getActiveBuffer()[j] !== undefined) { //add a new buffer
485
+ buffer.push(getActiveBuffer()[j++]);
486
+ }
487
+ }
488
+ }
489
+
490
+ return position;
491
+ }
492
+
493
+ function writeBuffer(input, buffer, caretPos) {
494
+ input._valueSet(buffer.join(''));
495
+ if (caretPos != undefined) {
496
+ if (android) {
497
+ setTimeout(function () {
498
+ caret(input, caretPos);
499
+ }, 100);
500
+ }
501
+ else caret(input, caretPos);
502
+ }
503
+ };
504
+ function clearBuffer(buffer, start, end) {
505
+ for (var i = start, maskL = getMaskLength() ; i < end && i < maskL; i++) {
506
+ setBufferElement(buffer, i, getBufferElement(getActiveBuffer().slice(), i));
507
+ }
508
+ };
509
+
510
+ function setReTargetPlaceHolder(buffer, pos) {
511
+ var testPos = determineTestPosition(pos);
512
+ setBufferElement(buffer, pos, getBufferElement(getActiveBuffer(), testPos));
513
+ }
514
+
515
+ function checkVal(input, buffer, clearInvalid, skipRadixHandling) {
516
+ var isRTL = $(input).data('inputmask')['isRTL'],
517
+ inputValue = truncateInput(input._valueGet(), isRTL).split('');
518
+
519
+ if (isRTL) { //align inputValue for RTL/numeric input
520
+ var maskL = getMaskLength();
521
+ var inputValueRev = inputValue.reverse(); inputValueRev.length = maskL;
522
+
523
+ for (var i = 0; i < maskL; i++) {
524
+ var targetPosition = determineTestPosition(maskL - (i + 1));
525
+ if (getActiveTests()[targetPosition].fn == null && inputValueRev[i] != getBufferElement(getActiveBuffer(), targetPosition)) {
526
+ inputValueRev.splice(i, 0, getBufferElement(getActiveBuffer(), targetPosition));
527
+ inputValueRev.length = maskL;
528
+ } else {
529
+ inputValueRev[i] = inputValueRev[i] || getBufferElement(getActiveBuffer(), targetPosition);
530
+ }
531
+ }
532
+ inputValue = inputValueRev.reverse();
533
+ }
534
+ clearBuffer(buffer, 0, buffer.length);
535
+ buffer.length = getActiveBuffer().length;
536
+ var lastMatch = -1, checkPosition = -1, np, maskL = getMaskLength(), ivl = inputValue.length, rtlMatch = ivl == 0 ? maskL : -1;
537
+ for (var i = 0; i < ivl; i++) {
538
+ for (var pos = checkPosition + 1; pos < maskL; pos++) {
539
+ if (isMask(pos)) {
540
+ var c = inputValue[i];
541
+ if ((np = isValid(pos, c, buffer, !clearInvalid, isRTL)) !== false) {
542
+ if (np !== true) {
543
+ pos = np.pos != undefined ? np.pos : pos; //set new position from isValid
544
+ c = np.c != undefined ? np.c : c; //set new char from isValid
545
+ }
546
+ setBufferElement(buffer, pos, c);
547
+ lastMatch = checkPosition = pos;
548
+ } else {
549
+ setReTargetPlaceHolder(buffer, pos);
550
+ if (c == getPlaceHolder(pos)) {
551
+ checkPosition = pos;
552
+ rtlMatch = pos;
553
+ }
554
+ }
555
+ break;
556
+ } else { //nonmask
557
+ setReTargetPlaceHolder(buffer, pos);
558
+ if (lastMatch == checkPosition) //once outsync the nonmask cannot be the lastmatch
559
+ lastMatch = pos;
560
+ checkPosition = pos;
561
+ if (inputValue[i] == getBufferElement(buffer, pos))
562
+ break;
563
+ }
564
+ }
565
+ }
566
+ //Truncate buffer when using non-greedy masks
567
+ if (opts.greedy == false) {
568
+ var newBuffer = truncateInput(buffer.join(''), isRTL).split('');
569
+ while (buffer.length != newBuffer.length) { //map changes into the original buffer
570
+ isRTL ? buffer.shift() : buffer.pop();
571
+ }
572
+ }
573
+
574
+ if (clearInvalid) {
575
+ writeBuffer(input, buffer);
576
+ }
577
+ return isRTL ? (opts.numericInput ? ($.inArray(opts.radixPoint, buffer) != -1 && skipRadixHandling !== true ? $.inArray(opts.radixPoint, buffer) : seekNext(buffer, maskL)) : seekNext(buffer, rtlMatch)) : seekNext(buffer, lastMatch);
578
+ }
579
+
580
+ function escapeRegex(str) {
581
+ return $.inputmask.escapeRegex.call(this, str);
582
+ }
583
+
584
+ function truncateInput(inputValue, rtl) {
585
+ return rtl ? inputValue.replace(new RegExp("^(" + escapeRegex(getActiveBuffer().join('')) + ")*"), "") : inputValue.replace(new RegExp("(" + escapeRegex(getActiveBuffer().join('')) + ")*$"), "");
586
+ }
587
+
588
+ function clearOptionalTail(input, buffer) {
589
+ checkVal(input, buffer, false);
590
+ var tmpBuffer = buffer.slice();
591
+ if ($(input).data('inputmask')['isRTL']) {
592
+ for (var pos = 0; pos <= tmpBuffer.length - 1; pos++) {
593
+ var testPos = determineTestPosition(pos);
594
+ if (getActiveTests()[testPos].optionality) {
595
+ if (getPlaceHolder(pos) == buffer[pos] || !isMask(pos))
596
+ tmpBuffer.splice(0, 1);
597
+ else break;
598
+ } else break;
599
+ }
600
+ } else {
601
+ for (var pos = tmpBuffer.length - 1; pos >= 0; pos--) {
602
+ var testPos = determineTestPosition(pos);
603
+ if (getActiveTests()[testPos].optionality) {
604
+ if (getPlaceHolder(pos) == buffer[pos] || !isMask(pos))
605
+ tmpBuffer.pop();
606
+ else break;
607
+ } else break;
608
+ }
609
+ }
610
+ writeBuffer(input, tmpBuffer);
611
+ }
612
+
613
+ //functionality fn
614
+ function unmaskedvalue($input, skipDatepickerCheck) {
615
+ var input = $input[0];
616
+ if (getActiveTests() && (skipDatepickerCheck === true || !$input.hasClass('hasDatepicker'))) {
617
+ var buffer = getActiveBuffer().slice();
618
+ checkVal(input, buffer);
619
+ return $.map(buffer, function (element, index) {
620
+ return isMask(index) && element != getBufferElement(getActiveBuffer().slice(), index) ? element : null;
621
+ }).join('');
622
+ }
623
+ else {
624
+ return input._valueGet();
625
+ }
626
+ }
627
+
628
+ function caret(input, begin, end) {
629
+ var npt = input.jquery && input.length > 0 ? input[0] : input;
630
+ if (typeof begin == 'number') {
631
+ end = (typeof end == 'number') ? end : begin;
632
+ if (opts.insertMode == false && begin == end) end++; //set visualization for insert/overwrite mode
633
+ if (npt.setSelectionRange) {
634
+ npt.setSelectionRange(begin, end);
635
+ } else if (npt.createTextRange) {
636
+ var range = npt.createTextRange();
637
+ range.collapse(true);
638
+ range.moveEnd('character', end);
639
+ range.moveStart('character', begin);
640
+ range.select();
641
+ }
642
+ npt.focus();
643
+ if (android && end != npt.selectionEnd) caretposCorrection = { begin: begin, end: end };
644
+ } else {
645
+ var caretpos = android ? caretposCorrection : null, caretposCorrection = null;
646
+ if (caretpos == null) {
647
+ if (npt.setSelectionRange) {
648
+ begin = npt.selectionStart;
649
+ end = npt.selectionEnd;
650
+ } else if (document.selection && document.selection.createRange) {
651
+ var range = document.selection.createRange();
652
+ begin = 0 - range.duplicate().moveStart('character', -100000);
653
+ end = begin + range.text.length;
654
+ }
655
+ caretpos = { begin: begin, end: end };
656
+ }
657
+ return caretpos;
658
+ }
659
+ };
660
+
661
+ function isComplete(npt) {
662
+ var complete = false, nptValue = npt._valueGet(), ml = nptValue.length
663
+ currentActiveMasksetIndex = activeMasksetIndex, highestValidPosition = 0;
664
+ $.each(masksets, function (ndx, ms) {
665
+ activeMasksetIndex = ndx;
666
+ var aml = getMaskLength();
667
+ if (ms["lastValidPosition"] >= highestValidPosition && ms["lastValidPosition"] == (aml - 1)) {
668
+ var msComplete = true;
669
+ for (var i = 0; i < aml; i++) {
670
+ var mask = isMask(i);
671
+ if ((mask && nptValue.charAt(i) == getPlaceHolder(i)) || (!mask && nptValue.charAt(i) != getActiveBuffer()[i])) {
672
+ msComplete = false;
673
+ break;
674
+ }
675
+ }
676
+ complete = complete || msComplete;
677
+ if (complete) //break loop
678
+ return false;
679
+ }
680
+ highestValidPosition = ms["lastValidPosition"];
681
+ });
682
+ activeMasksetIndex = currentActiveMasksetIndex; //reset activeMaskset
683
+ return complete;
684
+ }
685
+
686
+ function mask(el) {
687
+ var $input = $(el);
688
+ if (!$input.is(":input")) return;
689
+
690
+ //correct greedy setting if needed
691
+ opts.greedy = opts.greedy ? opts.greedy : opts.repeat == 0;
692
+
693
+
694
+
695
+ //handle maxlength attribute
696
+ var maxLength = $input.prop('maxLength');
697
+ if (getMaskLength() > maxLength && maxLength > -1) { //FF sets no defined max length to -1
698
+ if (maxLength < getActiveBuffer().length) getActiveBuffer().length = maxLength;
699
+ if (opts.greedy == false) {
700
+ opts.repeat = Math.round(maxLength / getActiveBuffer().length);
701
+ }
702
+ $input.prop('maxLength', getMaskLength() * 2);
703
+ }
704
+
705
+ //store tests & original buffer in the input element - used to get the unmasked value
706
+ $input.data('inputmask', {
707
+ 'masksets': masksets,
708
+ 'activeMasksetIndex': activeMasksetIndex,
709
+ 'greedy': opts.greedy,
710
+ 'repeat': opts.repeat,
711
+ 'autoUnmask': opts.autoUnmask,
712
+ 'definitions': opts.definitions,
713
+ 'isRTL': false
714
+ });
715
+
716
+ patchValueProperty(el);
717
+
718
+ //init vars
719
+ var buffer = getActiveBuffer().slice(),
720
+ undoBuffer = el._valueGet(),
721
+ skipKeyPressEvent = false, //Safari 5.1.x - modal dialog fires keypress twice workaround
722
+ lastPosition = -1,
723
+ firstMaskPos = seekNext(buffer, -1),
724
+ lastMaskPos = seekPrevious(buffer, getMaskLength()),
725
+ isRTL = false;
726
+ if (el.dir == "rtl" || opts.numericInput) {
727
+ el.dir = "ltr"
728
+ $input.css("text-align", "right");
729
+ $input.removeAttr("dir");
730
+ var inputData = $input.data('inputmask');
731
+ inputData['isRTL'] = true;
732
+ $input.data('inputmask', inputData);
733
+ isRTL = true;
734
+ }
735
+
736
+ //unbind all events - to make sure that no other mask will interfere when re-masking
737
+ $input.unbind(".inputmask");
738
+ $input.removeClass('focus.inputmask');
739
+ //bind events
740
+ $input.bind("mouseenter.inputmask", function () {
741
+ var $input = $(this), input = this;
742
+ if (!$input.hasClass('focus.inputmask') && opts.showMaskOnHover) {
743
+ var nptL = input._valueGet().length;
744
+ if (nptL < buffer.length) {
745
+ if (nptL == 0)
746
+ buffer = getActiveBuffer().slice();
747
+ writeBuffer(input, buffer);
748
+ }
749
+ }
750
+ }).bind("blur.inputmask", function () {
751
+ var $input = $(this), input = this, nptValue = input._valueGet();
752
+ $input.removeClass('focus.inputmask');
753
+ if (nptValue != undoBuffer) {
754
+ $input.change();
755
+ }
756
+ if (opts.clearMaskOnLostFocus && nptValue != '') {
757
+ if (nptValue == getActiveBuffer().join(''))
758
+ input._valueSet('');
759
+ else { //clearout optional tail of the mask
760
+ clearOptionalTail(input, buffer);
761
+ }
762
+ }
763
+ if (!isComplete(input)) {
764
+ $input.trigger("incomplete");
765
+ if (opts.clearIncomplete) {
766
+ if (opts.clearMaskOnLostFocus)
767
+ input._valueSet('');
768
+ else {
769
+ buffer = getActiveBuffer().slice();
770
+ writeBuffer(input, buffer);
771
+ }
772
+ }
773
+ }
774
+ }).bind("focus.inputmask", function () {
775
+ var $input = $(this), input = this, nptValue = input._valueGet();
776
+ if (!$input.hasClass('focus.inputmask') && (!opts.showMaskOnHover || (opts.showMaskOnHover && nptValue == ''))) {
777
+ var nptL = nptValue.length;
778
+ if (nptL < buffer.length) {
779
+ if (nptL == 0)
780
+ buffer = getActiveBuffer().slice();
781
+ caret(input, checkVal(input, buffer, true));
782
+ }
783
+ }
784
+ $input.addClass('focus.inputmask');
785
+ undoBuffer = input._valueGet();
786
+ }).bind("mouseleave.inputmask", function () {
787
+ var $input = $(this), input = this;
788
+ if (opts.clearMaskOnLostFocus) {
789
+ if (!$input.hasClass('focus.inputmask')) {
790
+ if (input._valueGet() == getActiveBuffer().join('') || input._valueGet() == '')
791
+ input._valueSet('');
792
+ else { //clearout optional tail of the mask
793
+ clearOptionalTail(input, buffer);
794
+ }
795
+ }
796
+ }
797
+ }).bind("click.inputmask", function () {
798
+ var input = this;
799
+ setTimeout(function () {
800
+ var selectedCaret = caret(input);
801
+ if (selectedCaret.begin == selectedCaret.end) {
802
+ var clickPosition = selectedCaret.begin;
803
+ lastPosition = checkVal(input, buffer, false);
804
+ if (isRTL)
805
+ caret(input, clickPosition > lastPosition && (isValid(clickPosition, buffer[clickPosition], buffer, true, isRTL) !== false || !isMask(clickPosition)) ? clickPosition : lastPosition);
806
+ else
807
+ caret(input, clickPosition < lastPosition && (isValid(clickPosition, buffer[clickPosition], buffer, true, isRTL) !== false || !isMask(clickPosition)) ? clickPosition : lastPosition);
808
+ }
809
+ }, 0);
810
+ }).bind('dblclick.inputmask', function () {
811
+ var input = this;
812
+ setTimeout(function () {
813
+ caret(input, 0, lastPosition);
814
+ }, 0);
815
+ }).bind("keydown.inputmask", keydownEvent
816
+ ).bind("keypress.inputmask", keypressEvent
817
+ ).bind("keyup.inputmask", keyupEvent
818
+ ).bind(pasteEvent + ".inputmask dragdrop.inputmask drop.inputmask", function () {
819
+ var input = this;
820
+ setTimeout(function () {
821
+ caret(input, checkVal(input, buffer, true));
822
+ if (isComplete(input))
823
+ $input.trigger("complete");
824
+ }, 0);
825
+ }).bind('setvalue.inputmask', function () {
826
+ var input = this;
827
+ undoBuffer = input._valueGet();
828
+ checkVal(input, buffer, true);
829
+ if (input._valueGet() == getActiveBuffer().join(''))
830
+ input._valueSet('');
831
+ }).bind('complete.inputmask', opts.oncomplete)
832
+ .bind('incomplete.inputmask', opts.onincomplete)
833
+ .bind('cleared.inputmask', opts.oncleared);
834
+
835
+ //apply mask
836
+ lastPosition = checkVal(el, buffer, true);
837
+
838
+ // Wrap document.activeElement in a try/catch block since IE9 throw "Unspecified error" if document.activeElement is undefined when we are in an IFrame.
839
+ var activeElement;
840
+ try {
841
+ activeElement = document.activeElement;
842
+ } catch (e) { }
843
+ if (activeElement === el) { //position the caret when in focus
844
+ $input.addClass('focus.inputmask');
845
+ caret(el, lastPosition);
846
+ } else if (opts.clearMaskOnLostFocus) {
847
+ if (el._valueGet() == getActiveBuffer().join('')) {
848
+ el._valueSet('');
849
+ } else {
850
+ clearOptionalTail(el, buffer);
851
+ }
852
+ }
853
+
854
+ installEventRuler(el);
855
+
856
+ //private functions
857
+ function installEventRuler(npt) {
858
+ var events = $._data(npt).events;
859
+
860
+ $.each(events, function (eventType, eventHandlers) {
861
+ $.each(eventHandlers, function (ndx, eventHandler) {
862
+ if (eventHandler.namespace == "inputmask") {
863
+ var handler = eventHandler.handler;
864
+ eventHandler.handler = function () {
865
+ if (this.readOnly || this.disabled)
866
+ return false;
867
+ return handler.apply(this, arguments);
868
+ };
869
+ }
870
+ });
871
+ });
872
+ }
873
+
874
+ function patchValueProperty(npt) {
875
+ var valueProperty;
876
+ if (Object.getOwnPropertyDescriptor)
877
+ valueProperty = Object.getOwnPropertyDescriptor(npt, "value");
878
+ if (valueProperty && valueProperty.get) {
879
+ if (!npt._valueGet) {
880
+
881
+ npt._valueGet = valueProperty.get;
882
+ npt._valueSet = valueProperty.set;
883
+
884
+ Object.defineProperty(npt, "value", {
885
+ get: function () {
886
+ var $self = $(this), inputData = $(this).data('inputmask'), masksets = inputData['masksets'],
887
+ activeMasksetIndex = inputData['activeMasksetIndex'];
888
+ return inputData && inputData['autoUnmask'] ? $self.inputmask('unmaskedvalue') : this._valueGet() != masksets[activeMasksetIndex]['_buffer'].join('') ? this._valueGet() : '';
889
+ },
890
+ set: function (value) {
891
+ this._valueSet(value); $(this).triggerHandler('setvalue.inputmask');
892
+ }
893
+ });
894
+ }
895
+ } else if (document.__lookupGetter__ && npt.__lookupGetter__("value")) {
896
+ if (!npt._valueGet) {
897
+ npt._valueGet = npt.__lookupGetter__("value");
898
+ npt._valueSet = npt.__lookupSetter__("value");
899
+
900
+ npt.__defineGetter__("value", function () {
901
+ var $self = $(this), inputData = $(this).data('inputmask'), masksets = inputData['masksets'],
902
+ activeMasksetIndex = inputData['activeMasksetIndex'];
903
+ return inputData && inputData['autoUnmask'] ? $self.inputmask('unmaskedvalue') : this._valueGet() != masksets[activeMasksetIndex]['_buffer'].join('') ? this._valueGet() : '';
904
+ });
905
+ npt.__defineSetter__("value", function (value) {
906
+ this._valueSet(value); $(this).triggerHandler('setvalue.inputmask');
907
+ });
908
+ }
909
+ } else {
910
+ if (!npt._valueGet) {
911
+ npt._valueGet = function () { return this.value; }
912
+ npt._valueSet = function (value) { this.value = value; }
913
+ }
914
+ if ($.fn.val.inputmaskpatch != true) {
915
+ $.fn.val = function () {
916
+ if (arguments.length == 0) {
917
+ var $self = $(this);
918
+ if ($self.data('inputmask')) {
919
+ if ($self.data('inputmask')['autoUnmask'])
920
+ return $self.inputmask('unmaskedvalue');
921
+ else {
922
+ var result = $.inputmask.val.apply($self);
923
+ var inputData = $(this).data('inputmask'), masksets = inputData['masksets'],
924
+ activeMasksetIndex = inputData['activeMasksetIndex'];
925
+ return result != masksets[activeMasksetIndex]['_buffer'].join('') ? result : '';
926
+ }
927
+ } else return $.inputmask.val.apply($self);
928
+ } else {
929
+ var args = arguments;
930
+ return this.each(function () {
931
+ var $self = $(this);
932
+ var result = $.inputmask.val.apply($self, args);
933
+ if ($self.data('inputmask')) $self.triggerHandler('setvalue.inputmask');
934
+ return result;
935
+ });
936
+ }
937
+ };
938
+ $.extend($.fn.val, {
939
+ inputmaskpatch: true
940
+ });
941
+ }
942
+ }
943
+ }
944
+ //shift chars to left from start to end and put c at end position if defined
945
+ function shiftL(start, end, c) {
946
+ while (!isMask(start) && start - 1 >= 0) start--;
947
+ for (var i = start; i < end && i < getMaskLength() ; i++) {
948
+ if (isMask(i)) {
949
+ setReTargetPlaceHolder(buffer, i);
950
+ var j = seekNext(buffer, i);
951
+ var p = getBufferElement(buffer, j);
952
+ if (p != getPlaceHolder(j)) {
953
+ if (j < getMaskLength() && isValid(i, p, buffer, true, isRTL) !== false && getActiveTests()[determineTestPosition(i)].def == getActiveTests()[determineTestPosition(j)].def) {
954
+ setBufferElement(buffer, i, getBufferElement(buffer, j));
955
+ setReTargetPlaceHolder(buffer, j); //cleanup next position
956
+ } else {
957
+ if (isMask(i))
958
+ break;
959
+ }
960
+ } else if (c == undefined) break;
961
+ } else {
962
+ setReTargetPlaceHolder(buffer, i);
963
+ }
964
+ }
965
+ if (c != undefined)
966
+ setBufferElement(buffer, isRTL ? end : seekPrevious(buffer, end), c);
967
+
968
+ buffer = truncateInput(buffer.join(''), isRTL).split('');
969
+ if (buffer.length == 0) buffer = getActiveBuffer().slice();
970
+
971
+ return start; //return the used start position
972
+ }
973
+ function shiftR(start, end, c, full) { //full => behave like a push right ~ do not stop on placeholders
974
+ for (var i = start; i <= end && i < getMaskLength() ; i++) {
975
+ if (isMask(i)) {
976
+ var t = getBufferElement(buffer, i);
977
+ setBufferElement(buffer, i, c);
978
+ if (t != getPlaceHolder(i)) {
979
+ var j = seekNext(buffer, i);
980
+ if (j < getMaskLength()) {
981
+ if (isValid(j, t, buffer, true, isRTL) !== false && getActiveTests()[determineTestPosition(i)].def == getActiveTests()[determineTestPosition(j)].def)
982
+ c = t;
983
+ else {
984
+ if (isMask(j))
985
+ break;
986
+ else c = t;
987
+ }
988
+ } else break;
989
+ } else if (full !== true) break;
990
+ } else
991
+ setReTargetPlaceHolder(buffer, i);
992
+ }
993
+ var lengthBefore = buffer.length;
994
+ buffer = truncateInput(buffer.join(''), isRTL).split('');
995
+ if (buffer.length == 0) buffer = getActiveBuffer().slice();
996
+
997
+ return end - (lengthBefore - buffer.length); //return new start position
998
+ };
999
+
1000
+ function keydownEvent(e) {
1001
+ //Safari 5.1.x - modal dialog fires keypress twice workaround
1002
+ skipKeyPressEvent = false;
1003
+
1004
+ var input = this, k = e.keyCode, pos = caret(input);
1005
+
1006
+ //set input direction according the position to the radixPoint
1007
+ if (opts.numericInput) {
1008
+ var nptStr = input._valueGet();
1009
+ var radixPosition = nptStr.indexOf(opts.radixPoint);
1010
+ if (radixPosition != -1) {
1011
+ isRTL = pos.begin <= radixPosition || pos.end <= radixPosition;
1012
+ }
1013
+ }
1014
+
1015
+ //backspace, delete, and escape get special treatment
1016
+ if (k == opts.keyCode.BACKSPACE || k == opts.keyCode.DELETE || (iphone && k == 127)) {//backspace/delete
1017
+ var maskL = getMaskLength();
1018
+ if (pos.begin == 0 && pos.end == maskL) {
1019
+ activeMasksetIndex = 0; //reset activemask
1020
+ buffer = getActiveBuffer().slice();
1021
+ writeBuffer(input, buffer);
1022
+ caret(input, checkVal(input, buffer, false));
1023
+ } else if ((pos.end - pos.begin) > 1 || ((pos.end - pos.begin) == 1 && opts.insertMode)) {
1024
+ clearBuffer(buffer, pos.begin, pos.end);
1025
+ determineActiveMasksetIndex(buffer, pos.begin, activeMasksetIndex);
1026
+ writeBuffer(input, buffer);
1027
+ caret(isRTL ? checkVal(input, buffer, false) : pos.begin);
1028
+ } else {
1029
+ var beginPos = pos.begin - (k == opts.keyCode.DELETE ? 0 : 1);
1030
+ if (beginPos < firstMaskPos && k == opts.keyCode.DELETE) {
1031
+ beginPos = firstMaskPos;
1032
+ }
1033
+ if (beginPos >= firstMaskPos) {
1034
+ if (opts.numericInput && opts.greedy && k == opts.keyCode.DELETE && buffer[beginPos] == opts.radixPoint) {
1035
+ beginPos = seekNext(buffer, beginPos);
1036
+ isRTL = false;
1037
+ }
1038
+ if (isRTL) {
1039
+ beginPos = shiftR(firstMaskPos, beginPos, getPlaceHolder(beginPos), true);
1040
+ beginPos = (opts.numericInput && opts.greedy && k == opts.keyCode.BACKSPACE && buffer[beginPos + 1] == opts.radixPoint) ? beginPos + 1 : seekNext(buffer, beginPos);
1041
+ } else beginPos = shiftL(beginPos, maskL);
1042
+ determineActiveMasksetIndex(buffer, beginPos, activeMasksetIndex);
1043
+ writeBuffer(input, buffer, beginPos);
1044
+ }
1045
+ }
1046
+ if (input._valueGet() == getActiveBuffer().join(''))
1047
+ $(input).trigger('cleared');
1048
+
1049
+ e.preventDefault(); //stop default action but allow propagation
1050
+ } else if (k == opts.keyCode.END || k == opts.keyCode.PAGE_DOWN) { //when END or PAGE_DOWN pressed set position at lastmatch
1051
+ setTimeout(function () {
1052
+ var caretPos = checkVal(input, buffer, false, true);
1053
+ if (!opts.insertMode && caretPos == getMaskLength() && !e.shiftKey) caretPos--;
1054
+ caret(input, e.shiftKey ? pos.begin : caretPos, caretPos);
1055
+ }, 0);
1056
+ } else if (k == opts.keyCode.HOME || k == opts.keyCode.PAGE_UP) {//Home or page_up
1057
+ caret(input, 0, e.shiftKey ? pos.begin : 0);
1058
+ }
1059
+ else if (k == opts.keyCode.ESCAPE) {//escape
1060
+ input._valueSet(undoBuffer);
1061
+ caret(input, 0, checkVal(input, buffer));
1062
+ } else if (k == opts.keyCode.INSERT) {//insert
1063
+ opts.insertMode = !opts.insertMode;
1064
+ caret(input, !opts.insertMode && pos.begin == getMaskLength() ? pos.begin - 1 : pos.begin);
1065
+ } else if (e.ctrlKey && k == 88) {
1066
+ setTimeout(function () {
1067
+ caret(input, checkVal(input, buffer, true));
1068
+ }, 0);
1069
+ } else if (!opts.insertMode) { //overwritemode
1070
+ if (k == opts.keyCode.RIGHT) {//right
1071
+ var caretPos = pos.begin == pos.end ? pos.end + 1 : pos.end;
1072
+ caretPos = caretPos < getMaskLength() ? caretPos : pos.end;
1073
+ caret(input, e.shiftKey ? pos.begin : caretPos, e.shiftKey ? caretPos + 1 : caretPos);
1074
+ } else if (k == opts.keyCode.LEFT) {//left
1075
+ var caretPos = pos.begin - 1;
1076
+ caretPos = caretPos > 0 ? caretPos : 0;
1077
+ caret(input, caretPos, e.shiftKey ? pos.end : caretPos);
1078
+ }
1079
+ }
1080
+
1081
+ opts.onKeyDown.call(this, e, opts); //extra stuff to execute on keydown
1082
+ }
1083
+
1084
+ function keypressEvent(e) {
1085
+ //Safari 5.1.x - modal dialog fires keypress twice workaround
1086
+ if (skipKeyPressEvent) return false;
1087
+ skipKeyPressEvent = true;
1088
+
1089
+ var input = this, $input = $(input);
1090
+
1091
+ e = e || window.event;
1092
+ var k = e.which || e.charCode || e.keyCode,
1093
+ c = String.fromCharCode(k);
1094
+
1095
+ if (opts.numericInput && c == opts.radixPoint) {
1096
+ var nptStr = input._valueGet();
1097
+ var radixPosition = nptStr.indexOf(opts.radixPoint);
1098
+ caret(input, seekNext(buffer, radixPosition != -1 ? radixPosition : getMaskLength()));
1099
+ }
1100
+
1101
+ if (e.ctrlKey || e.altKey || e.metaKey) {
1102
+ return true;
1103
+ } else {
1104
+ if (k) {
1105
+ $input.trigger('input');
1106
+
1107
+ var pos = caret(input), maskL = getMaskLength(), writeOutBuffer = true;
1108
+ clearBuffer(buffer, pos.begin, pos.end);
1109
+
1110
+ if (isRTL) {
1111
+ var p = opts.numericInput ? pos.end : seekPrevious(buffer, pos.end), np;
1112
+ if ((np = isValid(p == maskL || getBufferElement(buffer, p) == opts.radixPoint ? seekPrevious(buffer, p) : p, c, buffer, false, isRTL)) !== false) {
1113
+ var refresh = false;
1114
+ if (np !== true) {
1115
+ refresh = np["refresh"]; //only rewrite buffer from isValid
1116
+ p = np.pos != undefined ? np.pos : p; //set new position from isValid
1117
+ c = np.c != undefined ? np.c : c; //set new char from isValid
1118
+ }
1119
+ if (refresh !== true) {
1120
+ var firstUnmaskedPosition = firstMaskPos;
1121
+ if (opts.insertMode == true) {
1122
+ if (opts.greedy == true) {
1123
+ var bfrClone = buffer.slice();
1124
+ while (getBufferElement(bfrClone, firstUnmaskedPosition, true) != getPlaceHolder(firstUnmaskedPosition) && firstUnmaskedPosition <= p) {
1125
+ firstUnmaskedPosition = firstUnmaskedPosition == maskL ? (maskL + 1) : seekNext(buffer, firstUnmaskedPosition);
1126
+ }
1127
+ }
1128
+
1129
+ if (firstUnmaskedPosition <= p && (opts.greedy || buffer.length < maskL)) {
1130
+ if (buffer[firstMaskPos] != getPlaceHolder(firstMaskPos) && buffer.length < maskL) {
1131
+ var offset = prepareBuffer(buffer, -1, isRTL);
1132
+ if (pos.end != 0) p = p + offset;
1133
+ maskL = buffer.length;
1134
+ }
1135
+ shiftL(firstUnmaskedPosition, opts.numericInput ? seekPrevious(buffer, p) : p, c);
1136
+ } else writeOutBuffer = false;
1137
+ } else setBufferElement(buffer, opts.numericInput ? seekPrevious(buffer, p) : p, c);
1138
+ }
1139
+ if (writeOutBuffer) {
1140
+ writeBuffer(input, buffer, opts.numericInput && p == 0 ? seekNext(buffer, p) : p);
1141
+ setTimeout(function () { //timeout needed for IE
1142
+ if (isComplete(input))
1143
+ $input.trigger("complete");
1144
+ }, 0);
1145
+ }
1146
+ } else if (android) writeBuffer(input, buffer, pos.begin);
1147
+ }
1148
+ else {
1149
+ var p = seekNext(buffer, pos.begin - 1), np;
1150
+ prepareBuffer(buffer, p, isRTL);
1151
+ if ((np = isValid(p, c, buffer, false, isRTL)) !== false) {
1152
+ var refresh = false;
1153
+ if (np !== true) {
1154
+ refresh = np["refresh"]; //only rewrite buffer from isValid
1155
+ p = np.pos != undefined ? np.pos : p; //set new position from isValid
1156
+ c = np.c != undefined ? np.c : c; //set new char from isValid
1157
+ }
1158
+ if (refresh !== true) {
1159
+ if (opts.insertMode == true) {
1160
+ var lastUnmaskedPosition = getMaskLength();
1161
+ var bfrClone = buffer.slice();
1162
+ while (getBufferElement(bfrClone, lastUnmaskedPosition, true) != getPlaceHolder(lastUnmaskedPosition) && lastUnmaskedPosition >= p) {
1163
+ lastUnmaskedPosition = lastUnmaskedPosition == 0 ? -1 : seekPrevious(buffer, lastUnmaskedPosition);
1164
+ }
1165
+ if (lastUnmaskedPosition >= p)
1166
+ shiftR(p, buffer.length, c);
1167
+ else writeOutBuffer = false;
1168
+ } else setBufferElement(buffer, p, c);
1169
+ }
1170
+ if (writeOutBuffer) {
1171
+ var next = seekNext(buffer, p);
1172
+ writeBuffer(input, buffer, next);
1173
+
1174
+ setTimeout(function () { //timeout needed for IE
1175
+ if (isComplete(input))
1176
+ $input.trigger("complete");
1177
+ }, 0);
1178
+ }
1179
+ } else if (android) writeBuffer(input, buffer, pos.begin);
1180
+ }
1181
+ e.preventDefault();
1182
+ }
1183
+ }
1184
+ }
1185
+
1186
+ function keyupEvent(e) {
1187
+ var $input = $(this), input = this;
1188
+ var k = e.keyCode;
1189
+ opts.onKeyUp.call(this, e, opts); //extra stuff to execute on keyup
1190
+ if (k == opts.keyCode.TAB && $input.hasClass('focus.inputmask') && input._valueGet().length == 0) {
1191
+ buffer = getActiveBuffer().slice();
1192
+ writeBuffer(input, buffer);
1193
+ if (!isRTL) caret(input, 0);
1194
+ undoBuffer = input._valueGet();
1195
+ }
1196
+ }
1197
+ }
1198
+
1199
+ return this; //return this to expose publics
1200
+ };
1201
+ }
1202
+ })(jQuery);