]>
Commit | Line | Data |
---|---|---|
1 | /** | |
2 | * @license Input Mask plugin for jquery | |
3 | * http://github.com/RobinHerbots/jquery.inputmask | |
4 | * Copyright (c) 2010 - 2014 Robin Herbots | |
5 | * Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php) | |
6 | * Version: 0.0.0 | |
7 | */ | |
8 | ||
9 | (function ($) { | |
10 | if ($.fn.inputmask === undefined) { | |
11 | //helper functions | |
12 | function isInputEventSupported(eventName) { | |
13 | var el = document.createElement('input'), | |
14 | eventName = 'on' + eventName, | |
15 | isSupported = (eventName in el); | |
16 | if (!isSupported) { | |
17 | el.setAttribute(eventName, 'return;'); | |
18 | isSupported = typeof el[eventName] == 'function'; | |
19 | } | |
20 | el = null; | |
21 | return isSupported; | |
22 | } | |
23 | function resolveAlias(aliasStr, options, opts) { | |
24 | var aliasDefinition = opts.aliases[aliasStr]; | |
25 | if (aliasDefinition) { | |
26 | if (aliasDefinition.alias) resolveAlias(aliasDefinition.alias, undefined, opts); //alias is another alias | |
27 | $.extend(true, opts, aliasDefinition); //merge alias definition in the options | |
28 | $.extend(true, opts, options); //reapply extra given options | |
29 | return true; | |
30 | } | |
31 | return false; | |
32 | } | |
33 | function generateMaskSets(opts) { | |
34 | var ms = []; | |
35 | var genmasks = []; //used to keep track of the masks that where processed, to avoid duplicates | |
36 | function getMaskTemplate(mask) { | |
37 | if (opts.numericInput) { | |
38 | mask = mask.split('').reverse().join(''); | |
39 | } | |
40 | var escaped = false, outCount = 0, greedy = opts.greedy, repeat = opts.repeat; | |
41 | if (repeat == "*") greedy = false; | |
42 | //if (greedy == true && opts.placeholder == "") opts.placeholder = " "; | |
43 | if (mask.length == 1 && greedy == false && repeat != 0) { opts.placeholder = ""; } //hide placeholder with single non-greedy mask | |
44 | var singleMask = $.map(mask.split(""), function (element, index) { | |
45 | var outElem = []; | |
46 | if (element == opts.escapeChar) { | |
47 | escaped = true; | |
48 | } | |
49 | else if ((element != opts.optionalmarker.start && element != opts.optionalmarker.end) || escaped) { | |
50 | var maskdef = opts.definitions[element]; | |
51 | if (maskdef && !escaped) { | |
52 | for (var i = 0; i < maskdef.cardinality; i++) { | |
53 | outElem.push(opts.placeholder.charAt((outCount + i) % opts.placeholder.length)); | |
54 | } | |
55 | } else { | |
56 | outElem.push(element); | |
57 | escaped = false; | |
58 | } | |
59 | outCount += outElem.length; | |
60 | return outElem; | |
61 | } | |
62 | }); | |
63 | ||
64 | //allocate repetitions | |
65 | var repeatedMask = singleMask.slice(); | |
66 | for (var i = 1; i < repeat && greedy; i++) { | |
67 | repeatedMask = repeatedMask.concat(singleMask.slice()); | |
68 | } | |
69 | ||
70 | return { "mask": repeatedMask, "repeat": repeat, "greedy": greedy }; | |
71 | } | |
72 | //test definition => {fn: RegExp/function, cardinality: int, optionality: bool, newBlockMarker: bool, offset: int, casing: null/upper/lower, def: definitionSymbol} | |
73 | function getTestingChain(mask) { | |
74 | if (opts.numericInput) { | |
75 | mask = mask.split('').reverse().join(''); | |
76 | } | |
77 | var isOptional = false, escaped = false; | |
78 | var newBlockMarker = false; //indicates wheter the begin/ending of a block should be indicated | |
79 | ||
80 | return $.map(mask.split(""), function (element, index) { | |
81 | var outElem = []; | |
82 | ||
83 | if (element == opts.escapeChar) { | |
84 | escaped = true; | |
85 | } else if (element == opts.optionalmarker.start && !escaped) { | |
86 | isOptional = true; | |
87 | newBlockMarker = true; | |
88 | } | |
89 | else if (element == opts.optionalmarker.end && !escaped) { | |
90 | isOptional = false; | |
91 | newBlockMarker = true; | |
92 | } | |
93 | else { | |
94 | var maskdef = opts.definitions[element]; | |
95 | if (maskdef && !escaped) { | |
96 | var prevalidators = maskdef["prevalidator"], prevalidatorsL = prevalidators ? prevalidators.length : 0; | |
97 | for (var i = 1; i < maskdef.cardinality; i++) { | |
98 | var prevalidator = prevalidatorsL >= i ? prevalidators[i - 1] : [], validator = prevalidator["validator"], cardinality = prevalidator["cardinality"]; | |
99 | 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: maskdef["definitionSymbol"] || element }); | |
100 | if (isOptional == true) //reset newBlockMarker | |
101 | newBlockMarker = false; | |
102 | } | |
103 | 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: maskdef["definitionSymbol"] || element }); | |
104 | } else { | |
105 | outElem.push({ fn: null, cardinality: 0, optionality: isOptional, newBlockMarker: newBlockMarker, offset: 0, casing: null, def: element }); | |
106 | escaped = false; | |
107 | } | |
108 | //reset newBlockMarker | |
109 | newBlockMarker = false; | |
110 | return outElem; | |
111 | } | |
112 | }); | |
113 | } | |
114 | function markOptional(maskPart) { //needed for the clearOptionalTail functionality | |
115 | return opts.optionalmarker.start + maskPart + opts.optionalmarker.end; | |
116 | } | |
117 | function splitFirstOptionalEndPart(maskPart) { | |
118 | var optionalStartMarkers = 0, optionalEndMarkers = 0, mpl = maskPart.length; | |
119 | for (var i = 0; i < mpl; i++) { | |
120 | if (maskPart.charAt(i) == opts.optionalmarker.start) { | |
121 | optionalStartMarkers++; | |
122 | } | |
123 | if (maskPart.charAt(i) == opts.optionalmarker.end) { | |
124 | optionalEndMarkers++; | |
125 | } | |
126 | if (optionalStartMarkers > 0 && optionalStartMarkers == optionalEndMarkers) | |
127 | break; | |
128 | } | |
129 | var maskParts = [maskPart.substring(0, i)]; | |
130 | if (i < mpl) { | |
131 | maskParts.push(maskPart.substring(i + 1, mpl)); | |
132 | } | |
133 | return maskParts; | |
134 | } | |
135 | function splitFirstOptionalStartPart(maskPart) { | |
136 | var mpl = maskPart.length; | |
137 | for (var i = 0; i < mpl; i++) { | |
138 | if (maskPart.charAt(i) == opts.optionalmarker.start) { | |
139 | break; | |
140 | } | |
141 | } | |
142 | var maskParts = [maskPart.substring(0, i)]; | |
143 | if (i < mpl) { | |
144 | maskParts.push(maskPart.substring(i + 1, mpl)); | |
145 | } | |
146 | return maskParts; | |
147 | } | |
148 | function generateMask(maskPrefix, maskPart, metadata) { | |
149 | var maskParts = splitFirstOptionalEndPart(maskPart); | |
150 | var newMask, maskTemplate; | |
151 | ||
152 | var masks = splitFirstOptionalStartPart(maskParts[0]); | |
153 | if (masks.length > 1) { | |
154 | newMask = maskPrefix + masks[0] + markOptional(masks[1]) + (maskParts.length > 1 ? maskParts[1] : ""); | |
155 | if ($.inArray(newMask, genmasks) == -1 && newMask != "") { | |
156 | genmasks.push(newMask); | |
157 | maskTemplate = getMaskTemplate(newMask); | |
158 | ms.push({ | |
159 | "mask": newMask, | |
160 | "_buffer": maskTemplate["mask"], | |
161 | "buffer": maskTemplate["mask"].slice(), | |
162 | "tests": getTestingChain(newMask), | |
163 | "lastValidPosition": -1, | |
164 | "greedy": maskTemplate["greedy"], | |
165 | "repeat": maskTemplate["repeat"], | |
166 | "metadata": metadata | |
167 | }); | |
168 | } | |
169 | newMask = maskPrefix + masks[0] + (maskParts.length > 1 ? maskParts[1] : ""); | |
170 | if ($.inArray(newMask, genmasks) == -1 && newMask != "") { | |
171 | genmasks.push(newMask); | |
172 | maskTemplate = getMaskTemplate(newMask); | |
173 | ms.push({ | |
174 | "mask": newMask, | |
175 | "_buffer": maskTemplate["mask"], | |
176 | "buffer": maskTemplate["mask"].slice(), | |
177 | "tests": getTestingChain(newMask), | |
178 | "lastValidPosition": -1, | |
179 | "greedy": maskTemplate["greedy"], | |
180 | "repeat": maskTemplate["repeat"], | |
181 | "metadata": metadata | |
182 | }); | |
183 | } | |
184 | if (splitFirstOptionalStartPart(masks[1]).length > 1) { //optional contains another optional | |
185 | generateMask(maskPrefix + masks[0], masks[1] + maskParts[1], metadata); | |
186 | } | |
187 | if (maskParts.length > 1 && splitFirstOptionalStartPart(maskParts[1]).length > 1) { | |
188 | generateMask(maskPrefix + masks[0] + markOptional(masks[1]), maskParts[1], metadata); | |
189 | generateMask(maskPrefix + masks[0], maskParts[1], metadata); | |
190 | } | |
191 | } | |
192 | else { | |
193 | newMask = maskPrefix + maskParts; | |
194 | if ($.inArray(newMask, genmasks) == -1 && newMask != "") { | |
195 | genmasks.push(newMask); | |
196 | maskTemplate = getMaskTemplate(newMask); | |
197 | ms.push({ | |
198 | "mask": newMask, | |
199 | "_buffer": maskTemplate["mask"], | |
200 | "buffer": maskTemplate["mask"].slice(), | |
201 | "tests": getTestingChain(newMask), | |
202 | "lastValidPosition": -1, | |
203 | "greedy": maskTemplate["greedy"], | |
204 | "repeat": maskTemplate["repeat"], | |
205 | "metadata": metadata | |
206 | }); | |
207 | } | |
208 | } | |
209 | ||
210 | } | |
211 | ||
212 | if ($.isFunction(opts.mask)) { //allow mask to be a preprocessing fn - should return a valid mask | |
213 | opts.mask = opts.mask.call(this, opts); | |
214 | } | |
215 | if ($.isArray(opts.mask)) { | |
216 | $.each(opts.mask, function (ndx, msk) { | |
217 | if (msk["mask"] != undefined) { | |
218 | generateMask("", msk["mask"].toString(), msk); | |
219 | } else | |
220 | generateMask("", msk.toString()); | |
221 | }); | |
222 | } else generateMask("", opts.mask.toString()); | |
223 | ||
224 | return opts.greedy ? ms : ms.sort(function (a, b) { return a["mask"].length - b["mask"].length; }); | |
225 | } | |
226 | ||
227 | var msie10 = navigator.userAgent.match(new RegExp("msie 10", "i")) !== null, | |
228 | iphone = navigator.userAgent.match(new RegExp("iphone", "i")) !== null, | |
229 | android = navigator.userAgent.match(new RegExp("android.*safari.*", "i")) !== null, | |
230 | androidchrome = navigator.userAgent.match(new RegExp("android.*chrome.*", "i")) !== null, | |
231 | pasteEvent = isInputEventSupported('paste') ? 'paste' : isInputEventSupported('input') ? 'input' : "propertychange"; | |
232 | ||
233 | ||
234 | //masking scope | |
235 | //actionObj definition see below | |
236 | function maskScope(masksets, activeMasksetIndex, opts, actionObj) { | |
237 | var isRTL = false, | |
238 | valueOnFocus = getActiveBuffer().join(''), | |
239 | $el, chromeValueOnInput, | |
240 | skipKeyPressEvent = false, //Safari 5.1.x - modal dialog fires keypress twice workaround | |
241 | skipInputEvent = false, //skip when triggered from within inputmask | |
242 | ignorable = false; | |
243 | ||
244 | ||
245 | //maskset helperfunctions | |
246 | ||
247 | function getActiveMaskSet() { | |
248 | return masksets[activeMasksetIndex]; | |
249 | } | |
250 | ||
251 | function getActiveTests() { | |
252 | return getActiveMaskSet()['tests']; | |
253 | } | |
254 | ||
255 | function getActiveBufferTemplate() { | |
256 | return getActiveMaskSet()['_buffer']; | |
257 | } | |
258 | ||
259 | function getActiveBuffer() { | |
260 | return getActiveMaskSet()['buffer']; | |
261 | } | |
262 | ||
263 | function isValid(pos, c, strict) { //strict true ~ no correction or autofill | |
264 | strict = strict === true; //always set a value to strict to prevent possible strange behavior in the extensions | |
265 | ||
266 | function _isValid(position, activeMaskset, c, strict) { | |
267 | var testPos = determineTestPosition(position), loopend = c ? 1 : 0, chrs = '', buffer = activeMaskset["buffer"]; | |
268 | for (var i = activeMaskset['tests'][testPos].cardinality; i > loopend; i--) { | |
269 | chrs += getBufferElement(buffer, testPos - (i - 1)); | |
270 | } | |
271 | ||
272 | if (c) { | |
273 | chrs += c; | |
274 | } | |
275 | ||
276 | //return is false or a json object => { pos: ??, c: ??} or true | |
277 | return activeMaskset['tests'][testPos].fn != null ? | |
278 | activeMaskset['tests'][testPos].fn.test(chrs, buffer, position, strict, opts) | |
279 | : (c == getBufferElement(activeMaskset['_buffer'], position, true) || c == opts.skipOptionalPartCharacter) ? | |
280 | { "refresh": true, c: getBufferElement(activeMaskset['_buffer'], position, true), pos: position } | |
281 | : false; | |
282 | } | |
283 | ||
284 | function PostProcessResults(maskForwards, results) { | |
285 | var hasValidActual = false; | |
286 | $.each(results, function (ndx, rslt) { | |
287 | hasValidActual = $.inArray(rslt["activeMasksetIndex"], maskForwards) == -1 && rslt["result"] !== false; | |
288 | if (hasValidActual) return false; | |
289 | }); | |
290 | if (hasValidActual) { //strip maskforwards | |
291 | results = $.map(results, function (rslt, ndx) { | |
292 | if ($.inArray(rslt["activeMasksetIndex"], maskForwards) == -1) { | |
293 | return rslt; | |
294 | } else { | |
295 | masksets[rslt["activeMasksetIndex"]]["lastValidPosition"] = actualLVP; | |
296 | } | |
297 | }); | |
298 | } else { //keep maskforwards with the least forward | |
299 | var lowestPos = -1, lowestIndex = -1, rsltValid; | |
300 | $.each(results, function (ndx, rslt) { | |
301 | if ($.inArray(rslt["activeMasksetIndex"], maskForwards) != -1 && rslt["result"] !== false & (lowestPos == -1 || lowestPos > rslt["result"]["pos"])) { | |
302 | lowestPos = rslt["result"]["pos"]; | |
303 | lowestIndex = rslt["activeMasksetIndex"]; | |
304 | } | |
305 | }); | |
306 | results = $.map(results, function (rslt, ndx) { | |
307 | if ($.inArray(rslt["activeMasksetIndex"], maskForwards) != -1) { | |
308 | if (rslt["result"]["pos"] == lowestPos) { | |
309 | return rslt; | |
310 | } else if (rslt["result"] !== false) { | |
311 | for (var i = pos; i < lowestPos; i++) { | |
312 | rsltValid = _isValid(i, masksets[rslt["activeMasksetIndex"]], masksets[lowestIndex]["buffer"][i], true); | |
313 | if (rsltValid === false) { | |
314 | masksets[rslt["activeMasksetIndex"]]["lastValidPosition"] = lowestPos - 1; | |
315 | break; | |
316 | } else { | |
317 | setBufferElement(masksets[rslt["activeMasksetIndex"]]["buffer"], i, masksets[lowestIndex]["buffer"][i], true); | |
318 | masksets[rslt["activeMasksetIndex"]]["lastValidPosition"] = i; | |
319 | } | |
320 | } | |
321 | //also check check for the lowestpos with the new input | |
322 | rsltValid = _isValid(lowestPos, masksets[rslt["activeMasksetIndex"]], c, true); | |
323 | if (rsltValid !== false) { | |
324 | setBufferElement(masksets[rslt["activeMasksetIndex"]]["buffer"], lowestPos, c, true); | |
325 | masksets[rslt["activeMasksetIndex"]]["lastValidPosition"] = lowestPos; | |
326 | } | |
327 | //console.log("ndx " + rslt["activeMasksetIndex"] + " validate " + masksets[rslt["activeMasksetIndex"]]["buffer"].join('') + " lv " + masksets[rslt["activeMasksetIndex"]]['lastValidPosition']); | |
328 | return rslt; | |
329 | } | |
330 | } | |
331 | }); | |
332 | } | |
333 | return results; | |
334 | } | |
335 | ||
336 | if (strict) { | |
337 | var result = _isValid(pos, getActiveMaskSet(), c, strict); //only check validity in current mask when validating strict | |
338 | if (result === true) { | |
339 | result = { "pos": pos }; //always take a possible corrected maskposition into account | |
340 | } | |
341 | return result; | |
342 | } | |
343 | ||
344 | var results = [], result = false, currentActiveMasksetIndex = activeMasksetIndex, | |
345 | actualBuffer = getActiveBuffer().slice(), actualLVP = getActiveMaskSet()["lastValidPosition"], | |
346 | actualPrevious = seekPrevious(pos), | |
347 | maskForwards = []; | |
348 | $.each(masksets, function (index, value) { | |
349 | if (typeof (value) == "object") { | |
350 | activeMasksetIndex = index; | |
351 | ||
352 | var maskPos = pos; | |
353 | var lvp = getActiveMaskSet()['lastValidPosition'], | |
354 | rsltValid; | |
355 | if (lvp == actualLVP) { | |
356 | if ((maskPos - actualLVP) > 1) { | |
357 | for (var i = lvp == -1 ? 0 : lvp; i < maskPos; i++) { | |
358 | rsltValid = _isValid(i, getActiveMaskSet(), actualBuffer[i], true); | |
359 | if (rsltValid === false) { | |
360 | break; | |
361 | } else { | |
362 | setBufferElement(getActiveBuffer(), i, actualBuffer[i], true); | |
363 | if (rsltValid === true) { | |
364 | rsltValid = { "pos": i }; //always take a possible corrected maskposition into account | |
365 | } | |
366 | var newValidPosition = rsltValid.pos || i; | |
367 | if (getActiveMaskSet()['lastValidPosition'] < newValidPosition) | |
368 | getActiveMaskSet()['lastValidPosition'] = newValidPosition; //set new position from isValid | |
369 | } | |
370 | } | |
371 | } | |
372 | //does the input match on a further position? | |
373 | if (!isMask(maskPos) && !_isValid(maskPos, getActiveMaskSet(), c, strict)) { | |
374 | var maxForward = seekNext(maskPos) - maskPos; | |
375 | for (var fw = 0; fw < maxForward; fw++) { | |
376 | if (_isValid(++maskPos, getActiveMaskSet(), c, strict) !== false) | |
377 | break; | |
378 | } | |
379 | maskForwards.push(activeMasksetIndex); | |
380 | //console.log('maskforward ' + activeMasksetIndex + " pos " + pos + " maskPos " + maskPos); | |
381 | } | |
382 | } | |
383 | ||
384 | if (getActiveMaskSet()['lastValidPosition'] >= actualLVP || activeMasksetIndex == currentActiveMasksetIndex) { | |
385 | if (maskPos >= 0 && maskPos < getMaskLength()) { | |
386 | result = _isValid(maskPos, getActiveMaskSet(), c, strict); | |
387 | if (result !== false) { | |
388 | if (result === true) { | |
389 | result = { "pos": maskPos }; //always take a possible corrected maskposition into account | |
390 | } | |
391 | var newValidPosition = result.pos || maskPos; | |
392 | if (getActiveMaskSet()['lastValidPosition'] < newValidPosition) | |
393 | getActiveMaskSet()['lastValidPosition'] = newValidPosition; //set new position from isValid | |
394 | } | |
395 | //console.log("pos " + pos + " ndx " + activeMasksetIndex + " validate " + getActiveBuffer().join('') + " lv " + getActiveMaskSet()['lastValidPosition']); | |
396 | results.push({ "activeMasksetIndex": index, "result": result }); | |
397 | } | |
398 | } | |
399 | } | |
400 | }); | |
401 | activeMasksetIndex = currentActiveMasksetIndex; //reset activeMasksetIndex | |
402 | ||
403 | return PostProcessResults(maskForwards, results); //return results of the multiple mask validations | |
404 | } | |
405 | ||
406 | function determineActiveMasksetIndex() { | |
407 | var currentMasksetIndex = activeMasksetIndex, | |
408 | highestValid = { "activeMasksetIndex": 0, "lastValidPosition": -1, "next": -1 }; | |
409 | $.each(masksets, function (index, value) { | |
410 | if (typeof (value) == "object") { | |
411 | activeMasksetIndex = index; | |
412 | if (getActiveMaskSet()['lastValidPosition'] > highestValid['lastValidPosition']) { | |
413 | highestValid["activeMasksetIndex"] = index; | |
414 | highestValid["lastValidPosition"] = getActiveMaskSet()['lastValidPosition']; | |
415 | highestValid["next"] = seekNext(getActiveMaskSet()['lastValidPosition']); | |
416 | } else if (getActiveMaskSet()['lastValidPosition'] == highestValid['lastValidPosition'] && | |
417 | (highestValid['next'] == -1 || highestValid['next'] > seekNext(getActiveMaskSet()['lastValidPosition']))) { | |
418 | highestValid["activeMasksetIndex"] = index; | |
419 | highestValid["lastValidPosition"] = getActiveMaskSet()['lastValidPosition']; | |
420 | highestValid["next"] = seekNext(getActiveMaskSet()['lastValidPosition']); | |
421 | } | |
422 | } | |
423 | }); | |
424 | ||
425 | activeMasksetIndex = highestValid["lastValidPosition"] != -1 && masksets[currentMasksetIndex]["lastValidPosition"] == highestValid["lastValidPosition"] ? currentMasksetIndex : highestValid["activeMasksetIndex"]; | |
426 | if (currentMasksetIndex != activeMasksetIndex) { | |
427 | clearBuffer(getActiveBuffer(), seekNext(highestValid["lastValidPosition"]), getMaskLength()); | |
428 | getActiveMaskSet()["writeOutBuffer"] = true; | |
429 | } | |
430 | $el.data('_inputmask')['activeMasksetIndex'] = activeMasksetIndex; //store the activeMasksetIndex | |
431 | } | |
432 | ||
433 | function isMask(pos) { | |
434 | var testPos = determineTestPosition(pos); | |
435 | var test = getActiveTests()[testPos]; | |
436 | ||
437 | return test != undefined ? test.fn : false; | |
438 | } | |
439 | ||
440 | function determineTestPosition(pos) { | |
441 | return pos % getActiveTests().length; | |
442 | } | |
443 | ||
444 | function getMaskLength() { | |
445 | return opts.getMaskLength(getActiveBufferTemplate(), getActiveMaskSet()['greedy'], getActiveMaskSet()['repeat'], getActiveBuffer(), opts); | |
446 | } | |
447 | ||
448 | //pos: from position | |
449 | ||
450 | function seekNext(pos) { | |
451 | var maskL = getMaskLength(); | |
452 | if (pos >= maskL) return maskL; | |
453 | var position = pos; | |
454 | while (++position < maskL && !isMask(position)) { | |
455 | } | |
456 | return position; | |
457 | } | |
458 | ||
459 | //pos: from position | |
460 | ||
461 | function seekPrevious(pos) { | |
462 | var position = pos; | |
463 | if (position <= 0) return 0; | |
464 | ||
465 | while (--position > 0 && !isMask(position)) { | |
466 | } | |
467 | return position; | |
468 | } | |
469 | ||
470 | function setBufferElement(buffer, position, element, autoPrepare) { | |
471 | if (autoPrepare) position = prepareBuffer(buffer, position); | |
472 | ||
473 | var test = getActiveTests()[determineTestPosition(position)]; | |
474 | var elem = element; | |
475 | if (elem != undefined && test != undefined) { | |
476 | switch (test.casing) { | |
477 | case "upper": | |
478 | elem = element.toUpperCase(); | |
479 | break; | |
480 | case "lower": | |
481 | elem = element.toLowerCase(); | |
482 | break; | |
483 | } | |
484 | } | |
485 | ||
486 | buffer[position] = elem; | |
487 | } | |
488 | ||
489 | function getBufferElement(buffer, position, autoPrepare) { | |
490 | if (autoPrepare) position = prepareBuffer(buffer, position); | |
491 | return buffer[position]; | |
492 | } | |
493 | ||
494 | //needed to handle the non-greedy mask repetitions | |
495 | ||
496 | function prepareBuffer(buffer, position) { | |
497 | var j; | |
498 | while (buffer[position] == undefined && buffer.length < getMaskLength()) { | |
499 | j = 0; | |
500 | while (getActiveBufferTemplate()[j] !== undefined) { //add a new buffer | |
501 | buffer.push(getActiveBufferTemplate()[j++]); | |
502 | } | |
503 | } | |
504 | ||
505 | return position; | |
506 | } | |
507 | ||
508 | function writeBuffer(input, buffer, caretPos) { | |
509 | input._valueSet(buffer.join('')); | |
510 | if (caretPos != undefined) { | |
511 | caret(input, caretPos); | |
512 | } | |
513 | } | |
514 | ||
515 | function clearBuffer(buffer, start, end, stripNomasks) { | |
516 | for (var i = start, maskL = getMaskLength() ; i < end && i < maskL; i++) { | |
517 | if (stripNomasks === true) { | |
518 | if (!isMask(i)) | |
519 | setBufferElement(buffer, i, ""); | |
520 | } else | |
521 | setBufferElement(buffer, i, getBufferElement(getActiveBufferTemplate().slice(), i, true)); | |
522 | } | |
523 | } | |
524 | ||
525 | function setReTargetPlaceHolder(buffer, pos) { | |
526 | var testPos = determineTestPosition(pos); | |
527 | setBufferElement(buffer, pos, getBufferElement(getActiveBufferTemplate(), testPos)); | |
528 | } | |
529 | ||
530 | function getPlaceHolder(pos) { | |
531 | return opts.placeholder.charAt(pos % opts.placeholder.length); | |
532 | } | |
533 | ||
534 | function checkVal(input, writeOut, strict, nptvl, intelliCheck) { | |
535 | var inputValue = nptvl != undefined ? nptvl.slice() : truncateInput(input._valueGet()).split(''); | |
536 | ||
537 | $.each(masksets, function (ndx, ms) { | |
538 | if (typeof (ms) == "object") { | |
539 | ms["buffer"] = ms["_buffer"].slice(); | |
540 | ms["lastValidPosition"] = -1; | |
541 | ms["p"] = -1; | |
542 | } | |
543 | }); | |
544 | if (strict !== true) activeMasksetIndex = 0; | |
545 | if (writeOut) input._valueSet(""); //initial clear | |
546 | var ml = getMaskLength(); | |
547 | $.each(inputValue, function (ndx, charCode) { | |
548 | if (intelliCheck === true) { | |
549 | var p = getActiveMaskSet()["p"], lvp = p == -1 ? p : seekPrevious(p), | |
550 | pos = lvp == -1 ? ndx : seekNext(lvp); | |
551 | if ($.inArray(charCode, getActiveBufferTemplate().slice(lvp + 1, pos)) == -1) { | |
552 | keypressEvent.call(input, undefined, true, charCode.charCodeAt(0), writeOut, strict, ndx); | |
553 | } | |
554 | } else { | |
555 | keypressEvent.call(input, undefined, true, charCode.charCodeAt(0), writeOut, strict, ndx); | |
556 | } | |
557 | }); | |
558 | ||
559 | if (strict === true && getActiveMaskSet()["p"] != -1) { | |
560 | getActiveMaskSet()["lastValidPosition"] = seekPrevious(getActiveMaskSet()["p"]); | |
561 | } | |
562 | } | |
563 | ||
564 | function escapeRegex(str) { | |
565 | return $.inputmask.escapeRegex.call(this, str); | |
566 | } | |
567 | ||
568 | function truncateInput(inputValue) { | |
569 | return inputValue.replace(new RegExp("(" + escapeRegex(getActiveBufferTemplate().join('')) + ")*$"), ""); | |
570 | } | |
571 | ||
572 | function clearOptionalTail(input) { | |
573 | var buffer = getActiveBuffer(), tmpBuffer = buffer.slice(), testPos, pos; | |
574 | for (var pos = tmpBuffer.length - 1; pos >= 0; pos--) { | |
575 | var testPos = determineTestPosition(pos); | |
576 | if (getActiveTests()[testPos].optionality) { | |
577 | if (!isMask(pos) || !isValid(pos, buffer[pos], true)) | |
578 | tmpBuffer.pop(); | |
579 | else break; | |
580 | } else break; | |
581 | } | |
582 | writeBuffer(input, tmpBuffer); | |
583 | } | |
584 | ||
585 | function unmaskedvalue($input, skipDatepickerCheck) { | |
586 | if (getActiveTests() && (skipDatepickerCheck === true || !$input.hasClass('hasDatepicker'))) { | |
587 | //checkVal(input, false, true); | |
588 | var umValue = $.map(getActiveBuffer(), function (element, index) { | |
589 | return isMask(index) && isValid(index, element, true) ? element : null; | |
590 | }); | |
591 | var unmaskedValue = (isRTL ? umValue.reverse() : umValue).join(''); | |
592 | return opts.onUnMask != undefined ? opts.onUnMask.call(this, getActiveBuffer().join(''), unmaskedValue) : unmaskedValue; | |
593 | } else { | |
594 | return $input[0]._valueGet(); | |
595 | } | |
596 | } | |
597 | ||
598 | function TranslatePosition(pos) { | |
599 | if (isRTL && typeof pos == 'number' && (!opts.greedy || opts.placeholder != "")) { | |
600 | var bffrLght = getActiveBuffer().length; | |
601 | pos = bffrLght - pos; | |
602 | } | |
603 | return pos; | |
604 | } | |
605 | ||
606 | function caret(input, begin, end) { | |
607 | var npt = input.jquery && input.length > 0 ? input[0] : input, range; | |
608 | if (typeof begin == 'number') { | |
609 | begin = TranslatePosition(begin); | |
610 | end = TranslatePosition(end); | |
611 | if (!$(input).is(':visible')) { | |
612 | return; | |
613 | } | |
614 | end = (typeof end == 'number') ? end : begin; | |
615 | npt.scrollLeft = npt.scrollWidth; | |
616 | if (opts.insertMode == false && begin == end) end++; //set visualization for insert/overwrite mode | |
617 | if (npt.setSelectionRange) { | |
618 | npt.selectionStart = begin; | |
619 | npt.selectionEnd = android ? begin : end; | |
620 | ||
621 | } else if (npt.createTextRange) { | |
622 | range = npt.createTextRange(); | |
623 | range.collapse(true); | |
624 | range.moveEnd('character', end); | |
625 | range.moveStart('character', begin); | |
626 | range.select(); | |
627 | } | |
628 | } else { | |
629 | if (!$(input).is(':visible')) { | |
630 | return { "begin": 0, "end": 0 }; | |
631 | } | |
632 | if (npt.setSelectionRange) { | |
633 | begin = npt.selectionStart; | |
634 | end = npt.selectionEnd; | |
635 | } else if (document.selection && document.selection.createRange) { | |
636 | range = document.selection.createRange(); | |
637 | begin = 0 - range.duplicate().moveStart('character', -100000); | |
638 | end = begin + range.text.length; | |
639 | } | |
640 | begin = TranslatePosition(begin); | |
641 | end = TranslatePosition(end); | |
642 | return { "begin": begin, "end": end }; | |
643 | } | |
644 | } | |
645 | ||
646 | function isComplete(buffer) { //return true / false / undefined (repeat *) | |
647 | if (opts.repeat == "*") return undefined; | |
648 | var complete = false, highestValidPosition = 0, currentActiveMasksetIndex = activeMasksetIndex; | |
649 | $.each(masksets, function (ndx, ms) { | |
650 | if (typeof (ms) == "object") { | |
651 | activeMasksetIndex = ndx; | |
652 | var aml = seekPrevious(getMaskLength()); | |
653 | if (ms["lastValidPosition"] >= highestValidPosition && ms["lastValidPosition"] == aml) { | |
654 | var msComplete = true; | |
655 | for (var i = 0; i <= aml; i++) { | |
656 | var mask = isMask(i), testPos = determineTestPosition(i); | |
657 | if ((mask && (buffer[i] == undefined || buffer[i] == getPlaceHolder(i))) || (!mask && buffer[i] != getActiveBufferTemplate()[testPos])) { | |
658 | msComplete = false; | |
659 | break; | |
660 | } | |
661 | } | |
662 | complete = complete || msComplete; | |
663 | if (complete) //break loop | |
664 | return false; | |
665 | } | |
666 | highestValidPosition = ms["lastValidPosition"]; | |
667 | } | |
668 | }); | |
669 | activeMasksetIndex = currentActiveMasksetIndex; //reset activeMaskset | |
670 | return complete; | |
671 | } | |
672 | ||
673 | function isSelection(begin, end) { | |
674 | return isRTL ? (begin - end) > 1 || ((begin - end) == 1 && opts.insertMode) : | |
675 | (end - begin) > 1 || ((end - begin) == 1 && opts.insertMode); | |
676 | } | |
677 | ||
678 | ||
679 | //private functions | |
680 | function installEventRuler(npt) { | |
681 | var events = $._data(npt).events; | |
682 | ||
683 | $.each(events, function (eventType, eventHandlers) { | |
684 | $.each(eventHandlers, function (ndx, eventHandler) { | |
685 | if (eventHandler.namespace == "inputmask") { | |
686 | if (eventHandler.type != "setvalue") { | |
687 | var handler = eventHandler.handler; | |
688 | eventHandler.handler = function (e) { | |
689 | if (this.readOnly || this.disabled) | |
690 | e.preventDefault; | |
691 | else | |
692 | return handler.apply(this, arguments); | |
693 | }; | |
694 | } | |
695 | } | |
696 | }); | |
697 | }); | |
698 | } | |
699 | ||
700 | function patchValueProperty(npt) { | |
701 | var valueProperty; | |
702 | if (Object.getOwnPropertyDescriptor) | |
703 | valueProperty = Object.getOwnPropertyDescriptor(npt, "value"); | |
704 | if (valueProperty && valueProperty.get) { | |
705 | if (!npt._valueGet) { | |
706 | var valueGet = valueProperty.get; | |
707 | var valueSet = valueProperty.set; | |
708 | npt._valueGet = function () { | |
709 | return isRTL ? valueGet.call(this).split('').reverse().join('') : valueGet.call(this); | |
710 | }; | |
711 | npt._valueSet = function (value) { | |
712 | valueSet.call(this, isRTL ? value.split('').reverse().join('') : value); | |
713 | }; | |
714 | ||
715 | Object.defineProperty(npt, "value", { | |
716 | get: function () { | |
717 | var $self = $(this), inputData = $(this).data('_inputmask'), masksets = inputData['masksets'], | |
718 | activeMasksetIndex = inputData['activeMasksetIndex']; | |
719 | return inputData && inputData['opts'].autoUnmask ? $self.inputmask('unmaskedvalue') : valueGet.call(this) != masksets[activeMasksetIndex]['_buffer'].join('') ? valueGet.call(this) : ''; | |
720 | }, | |
721 | set: function (value) { | |
722 | valueSet.call(this, value); | |
723 | $(this).triggerHandler('setvalue.inputmask'); | |
724 | } | |
725 | }); | |
726 | } | |
727 | } else if (document.__lookupGetter__ && npt.__lookupGetter__("value")) { | |
728 | if (!npt._valueGet) { | |
729 | var valueGet = npt.__lookupGetter__("value"); | |
730 | var valueSet = npt.__lookupSetter__("value"); | |
731 | npt._valueGet = function () { | |
732 | return isRTL ? valueGet.call(this).split('').reverse().join('') : valueGet.call(this); | |
733 | }; | |
734 | npt._valueSet = function (value) { | |
735 | valueSet.call(this, isRTL ? value.split('').reverse().join('') : value); | |
736 | }; | |
737 | ||
738 | npt.__defineGetter__("value", function () { | |
739 | var $self = $(this), inputData = $(this).data('_inputmask'), masksets = inputData['masksets'], | |
740 | activeMasksetIndex = inputData['activeMasksetIndex']; | |
741 | return inputData && inputData['opts'].autoUnmask ? $self.inputmask('unmaskedvalue') : valueGet.call(this) != masksets[activeMasksetIndex]['_buffer'].join('') ? valueGet.call(this) : ''; | |
742 | }); | |
743 | npt.__defineSetter__("value", function (value) { | |
744 | valueSet.call(this, value); | |
745 | $(this).triggerHandler('setvalue.inputmask'); | |
746 | }); | |
747 | } | |
748 | } else { | |
749 | if (!npt._valueGet) { | |
750 | npt._valueGet = function () { return isRTL ? this.value.split('').reverse().join('') : this.value; }; | |
751 | npt._valueSet = function (value) { this.value = isRTL ? value.split('').reverse().join('') : value; }; | |
752 | } | |
753 | if ($.valHooks.text == undefined || $.valHooks.text.inputmaskpatch != true) { | |
754 | var valueGet = $.valHooks.text && $.valHooks.text.get ? $.valHooks.text.get : function (elem) { return elem.value; }; | |
755 | var valueSet = $.valHooks.text && $.valHooks.text.set ? $.valHooks.text.set : function (elem, value) { | |
756 | elem.value = value; | |
757 | return elem; | |
758 | }; | |
759 | ||
760 | jQuery.extend($.valHooks, { | |
761 | text: { | |
762 | get: function (elem) { | |
763 | var $elem = $(elem); | |
764 | if ($elem.data('_inputmask')) { | |
765 | if ($elem.data('_inputmask')['opts'].autoUnmask) | |
766 | return $elem.inputmask('unmaskedvalue'); | |
767 | else { | |
768 | var result = valueGet(elem), | |
769 | inputData = $elem.data('_inputmask'), masksets = inputData['masksets'], | |
770 | activeMasksetIndex = inputData['activeMasksetIndex']; | |
771 | return result != masksets[activeMasksetIndex]['_buffer'].join('') ? result : ''; | |
772 | } | |
773 | } else return valueGet(elem); | |
774 | }, | |
775 | set: function (elem, value) { | |
776 | var $elem = $(elem); | |
777 | var result = valueSet(elem, value); | |
778 | if ($elem.data('_inputmask')) $elem.triggerHandler('setvalue.inputmask'); | |
779 | return result; | |
780 | }, | |
781 | inputmaskpatch: true | |
782 | } | |
783 | }); | |
784 | } | |
785 | } | |
786 | } | |
787 | ||
788 | //shift chars to left from start to end and put c at end position if defined | |
789 | ||
790 | function shiftL(start, end, c, maskJumps) { | |
791 | var buffer = getActiveBuffer(); | |
792 | if (maskJumps !== false) //jumping over nonmask position | |
793 | while (!isMask(start) && start - 1 >= 0) start--; | |
794 | for (var i = start; i < end && i < getMaskLength() ; i++) { | |
795 | if (isMask(i)) { | |
796 | setReTargetPlaceHolder(buffer, i); | |
797 | var j = seekNext(i); | |
798 | var p = getBufferElement(buffer, j); | |
799 | if (p != getPlaceHolder(j)) { | |
800 | if (j < getMaskLength() && isValid(i, p, true) !== false && getActiveTests()[determineTestPosition(i)].def == getActiveTests()[determineTestPosition(j)].def) { | |
801 | setBufferElement(buffer, i, p, true); | |
802 | } else { | |
803 | if (isMask(i)) | |
804 | break; | |
805 | } | |
806 | } | |
807 | } else { | |
808 | setReTargetPlaceHolder(buffer, i); | |
809 | } | |
810 | } | |
811 | if (c != undefined) | |
812 | setBufferElement(buffer, seekPrevious(end), c); | |
813 | ||
814 | if (getActiveMaskSet()["greedy"] == false) { | |
815 | var trbuffer = truncateInput(buffer.join('')).split(''); | |
816 | buffer.length = trbuffer.length; | |
817 | for (var i = 0, bl = buffer.length; i < bl; i++) { | |
818 | buffer[i] = trbuffer[i]; | |
819 | } | |
820 | if (buffer.length == 0) getActiveMaskSet()["buffer"] = getActiveBufferTemplate().slice(); | |
821 | } | |
822 | return start; //return the used start position | |
823 | } | |
824 | ||
825 | function shiftR(start, end, c) { | |
826 | var buffer = getActiveBuffer(); | |
827 | if (getBufferElement(buffer, start, true) != getPlaceHolder(start)) { | |
828 | for (var i = seekPrevious(end) ; i > start && i >= 0; i--) { | |
829 | if (isMask(i)) { | |
830 | var j = seekPrevious(i); | |
831 | var t = getBufferElement(buffer, j); | |
832 | if (t != getPlaceHolder(j)) { | |
833 | if (isValid(j, t, true) !== false && getActiveTests()[determineTestPosition(i)].def == getActiveTests()[determineTestPosition(j)].def) { | |
834 | setBufferElement(buffer, i, t, true); | |
835 | setReTargetPlaceHolder(buffer, j); | |
836 | } //else break; | |
837 | } | |
838 | } else | |
839 | setReTargetPlaceHolder(buffer, i); | |
840 | } | |
841 | } | |
842 | if (c != undefined && getBufferElement(buffer, start) == getPlaceHolder(start)) | |
843 | setBufferElement(buffer, start, c); | |
844 | var lengthBefore = buffer.length; | |
845 | if (getActiveMaskSet()["greedy"] == false) { | |
846 | var trbuffer = truncateInput(buffer.join('')).split(''); | |
847 | buffer.length = trbuffer.length; | |
848 | for (var i = 0, bl = buffer.length; i < bl; i++) { | |
849 | buffer[i] = trbuffer[i]; | |
850 | } | |
851 | if (buffer.length == 0) getActiveMaskSet()["buffer"] = getActiveBufferTemplate().slice(); | |
852 | } | |
853 | return end - (lengthBefore - buffer.length); //return new start position | |
854 | } | |
855 | ||
856 | function HandleRemove(input, k, pos) { | |
857 | if (opts.numericInput || isRTL) { | |
858 | switch (k) { | |
859 | case opts.keyCode.BACKSPACE: | |
860 | k = opts.keyCode.DELETE; | |
861 | break; | |
862 | case opts.keyCode.DELETE: | |
863 | k = opts.keyCode.BACKSPACE; | |
864 | break; | |
865 | } | |
866 | if (isRTL) { | |
867 | var pend = pos.end; | |
868 | pos.end = pos.begin; | |
869 | pos.begin = pend; | |
870 | } | |
871 | } | |
872 | ||
873 | var isSelection = true; | |
874 | if (pos.begin == pos.end) { | |
875 | var posBegin = k == opts.keyCode.BACKSPACE ? pos.begin - 1 : pos.begin; | |
876 | if (opts.isNumeric && opts.radixPoint != "" && getActiveBuffer()[posBegin] == opts.radixPoint) { | |
877 | pos.begin = (getActiveBuffer().length - 1 == posBegin) /* radixPoint is latest? delete it */ ? pos.begin : k == opts.keyCode.BACKSPACE ? posBegin : seekNext(posBegin); | |
878 | pos.end = pos.begin; | |
879 | } | |
880 | isSelection = false; | |
881 | if (k == opts.keyCode.BACKSPACE) | |
882 | pos.begin--; | |
883 | else if (k == opts.keyCode.DELETE) | |
884 | pos.end++; | |
885 | } else if (pos.end - pos.begin == 1 && !opts.insertMode) { | |
886 | isSelection = false; | |
887 | if (k == opts.keyCode.BACKSPACE) | |
888 | pos.begin--; | |
889 | } | |
890 | ||
891 | clearBuffer(getActiveBuffer(), pos.begin, pos.end); | |
892 | ||
893 | var ml = getMaskLength(); | |
894 | if (opts.greedy == false) { | |
895 | shiftL(pos.begin, ml, undefined, !isRTL && (k == opts.keyCode.BACKSPACE && !isSelection)); | |
896 | } else { | |
897 | var newpos = pos.begin; | |
898 | for (var i = pos.begin; i < pos.end; i++) { //seeknext to skip placeholders at start in selection | |
899 | if (isMask(i) || !isSelection) | |
900 | newpos = shiftL(pos.begin, ml, undefined, !isRTL && (k == opts.keyCode.BACKSPACE && !isSelection)); | |
901 | } | |
902 | if (!isSelection) pos.begin = newpos; | |
903 | } | |
904 | var firstMaskPos = seekNext(-1); | |
905 | clearBuffer(getActiveBuffer(), pos.begin, pos.end, true); | |
906 | checkVal(input, false, masksets[1] == undefined || firstMaskPos >= pos.end, getActiveBuffer()); | |
907 | if (getActiveMaskSet()['lastValidPosition'] < firstMaskPos) { | |
908 | getActiveMaskSet()["lastValidPosition"] = -1; | |
909 | getActiveMaskSet()["p"] = firstMaskPos; | |
910 | } else { | |
911 | getActiveMaskSet()["p"] = pos.begin; | |
912 | } | |
913 | } | |
914 | ||
915 | function keydownEvent(e) { | |
916 | //Safari 5.1.x - modal dialog fires keypress twice workaround | |
917 | skipKeyPressEvent = false; | |
918 | var input = this, $input = $(input), k = e.keyCode, pos = caret(input); | |
919 | ||
920 | //backspace, delete, and escape get special treatment | |
921 | if (k == opts.keyCode.BACKSPACE || k == opts.keyCode.DELETE || (iphone && k == 127) || e.ctrlKey && k == 88) { //backspace/delete | |
922 | e.preventDefault(); //stop default action but allow propagation | |
923 | if (k == 88) valueOnFocus = getActiveBuffer().join(''); | |
924 | HandleRemove(input, k, pos); | |
925 | determineActiveMasksetIndex(); | |
926 | writeBuffer(input, getActiveBuffer(), getActiveMaskSet()["p"]); | |
927 | if (input._valueGet() == getActiveBufferTemplate().join('')) | |
928 | $input.trigger('cleared'); | |
929 | ||
930 | if (opts.showTooltip) { //update tooltip | |
931 | $input.prop("title", getActiveMaskSet()["mask"]); | |
932 | } | |
933 | } else if (k == opts.keyCode.END || k == opts.keyCode.PAGE_DOWN) { //when END or PAGE_DOWN pressed set position at lastmatch | |
934 | setTimeout(function () { | |
935 | var caretPos = seekNext(getActiveMaskSet()["lastValidPosition"]); | |
936 | if (!opts.insertMode && caretPos == getMaskLength() && !e.shiftKey) caretPos--; | |
937 | caret(input, e.shiftKey ? pos.begin : caretPos, caretPos); | |
938 | }, 0); | |
939 | } else if ((k == opts.keyCode.HOME && !e.shiftKey) || k == opts.keyCode.PAGE_UP) { //Home or page_up | |
940 | caret(input, 0, e.shiftKey ? pos.begin : 0); | |
941 | } else if (k == opts.keyCode.ESCAPE || (k == 90 && e.ctrlKey)) { //escape && undo | |
942 | checkVal(input, true, false, valueOnFocus.split('')); | |
943 | $input.click(); | |
944 | } else if (k == opts.keyCode.INSERT && !(e.shiftKey || e.ctrlKey)) { //insert | |
945 | opts.insertMode = !opts.insertMode; | |
946 | caret(input, !opts.insertMode && pos.begin == getMaskLength() ? pos.begin - 1 : pos.begin); | |
947 | } else if (opts.insertMode == false && !e.shiftKey) { | |
948 | if (k == opts.keyCode.RIGHT) { | |
949 | setTimeout(function () { | |
950 | var caretPos = caret(input); | |
951 | caret(input, caretPos.begin); | |
952 | }, 0); | |
953 | } else if (k == opts.keyCode.LEFT) { | |
954 | setTimeout(function () { | |
955 | var caretPos = caret(input); | |
956 | caret(input, caretPos.begin - 1); | |
957 | }, 0); | |
958 | } | |
959 | } | |
960 | ||
961 | var currentCaretPos = caret(input); | |
962 | if (opts.onKeyDown.call(this, e, getActiveBuffer(), opts) === true) //extra stuff to execute on keydown | |
963 | caret(input, currentCaretPos.begin, currentCaretPos.end); | |
964 | ignorable = $.inArray(k, opts.ignorables) != -1; | |
965 | } | |
966 | ||
967 | ||
968 | function keypressEvent(e, checkval, k, writeOut, strict, ndx) { | |
969 | //Safari 5.1.x - modal dialog fires keypress twice workaround | |
970 | if (k == undefined && skipKeyPressEvent) return false; | |
971 | skipKeyPressEvent = true; | |
972 | ||
973 | var input = this, $input = $(input); | |
974 | ||
975 | e = e || window.event; | |
976 | var k = checkval ? k : (e.which || e.charCode || e.keyCode); | |
977 | ||
978 | if (checkval !== true && (!(e.ctrlKey && e.altKey) && (e.ctrlKey || e.metaKey || ignorable))) { | |
979 | return true; | |
980 | } else { | |
981 | if (k) { | |
982 | //special treat the decimal separator | |
983 | if (checkval !== true && k == 46 && e.shiftKey == false && opts.radixPoint == ",") k = 44; | |
984 | ||
985 | var pos, results, result, c = String.fromCharCode(k); | |
986 | if (checkval) { | |
987 | var pcaret = strict ? ndx : getActiveMaskSet()["lastValidPosition"] + 1; | |
988 | pos = { begin: pcaret, end: pcaret }; | |
989 | } else { | |
990 | pos = caret(input); | |
991 | } | |
992 | ||
993 | //should we clear a possible selection?? | |
994 | var isSlctn = isSelection(pos.begin, pos.end), redetermineLVP = false, | |
995 | initialIndex = activeMasksetIndex; | |
996 | if (isSlctn) { | |
997 | activeMasksetIndex = initialIndex; | |
998 | $.each(masksets, function (ndx, lmnt) { //init undobuffer for recovery when not valid | |
999 | if (typeof (lmnt) == "object") { | |
1000 | activeMasksetIndex = ndx; | |
1001 | getActiveMaskSet()["undoBuffer"] = getActiveBuffer().join(''); | |
1002 | } | |
1003 | }); | |
1004 | HandleRemove(input, opts.keyCode.DELETE, pos); | |
1005 | if (!opts.insertMode) { //preserve some space | |
1006 | $.each(masksets, function (ndx, lmnt) { | |
1007 | if (typeof (lmnt) == "object") { | |
1008 | activeMasksetIndex = ndx; | |
1009 | shiftR(pos.begin, getMaskLength()); | |
1010 | getActiveMaskSet()["lastValidPosition"] = seekNext(getActiveMaskSet()["lastValidPosition"]); | |
1011 | } | |
1012 | }); | |
1013 | } | |
1014 | activeMasksetIndex = initialIndex; //restore index | |
1015 | } | |
1016 | ||
1017 | var radixPosition = getActiveBuffer().join('').indexOf(opts.radixPoint); | |
1018 | if (opts.isNumeric && checkval !== true && radixPosition != -1) { | |
1019 | if (opts.greedy && pos.begin <= radixPosition) { | |
1020 | pos.begin = seekPrevious(pos.begin); | |
1021 | pos.end = pos.begin; | |
1022 | } else if (c == opts.radixPoint) { | |
1023 | pos.begin = radixPosition; | |
1024 | pos.end = pos.begin; | |
1025 | } | |
1026 | } | |
1027 | ||
1028 | ||
1029 | var p = pos.begin; | |
1030 | results = isValid(p, c, strict); | |
1031 | if (strict === true) results = [{ "activeMasksetIndex": activeMasksetIndex, "result": results }]; | |
1032 | var minimalForwardPosition = -1; | |
1033 | $.each(results, function (index, result) { | |
1034 | activeMasksetIndex = result["activeMasksetIndex"]; | |
1035 | getActiveMaskSet()["writeOutBuffer"] = true; | |
1036 | var np = result["result"]; | |
1037 | if (np !== false) { | |
1038 | var refresh = false, buffer = getActiveBuffer(); | |
1039 | if (np !== true) { | |
1040 | refresh = np["refresh"]; //only rewrite buffer from isValid | |
1041 | p = np.pos != undefined ? np.pos : p; //set new position from isValid | |
1042 | c = np.c != undefined ? np.c : c; //set new char from isValid | |
1043 | } | |
1044 | if (refresh !== true) { | |
1045 | if (opts.insertMode == true) { | |
1046 | var lastUnmaskedPosition = getMaskLength(); | |
1047 | var bfrClone = buffer.slice(); | |
1048 | while (getBufferElement(bfrClone, lastUnmaskedPosition, true) != getPlaceHolder(lastUnmaskedPosition) && lastUnmaskedPosition >= p) { | |
1049 | lastUnmaskedPosition = lastUnmaskedPosition == 0 ? -1 : seekPrevious(lastUnmaskedPosition); | |
1050 | } | |
1051 | if (lastUnmaskedPosition >= p) { | |
1052 | shiftR(p, getMaskLength(), c); | |
1053 | //shift the lvp if needed | |
1054 | var lvp = getActiveMaskSet()["lastValidPosition"], nlvp = seekNext(lvp); | |
1055 | if (nlvp != getMaskLength() && lvp >= p && (getBufferElement(getActiveBuffer(), nlvp, true) != getPlaceHolder(nlvp))) { | |
1056 | getActiveMaskSet()["lastValidPosition"] = nlvp; | |
1057 | } | |
1058 | } else getActiveMaskSet()["writeOutBuffer"] = false; | |
1059 | } else setBufferElement(buffer, p, c, true); | |
1060 | if (minimalForwardPosition == -1 || minimalForwardPosition > seekNext(p)) { | |
1061 | minimalForwardPosition = seekNext(p); | |
1062 | } | |
1063 | } else if (!strict) { | |
1064 | var nextPos = p < getMaskLength() ? p + 1 : p; | |
1065 | if (minimalForwardPosition == -1 || minimalForwardPosition > nextPos) { | |
1066 | minimalForwardPosition = nextPos; | |
1067 | } | |
1068 | } | |
1069 | if (minimalForwardPosition > getActiveMaskSet()["p"]) | |
1070 | getActiveMaskSet()["p"] = minimalForwardPosition; //needed for checkval strict | |
1071 | } | |
1072 | }); | |
1073 | ||
1074 | if (strict !== true) { | |
1075 | activeMasksetIndex = initialIndex; | |
1076 | determineActiveMasksetIndex(); | |
1077 | } | |
1078 | if (writeOut !== false) { | |
1079 | $.each(results, function (ndx, rslt) { | |
1080 | if (rslt["activeMasksetIndex"] == activeMasksetIndex) { | |
1081 | result = rslt; | |
1082 | return false; | |
1083 | } | |
1084 | }); | |
1085 | if (result != undefined) { | |
1086 | var self = this; | |
1087 | setTimeout(function () { opts.onKeyValidation.call(self, result["result"], opts); }, 0); | |
1088 | if (getActiveMaskSet()["writeOutBuffer"] && result["result"] !== false) { | |
1089 | var buffer = getActiveBuffer(); | |
1090 | ||
1091 | var newCaretPosition; | |
1092 | if (checkval) { | |
1093 | newCaretPosition = undefined; | |
1094 | } else if (opts.numericInput) { | |
1095 | if (p > radixPosition) { | |
1096 | newCaretPosition = seekPrevious(minimalForwardPosition); | |
1097 | } else if (c == opts.radixPoint) { | |
1098 | newCaretPosition = minimalForwardPosition - 1; | |
1099 | } else newCaretPosition = seekPrevious(minimalForwardPosition - 1); | |
1100 | } else { | |
1101 | newCaretPosition = minimalForwardPosition; | |
1102 | } | |
1103 | ||
1104 | writeBuffer(input, buffer, newCaretPosition); | |
1105 | if (checkval !== true) { | |
1106 | setTimeout(function () { //timeout needed for IE | |
1107 | if (isComplete(buffer) === true) | |
1108 | $input.trigger("complete"); | |
1109 | skipInputEvent = true; | |
1110 | $input.trigger("input"); | |
1111 | }, 0); | |
1112 | } | |
1113 | } else if (isSlctn) { | |
1114 | getActiveMaskSet()["buffer"] = getActiveMaskSet()["undoBuffer"].split(''); | |
1115 | } | |
1116 | } | |
1117 | } | |
1118 | ||
1119 | if (opts.showTooltip) { //update tooltip | |
1120 | $input.prop("title", getActiveMaskSet()["mask"]); | |
1121 | } | |
1122 | ||
1123 | //needed for IE8 and below | |
1124 | if (e) e.preventDefault ? e.preventDefault() : e.returnValue = false; | |
1125 | } | |
1126 | } | |
1127 | } | |
1128 | ||
1129 | function keyupEvent(e) { | |
1130 | var $input = $(this), input = this, k = e.keyCode, buffer = getActiveBuffer(); | |
1131 | ||
1132 | if (androidchrome && k == opts.keyCode.BACKSPACE) { | |
1133 | if (chromeValueOnInput == input._valueGet()) | |
1134 | keydownEvent.call(this, e); | |
1135 | } | |
1136 | ||
1137 | opts.onKeyUp.call(this, e, buffer, opts); //extra stuff to execute on keyup | |
1138 | if (k == opts.keyCode.TAB && opts.showMaskOnFocus) { | |
1139 | if ($input.hasClass('focus.inputmask') && input._valueGet().length == 0) { | |
1140 | buffer = getActiveBufferTemplate().slice(); | |
1141 | writeBuffer(input, buffer); | |
1142 | caret(input, 0); | |
1143 | valueOnFocus = getActiveBuffer().join(''); | |
1144 | } else { | |
1145 | writeBuffer(input, buffer); | |
1146 | if (buffer.join('') == getActiveBufferTemplate().join('') && $.inArray(opts.radixPoint, buffer) != -1) { | |
1147 | caret(input, TranslatePosition(0)); | |
1148 | $input.click(); | |
1149 | } else | |
1150 | caret(input, TranslatePosition(0), TranslatePosition(getMaskLength())); | |
1151 | } | |
1152 | } | |
1153 | } | |
1154 | ||
1155 | function inputEvent(e) { | |
1156 | if (skipInputEvent === true) { | |
1157 | skipInputEvent = false; | |
1158 | return true; | |
1159 | } | |
1160 | var input = this, $input = $(input); | |
1161 | ||
1162 | chromeValueOnInput = getActiveBuffer().join(''); | |
1163 | checkVal(input, false, false); | |
1164 | writeBuffer(input, getActiveBuffer()); | |
1165 | if (isComplete(getActiveBuffer()) === true) | |
1166 | $input.trigger("complete"); | |
1167 | $input.click(); | |
1168 | } | |
1169 | ||
1170 | function mask(el) { | |
1171 | $el = $(el); | |
1172 | if ($el.is(":input")) { | |
1173 | //store tests & original buffer in the input element - used to get the unmasked value | |
1174 | $el.data('_inputmask', { | |
1175 | 'masksets': masksets, | |
1176 | 'activeMasksetIndex': activeMasksetIndex, | |
1177 | 'opts': opts, | |
1178 | 'isRTL': false | |
1179 | }); | |
1180 | ||
1181 | //show tooltip | |
1182 | if (opts.showTooltip) { | |
1183 | $el.prop("title", getActiveMaskSet()["mask"]); | |
1184 | } | |
1185 | ||
1186 | //correct greedy setting if needed | |
1187 | getActiveMaskSet()['greedy'] = getActiveMaskSet()['greedy'] ? getActiveMaskSet()['greedy'] : getActiveMaskSet()['repeat'] == 0; | |
1188 | ||
1189 | //handle maxlength attribute | |
1190 | if ($el.attr("maxLength") != null) //only when the attribute is set | |
1191 | { | |
1192 | var maxLength = $el.prop('maxLength'); | |
1193 | if (maxLength > -1) { //handle *-repeat | |
1194 | $.each(masksets, function (ndx, ms) { | |
1195 | if (typeof (ms) == "object") { | |
1196 | if (ms["repeat"] == "*") { | |
1197 | ms["repeat"] = maxLength; | |
1198 | } | |
1199 | } | |
1200 | }); | |
1201 | } | |
1202 | if (getMaskLength() >= maxLength && maxLength > -1) { //FF sets no defined max length to -1 | |
1203 | if (maxLength < getActiveBufferTemplate().length) getActiveBufferTemplate().length = maxLength; | |
1204 | if (getActiveMaskSet()['greedy'] == false) { | |
1205 | getActiveMaskSet()['repeat'] = Math.round(maxLength / getActiveBufferTemplate().length); | |
1206 | } | |
1207 | $el.prop('maxLength', getMaskLength() * 2); | |
1208 | } | |
1209 | } | |
1210 | ||
1211 | patchValueProperty(el); | |
1212 | ||
1213 | if (opts.numericInput) opts.isNumeric = opts.numericInput; | |
1214 | if (el.dir == "rtl" || (opts.numericInput && opts.rightAlignNumerics) || (opts.isNumeric && opts.rightAlignNumerics)) | |
1215 | $el.css("text-align", "right"); | |
1216 | ||
1217 | if (el.dir == "rtl" || opts.numericInput) { | |
1218 | el.dir = "ltr"; | |
1219 | $el.removeAttr("dir"); | |
1220 | var inputData = $el.data('_inputmask'); | |
1221 | inputData['isRTL'] = true; | |
1222 | $el.data('_inputmask', inputData); | |
1223 | isRTL = true; | |
1224 | } | |
1225 | ||
1226 | //unbind all events - to make sure that no other mask will interfere when re-masking | |
1227 | $el.unbind(".inputmask"); | |
1228 | $el.removeClass('focus.inputmask'); | |
1229 | //bind events | |
1230 | $el.closest('form').bind("submit", function () { //trigger change on submit if any | |
1231 | if (valueOnFocus != getActiveBuffer().join('')) { | |
1232 | $el.change(); | |
1233 | } | |
1234 | }).bind('reset', function () { | |
1235 | setTimeout(function () { | |
1236 | $el.trigger("setvalue"); | |
1237 | }, 0); | |
1238 | }); | |
1239 | $el.bind("mouseenter.inputmask", function () { | |
1240 | var $input = $(this), input = this; | |
1241 | if (!$input.hasClass('focus.inputmask') && opts.showMaskOnHover) { | |
1242 | if (input._valueGet() != getActiveBuffer().join('')) { | |
1243 | writeBuffer(input, getActiveBuffer()); | |
1244 | } | |
1245 | } | |
1246 | }).bind("blur.inputmask", function () { | |
1247 | var $input = $(this), input = this, nptValue = input._valueGet(), buffer = getActiveBuffer(); | |
1248 | $input.removeClass('focus.inputmask'); | |
1249 | if (valueOnFocus != getActiveBuffer().join('')) { | |
1250 | $input.change(); | |
1251 | } | |
1252 | if (opts.clearMaskOnLostFocus && nptValue != '') { | |
1253 | if (nptValue == getActiveBufferTemplate().join('')) | |
1254 | input._valueSet(''); | |
1255 | else { //clearout optional tail of the mask | |
1256 | clearOptionalTail(input); | |
1257 | } | |
1258 | } | |
1259 | if (isComplete(buffer) === false) { | |
1260 | $input.trigger("incomplete"); | |
1261 | if (opts.clearIncomplete) { | |
1262 | $.each(masksets, function (ndx, ms) { | |
1263 | if (typeof (ms) == "object") { | |
1264 | ms["buffer"] = ms["_buffer"].slice(); | |
1265 | ms["lastValidPosition"] = -1; | |
1266 | } | |
1267 | }); | |
1268 | activeMasksetIndex = 0; | |
1269 | if (opts.clearMaskOnLostFocus) | |
1270 | input._valueSet(''); | |
1271 | else { | |
1272 | buffer = getActiveBufferTemplate().slice(); | |
1273 | writeBuffer(input, buffer); | |
1274 | } | |
1275 | } | |
1276 | } | |
1277 | }).bind("focus.inputmask", function () { | |
1278 | var $input = $(this), input = this, nptValue = input._valueGet(); | |
1279 | if (opts.showMaskOnFocus && !$input.hasClass('focus.inputmask') && (!opts.showMaskOnHover || (opts.showMaskOnHover && nptValue == ''))) { | |
1280 | if (input._valueGet() != getActiveBuffer().join('')) { | |
1281 | writeBuffer(input, getActiveBuffer(), seekNext(getActiveMaskSet()["lastValidPosition"])); | |
1282 | } | |
1283 | } | |
1284 | $input.addClass('focus.inputmask'); | |
1285 | valueOnFocus = getActiveBuffer().join(''); | |
1286 | }).bind("mouseleave.inputmask", function () { | |
1287 | var $input = $(this), input = this; | |
1288 | if (opts.clearMaskOnLostFocus) { | |
1289 | if (!$input.hasClass('focus.inputmask') && input._valueGet() != $input.attr("placeholder")) { | |
1290 | if (input._valueGet() == getActiveBufferTemplate().join('') || input._valueGet() == '') | |
1291 | input._valueSet(''); | |
1292 | else { //clearout optional tail of the mask | |
1293 | clearOptionalTail(input); | |
1294 | } | |
1295 | } | |
1296 | } | |
1297 | }).bind("click.inputmask", function () { | |
1298 | var input = this; | |
1299 | setTimeout(function () { | |
1300 | var selectedCaret = caret(input), buffer = getActiveBuffer(); | |
1301 | if (selectedCaret.begin == selectedCaret.end) { | |
1302 | var clickPosition = isRTL ? TranslatePosition(selectedCaret.begin) : selectedCaret.begin, | |
1303 | lvp = getActiveMaskSet()["lastValidPosition"], | |
1304 | lastPosition; | |
1305 | if (opts.isNumeric) { | |
1306 | lastPosition = opts.skipRadixDance === false && opts.radixPoint != "" && $.inArray(opts.radixPoint, buffer) != -1 ? | |
1307 | (opts.numericInput ? seekNext($.inArray(opts.radixPoint, buffer)) : $.inArray(opts.radixPoint, buffer)) : | |
1308 | seekNext(lvp); | |
1309 | } else { | |
1310 | lastPosition = seekNext(lvp); | |
1311 | } | |
1312 | if (clickPosition < lastPosition) { | |
1313 | if (isMask(clickPosition)) | |
1314 | caret(input, clickPosition); | |
1315 | else caret(input, seekNext(clickPosition)); | |
1316 | } else | |
1317 | caret(input, lastPosition); | |
1318 | } | |
1319 | }, 0); | |
1320 | }).bind('dblclick.inputmask', function () { | |
1321 | var input = this; | |
1322 | setTimeout(function () { | |
1323 | caret(input, 0, seekNext(getActiveMaskSet()["lastValidPosition"])); | |
1324 | }, 0); | |
1325 | }).bind(pasteEvent + ".inputmask dragdrop.inputmask drop.inputmask", function (e) { | |
1326 | if (skipInputEvent === true) { | |
1327 | skipInputEvent = false; | |
1328 | return true; | |
1329 | } | |
1330 | var input = this, $input = $(input); | |
1331 | ||
1332 | //paste event for IE8 and lower I guess ;-) | |
1333 | if (e.type == "propertychange" && input._valueGet().length <= getMaskLength()) { | |
1334 | return true; | |
1335 | } | |
1336 | setTimeout(function () { | |
1337 | var pasteValue = opts.onBeforePaste != undefined ? opts.onBeforePaste.call(this, input._valueGet()) : input._valueGet(); | |
1338 | checkVal(input, true, false, pasteValue.split(''), true); | |
1339 | if (isComplete(getActiveBuffer()) === true) | |
1340 | $input.trigger("complete"); | |
1341 | $input.click(); | |
1342 | }, 0); | |
1343 | }).bind('setvalue.inputmask', function () { | |
1344 | var input = this; | |
1345 | checkVal(input, true); | |
1346 | valueOnFocus = getActiveBuffer().join(''); | |
1347 | if (input._valueGet() == getActiveBufferTemplate().join('')) | |
1348 | input._valueSet(''); | |
1349 | }).bind('complete.inputmask', opts.oncomplete | |
1350 | ).bind('incomplete.inputmask', opts.onincomplete | |
1351 | ).bind('cleared.inputmask', opts.oncleared | |
1352 | ).bind("keyup.inputmask", keyupEvent); | |
1353 | ||
1354 | if (androidchrome) { | |
1355 | $el.bind("input.inputmask", inputEvent); | |
1356 | } else { | |
1357 | $el.bind("keydown.inputmask", keydownEvent | |
1358 | ).bind("keypress.inputmask", keypressEvent); | |
1359 | } | |
1360 | ||
1361 | if (msie10) | |
1362 | $el.bind("input.inputmask", inputEvent); | |
1363 | ||
1364 | //apply mask | |
1365 | checkVal(el, true, false); | |
1366 | valueOnFocus = getActiveBuffer().join(''); | |
1367 | // Wrap document.activeElement in a try/catch block since IE9 throw "Unspecified error" if document.activeElement is undefined when we are in an IFrame. | |
1368 | var activeElement; | |
1369 | try { | |
1370 | activeElement = document.activeElement; | |
1371 | } catch (e) { | |
1372 | } | |
1373 | if (activeElement === el) { //position the caret when in focus | |
1374 | $el.addClass('focus.inputmask'); | |
1375 | caret(el, seekNext(getActiveMaskSet()["lastValidPosition"])); | |
1376 | } else if (opts.clearMaskOnLostFocus) { | |
1377 | if (getActiveBuffer().join('') == getActiveBufferTemplate().join('')) { | |
1378 | el._valueSet(''); | |
1379 | } else { | |
1380 | clearOptionalTail(el); | |
1381 | } | |
1382 | } else { | |
1383 | writeBuffer(el, getActiveBuffer()); | |
1384 | } | |
1385 | ||
1386 | installEventRuler(el); | |
1387 | } | |
1388 | } | |
1389 | ||
1390 | //action object | |
1391 | if (actionObj != undefined) { | |
1392 | switch (actionObj["action"]) { | |
1393 | case "isComplete": | |
1394 | return isComplete(actionObj["buffer"]); | |
1395 | case "unmaskedvalue": | |
1396 | isRTL = actionObj["$input"].data('_inputmask')['isRTL']; | |
1397 | return unmaskedvalue(actionObj["$input"], actionObj["skipDatepickerCheck"]); | |
1398 | case "mask": | |
1399 | mask(actionObj["el"]); | |
1400 | break; | |
1401 | case "format": | |
1402 | $el = $({}); | |
1403 | $el.data('_inputmask', { | |
1404 | 'masksets': masksets, | |
1405 | 'activeMasksetIndex': activeMasksetIndex, | |
1406 | 'opts': opts, | |
1407 | 'isRTL': opts.numericInput | |
1408 | }); | |
1409 | if (opts.numericInput) { | |
1410 | opts.isNumeric = opts.numericInput; | |
1411 | isRTL = true; | |
1412 | } | |
1413 | ||
1414 | checkVal($el, false, false, actionObj["value"].split(''), true); | |
1415 | return getActiveBuffer().join(''); | |
1416 | } | |
1417 | } | |
1418 | } | |
1419 | $.inputmask = { | |
1420 | //options default | |
1421 | defaults: { | |
1422 | placeholder: "_", | |
1423 | optionalmarker: { start: "[", end: "]" }, | |
1424 | quantifiermarker: { start: "{", end: "}" }, | |
1425 | groupmarker: { start: "(", end: ")" }, | |
1426 | escapeChar: "\\", | |
1427 | mask: null, | |
1428 | oncomplete: $.noop, //executes when the mask is complete | |
1429 | onincomplete: $.noop, //executes when the mask is incomplete and focus is lost | |
1430 | oncleared: $.noop, //executes when the mask is cleared | |
1431 | repeat: 0, //repetitions of the mask: * ~ forever, otherwise specify an integer | |
1432 | greedy: true, //true: allocated buffer for the mask and repetitions - false: allocate only if needed | |
1433 | autoUnmask: false, //automatically unmask when retrieving the value with $.fn.val or value if the browser supports __lookupGetter__ or getOwnPropertyDescriptor | |
1434 | clearMaskOnLostFocus: true, | |
1435 | insertMode: true, //insert the input or overwrite the input | |
1436 | clearIncomplete: false, //clear the incomplete input on blur | |
1437 | aliases: {}, //aliases definitions => see jquery.inputmask.extensions.js | |
1438 | onKeyUp: $.noop, //override to implement autocomplete on certain keys for example | |
1439 | onKeyDown: $.noop, //override to implement autocomplete on certain keys for example | |
1440 | onBeforePaste: undefined, //executes before masking the pasted value to allow preprocessing of the pasted value. args => pastedValue => return processedValue | |
1441 | onUnMask: undefined, //executes after unmasking to allow postprocessing of the unmaskedvalue. args => maskedValue, unmaskedValue | |
1442 | showMaskOnFocus: true, //show the mask-placeholder when the input has focus | |
1443 | showMaskOnHover: true, //show the mask-placeholder when hovering the empty input | |
1444 | onKeyValidation: $.noop, //executes on every key-press with the result of isValid. Params: result, opts | |
1445 | skipOptionalPartCharacter: " ", //a character which can be used to skip an optional part of a mask | |
1446 | showTooltip: false, //show the activemask as tooltip | |
1447 | numericInput: false, //numericInput input direction style (input shifts to the left while holding the caret position) | |
1448 | //numeric basic properties | |
1449 | isNumeric: false, //enable numeric features | |
1450 | radixPoint: "", //".", // | "," | |
1451 | skipRadixDance: false, //disable radixpoint caret positioning | |
1452 | rightAlignNumerics: true, //align numerics to the right | |
1453 | //numeric basic properties | |
1454 | definitions: { | |
1455 | '9': { | |
1456 | validator: "[0-9]", | |
1457 | cardinality: 1 | |
1458 | }, | |
1459 | 'a': { | |
1460 | validator: "[A-Za-z\u0410-\u044F\u0401\u0451]", | |
1461 | cardinality: 1 | |
1462 | }, | |
1463 | '*': { | |
1464 | validator: "[A-Za-z\u0410-\u044F\u0401\u04510-9]", | |
1465 | cardinality: 1 | |
1466 | } | |
1467 | }, | |
1468 | keyCode: { | |
1469 | 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, | |
1470 | 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 | |
1471 | }, | |
1472 | //specify keycodes which should not be considered in the keypress event, otherwise the preventDefault will stop their default behavior especially in FF | |
1473 | ignorables: [8, 9, 13, 19, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 46, 93, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123], | |
1474 | getMaskLength: function (buffer, greedy, repeat, currentBuffer, opts) { | |
1475 | var calculatedLength = buffer.length; | |
1476 | if (!greedy) { | |
1477 | if (repeat == "*") { | |
1478 | calculatedLength = currentBuffer.length + 1; | |
1479 | } else if (repeat > 1) { | |
1480 | calculatedLength += (buffer.length * (repeat - 1)); | |
1481 | } | |
1482 | } | |
1483 | return calculatedLength; | |
1484 | } | |
1485 | }, | |
1486 | escapeRegex: function (str) { | |
1487 | var specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\']; | |
1488 | return str.replace(new RegExp('(\\' + specials.join('|\\') + ')', 'gim'), '\\$1'); | |
1489 | }, | |
1490 | format: function (value, options) { | |
1491 | var opts = $.extend(true, {}, $.inputmask.defaults, options); | |
1492 | resolveAlias(opts.alias, options, opts); | |
1493 | return maskScope(generateMaskSets(opts), 0, opts, { "action": "format", "value": value }); | |
1494 | } | |
1495 | }; | |
1496 | ||
1497 | $.fn.inputmask = function (fn, options) { | |
1498 | var opts = $.extend(true, {}, $.inputmask.defaults, options), | |
1499 | masksets, | |
1500 | activeMasksetIndex = 0; | |
1501 | ||
1502 | if (typeof fn === "string") { | |
1503 | switch (fn) { | |
1504 | case "mask": | |
1505 | //resolve possible aliases given by options | |
1506 | resolveAlias(opts.alias, options, opts); | |
1507 | masksets = generateMaskSets(opts); | |
1508 | if (masksets.length == 0) { return this; } | |
1509 | ||
1510 | return this.each(function () { | |
1511 | maskScope($.extend(true, {}, masksets), 0, opts, { "action": "mask", "el": this }); | |
1512 | }); | |
1513 | case "unmaskedvalue": | |
1514 | var $input = $(this), input = this; | |
1515 | if ($input.data('_inputmask')) { | |
1516 | masksets = $input.data('_inputmask')['masksets']; | |
1517 | activeMasksetIndex = $input.data('_inputmask')['activeMasksetIndex']; | |
1518 | opts = $input.data('_inputmask')['opts']; | |
1519 | return maskScope(masksets, activeMasksetIndex, opts, { "action": "unmaskedvalue", "$input": $input }); | |
1520 | } else return $input.val(); | |
1521 | case "remove": | |
1522 | return this.each(function () { | |
1523 | var $input = $(this), input = this; | |
1524 | if ($input.data('_inputmask')) { | |
1525 | masksets = $input.data('_inputmask')['masksets']; | |
1526 | activeMasksetIndex = $input.data('_inputmask')['activeMasksetIndex']; | |
1527 | opts = $input.data('_inputmask')['opts']; | |
1528 | //writeout the unmaskedvalue | |
1529 | input._valueSet(maskScope(masksets, activeMasksetIndex, opts, { "action": "unmaskedvalue", "$input": $input, "skipDatepickerCheck": true })); | |
1530 | //clear data | |
1531 | $input.removeData('_inputmask'); | |
1532 | //unbind all events | |
1533 | $input.unbind(".inputmask"); | |
1534 | $input.removeClass('focus.inputmask'); | |
1535 | //restore the value property | |
1536 | var valueProperty; | |
1537 | if (Object.getOwnPropertyDescriptor) | |
1538 | valueProperty = Object.getOwnPropertyDescriptor(input, "value"); | |
1539 | if (valueProperty && valueProperty.get) { | |
1540 | if (input._valueGet) { | |
1541 | Object.defineProperty(input, "value", { | |
1542 | get: input._valueGet, | |
1543 | set: input._valueSet | |
1544 | }); | |
1545 | } | |
1546 | } else if (document.__lookupGetter__ && input.__lookupGetter__("value")) { | |
1547 | if (input._valueGet) { | |
1548 | input.__defineGetter__("value", input._valueGet); | |
1549 | input.__defineSetter__("value", input._valueSet); | |
1550 | } | |
1551 | } | |
1552 | try { //try catch needed for IE7 as it does not supports deleting fns | |
1553 | delete input._valueGet; | |
1554 | delete input._valueSet; | |
1555 | } catch (e) { | |
1556 | input._valueGet = undefined; | |
1557 | input._valueSet = undefined; | |
1558 | ||
1559 | } | |
1560 | } | |
1561 | }); | |
1562 | break; | |
1563 | case "getemptymask": //return the default (empty) mask value, usefull for setting the default value in validation | |
1564 | if (this.data('_inputmask')) { | |
1565 | masksets = this.data('_inputmask')['masksets']; | |
1566 | activeMasksetIndex = this.data('_inputmask')['activeMasksetIndex']; | |
1567 | return masksets[activeMasksetIndex]['_buffer'].join(''); | |
1568 | } | |
1569 | else return ""; | |
1570 | case "hasMaskedValue": //check wheter the returned value is masked or not; currently only works reliable when using jquery.val fn to retrieve the value | |
1571 | return this.data('_inputmask') ? !this.data('_inputmask')['opts'].autoUnmask : false; | |
1572 | case "isComplete": | |
1573 | masksets = this.data('_inputmask')['masksets']; | |
1574 | activeMasksetIndex = this.data('_inputmask')['activeMasksetIndex']; | |
1575 | opts = this.data('_inputmask')['opts']; | |
1576 | return maskScope(masksets, activeMasksetIndex, opts, { "action": "isComplete", "buffer": this[0]._valueGet().split('') }); | |
1577 | case "getmetadata": //return mask metadata if exists | |
1578 | if (this.data('_inputmask')) { | |
1579 | masksets = this.data('_inputmask')['masksets']; | |
1580 | activeMasksetIndex = this.data('_inputmask')['activeMasksetIndex']; | |
1581 | return masksets[activeMasksetIndex]['metadata']; | |
1582 | } | |
1583 | else return undefined; | |
1584 | default: | |
1585 | //check if the fn is an alias | |
1586 | if (!resolveAlias(fn, options, opts)) { | |
1587 | //maybe fn is a mask so we try | |
1588 | //set mask | |
1589 | opts.mask = fn; | |
1590 | } | |
1591 | masksets = generateMaskSets(opts); | |
1592 | if (masksets.length == 0) { return this; } | |
1593 | return this.each(function () { | |
1594 | maskScope($.extend(true, {}, masksets), activeMasksetIndex, opts, { "action": "mask", "el": this }); | |
1595 | }); | |
1596 | ||
1597 | break; | |
1598 | } | |
1599 | } else if (typeof fn == "object") { | |
1600 | opts = $.extend(true, {}, $.inputmask.defaults, fn); | |
1601 | ||
1602 | resolveAlias(opts.alias, fn, opts); //resolve aliases | |
1603 | masksets = generateMaskSets(opts); | |
1604 | if (masksets.length == 0) { return this; } | |
1605 | return this.each(function () { | |
1606 | maskScope($.extend(true, {}, masksets), activeMasksetIndex, opts, { "action": "mask", "el": this }); | |
1607 | }); | |
1608 | } else if (fn == undefined) { | |
1609 | //look for data-inputmask atribute - the attribute should only contain optipns | |
1610 | return this.each(function () { | |
1611 | var attrOptions = $(this).attr("data-inputmask"); | |
1612 | if (attrOptions && attrOptions != "") { | |
1613 | try { | |
1614 | attrOptions = attrOptions.replace(new RegExp("'", "g"), '"'); | |
1615 | var dataoptions = $.parseJSON("{" + attrOptions + "}"); | |
1616 | $.extend(true, dataoptions, options); | |
1617 | opts = $.extend(true, {}, $.inputmask.defaults, dataoptions); | |
1618 | resolveAlias(opts.alias, dataoptions, opts); | |
1619 | opts.alias = undefined; | |
1620 | $(this).inputmask(opts); | |
1621 | } catch (ex) { } //need a more relax parseJSON | |
1622 | } | |
1623 | }); | |
1624 | } | |
1625 | }; | |
1626 | } | |
1627 | })(jQuery); |