jquery-inputmask-rails 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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);