Merge lp:~aristobulo/web-addons/web_fields_masks into lp:~webaddons-core-editors/web-addons/7.0
- web_fields_masks
- Merge into 7.0
Status: | Needs review |
---|---|
Proposed branch: | lp:~aristobulo/web-addons/web_fields_masks |
Merge into: | lp:~webaddons-core-editors/web-addons/7.0 |
Diff against target: |
2513 lines (+2476/-0) 6 files modified
web_fields_masks/__openerp__.py (+55/-0) web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.extensions.js (+110/-0) web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.js (+1834/-0) web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.numeric.extensions.js (+263/-0) web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.regex.extensions.js (+187/-0) web_fields_masks/static/src/js/main.js (+27/-0) |
To merge this branch: | bzr merge lp:~aristobulo/web-addons/web_fields_masks |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Holger Brunn (Therp) | Needs Resubmitting | ||
Mario Arias (community) | test | Needs Fixing | |
Review via email: mp+219084@code.launchpad.net |
Commit message
Description of the change
web_fields_masks: This module allows to use inputmasks. An inputmask helps the user with the input by ensuring a predefined format, like phone number, emails, ip addresses, etc.
- 36. By Aristóbulo Meneses
-
Moved external js libraries to static/lib/ folder.
Added visual style for input validation.
Using data-inputmask attribute for mask declaration.
Mario Arias (the-clone-master) wrote : | # |
We have been testing it and is working flawlessly...
Mario Arias (the-clone-master) wrote : | # |
Hi, what is still pending for this MP?
I'd be glad to keep track of one less branch...
Regards,
-Mario
Mario Arias (the-clone-master) wrote : | # |
Don't know what happened, but now it is not triggering the mask check.
I had to re-create my test environments and when reinstalled it didn't work anymore...
Holger Brunn (Therp) (hbrunn) wrote : | # |
This project is now hosted on https:/
Unmerged revisions
- 36. By Aristóbulo Meneses
-
Moved external js libraries to static/lib/ folder.
Added visual style for input validation.
Using data-inputmask attribute for mask declaration. - 35. By Aristóbulo Meneses
-
[add] Field masks support based on jquery.inputmask
Preview Diff
1 | === added directory 'web_fields_masks' |
2 | === added file 'web_fields_masks/__init__.py' |
3 | === added file 'web_fields_masks/__openerp__.py' |
4 | --- web_fields_masks/__openerp__.py 1970-01-01 00:00:00 +0000 |
5 | +++ web_fields_masks/__openerp__.py 2014-05-20 21:16:10 +0000 |
6 | @@ -0,0 +1,55 @@ |
7 | +{ |
8 | + 'name': 'Fields masks', |
9 | + 'version': '0.2', |
10 | + 'description': """ |
11 | +Fields masks |
12 | +================================================================================ |
13 | + |
14 | +Based on jquery.inputmask 3.x (https://github.com/RobinHerbots/jquery.inputmask) |
15 | + |
16 | +An inputmask helps the user with the input by ensuring a predefined format. |
17 | +This can be useful for dates, numerics, phone numbers, ... |
18 | + |
19 | + |
20 | + |
21 | +Instructions: |
22 | +------------- |
23 | + |
24 | +- Just add data-inputmask="mask" to <field /> |
25 | + |
26 | + Some examples: |
27 | + |
28 | + <field name="email" data-inputmask="'alias': 'email'" /> |
29 | + <field name="ip_address" data-inputmask="'alias': 'ip'" /> |
30 | + <field name="masked_field" data-inputmask="'mask': '99-9999999'" /> |
31 | + |
32 | + |
33 | +Masking definition: |
34 | +------------------- |
35 | + |
36 | + - 9: numeric value |
37 | + - a: alphabetical value |
38 | + - *: alphanumeric value |
39 | + |
40 | +Aliases available: |
41 | +------------------ |
42 | + |
43 | |
44 | + - ip: IPv4 addresses |
45 | + - url |
46 | + |
47 | + """, |
48 | + 'author': 'Aristobulo Meneses', |
49 | + 'website': 'https://menecio.github.io', |
50 | + 'category': 'web', |
51 | + 'depends': ['web'], |
52 | + 'js': [ |
53 | + 'static/lib/jquery.inputmask/jquery.inputmask.js', |
54 | + 'static/lib/jquery.inputmask/jquery.inputmask.extensions.js', |
55 | + 'static/lib/jquery.inputmask/jquery.inputmask.numeric.extensions.js', |
56 | + 'static/lib/jquery.inputmask/jquery.inputmask.regex.extensions.js', |
57 | + 'static/src/js/main.js', |
58 | + ], |
59 | + 'css': [ |
60 | + ], |
61 | +} |
62 | |
63 | === added directory 'web_fields_masks/static' |
64 | === added directory 'web_fields_masks/static/lib' |
65 | === added directory 'web_fields_masks/static/lib/jquery.inputmask' |
66 | === added file 'web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.extensions.js' |
67 | --- web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.extensions.js 1970-01-01 00:00:00 +0000 |
68 | +++ web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.extensions.js 2014-05-20 21:16:10 +0000 |
69 | @@ -0,0 +1,110 @@ |
70 | +/* |
71 | +Input Mask plugin extensions |
72 | +http://github.com/RobinHerbots/jquery.inputmask |
73 | +Copyright (c) 2010 - 2014 Robin Herbots |
74 | +Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php) |
75 | +Version: 0.0.0 |
76 | + |
77 | +Optional extensions on the jquery.inputmask base |
78 | +*/ |
79 | +(function ($) { |
80 | + //extra definitions |
81 | + $.extend($.inputmask.defaults.definitions, { |
82 | + 'A': { |
83 | + validator: "[A-Za-z]", |
84 | + cardinality: 1, |
85 | + casing: "upper" //auto uppercasing |
86 | + }, |
87 | + '#': { |
88 | + validator: "[A-Za-z\u0410-\u044F\u0401\u04510-9]", |
89 | + cardinality: 1, |
90 | + casing: "upper" |
91 | + } |
92 | + }); |
93 | + $.extend($.inputmask.defaults.aliases, { |
94 | + 'url': { |
95 | + mask: "ir", |
96 | + placeholder: "", |
97 | + separator: "", |
98 | + defaultPrefix: "http://", |
99 | + regex: { |
100 | + urlpre1: new RegExp("[fh]"), |
101 | + urlpre2: new RegExp("(ft|ht)"), |
102 | + urlpre3: new RegExp("(ftp|htt)"), |
103 | + urlpre4: new RegExp("(ftp:|http|ftps)"), |
104 | + urlpre5: new RegExp("(ftp:/|ftps:|http:|https)"), |
105 | + urlpre6: new RegExp("(ftp://|ftps:/|http:/|https:)"), |
106 | + urlpre7: new RegExp("(ftp://|ftps://|http://|https:/)"), |
107 | + urlpre8: new RegExp("(ftp://|ftps://|http://|https://)") |
108 | + }, |
109 | + definitions: { |
110 | + 'i': { |
111 | + validator: function (chrs, buffer, pos, strict, opts) { |
112 | + return true; |
113 | + }, |
114 | + cardinality: 8, |
115 | + prevalidator: (function () { |
116 | + var result = [], prefixLimit = 8; |
117 | + for (var i = 0; i < prefixLimit; i++) { |
118 | + result[i] = (function () { |
119 | + var j = i; |
120 | + return { |
121 | + validator: function (chrs, buffer, pos, strict, opts) { |
122 | + if (opts.regex["urlpre" + (j + 1)]) { |
123 | + var tmp = chrs, k; |
124 | + if (((j + 1) - chrs.length) > 0) { |
125 | + tmp = buffer.join('').substring(0, ((j + 1) - chrs.length)) + "" + tmp; |
126 | + } |
127 | + var isValid = opts.regex["urlpre" + (j + 1)].test(tmp); |
128 | + if (!strict && !isValid) { |
129 | + pos = pos - j; |
130 | + for (k = 0; k < opts.defaultPrefix.length; k++) { |
131 | + buffer[pos] = opts.defaultPrefix[k]; pos++; |
132 | + } |
133 | + for (k = 0; k < tmp.length - 1; k++) { |
134 | + buffer[pos] = tmp[k]; pos++; |
135 | + } |
136 | + return { "pos": pos }; |
137 | + } |
138 | + return isValid; |
139 | + } else { |
140 | + return false; |
141 | + } |
142 | + }, cardinality: j |
143 | + }; |
144 | + })(); |
145 | + } |
146 | + return result; |
147 | + })() |
148 | + }, |
149 | + "r": { |
150 | + validator: ".", |
151 | + cardinality: 50 |
152 | + } |
153 | + }, |
154 | + insertMode: false, |
155 | + autoUnmask: false |
156 | + }, |
157 | + "ip": { //ip-address mask |
158 | + mask: "i[i[i]].i[i[i]].i[i[i]].i[i[i]]", |
159 | + definitions: { |
160 | + 'i': { |
161 | + validator: function (chrs, buffer, pos, strict, opts) { |
162 | + if (pos - 1 > -1 && buffer[pos - 1] != ".") { |
163 | + chrs = buffer[pos - 1] + chrs; |
164 | + if (pos - 2 > -1 && buffer[pos - 2] != ".") { |
165 | + chrs = buffer[pos - 2] + chrs; |
166 | + } else chrs = "0" + chrs; |
167 | + } else chrs = "00" + chrs; |
168 | + return new RegExp("25[0-5]|2[0-4][0-9]|[01][0-9][0-9]").test(chrs); |
169 | + }, |
170 | + cardinality: 1 |
171 | + } |
172 | + } |
173 | + }, |
174 | + "email": { |
175 | + mask: "*{1,20}[.*{1,20}][.*{1,20}][.*{1,20}]@*{1,20}.*{2,6}[.*{1,2}]", |
176 | + greedy: false |
177 | + } |
178 | + }); |
179 | +})(jQuery); |
180 | |
181 | === added file 'web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.js' |
182 | --- web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.js 1970-01-01 00:00:00 +0000 |
183 | +++ web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.js 2014-05-20 21:16:10 +0000 |
184 | @@ -0,0 +1,1834 @@ |
185 | +/** |
186 | +* @license Input Mask plugin for jquery |
187 | +* http://github.com/RobinHerbots/jquery.inputmask |
188 | +* Copyright (c) 2010 - 2014 Robin Herbots |
189 | +* Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php) |
190 | +* Version: 0.0.0 |
191 | +*/ |
192 | + |
193 | +(function ($) { |
194 | + if ($.fn.inputmask === undefined) { |
195 | + |
196 | + //helper functions |
197 | + function isInputEventSupported(eventName) { |
198 | + var el = document.createElement('input'), |
199 | + eventName = 'on' + eventName, |
200 | + isSupported = (eventName in el); |
201 | + if (!isSupported) { |
202 | + el.setAttribute(eventName, 'return;'); |
203 | + isSupported = typeof el[eventName] == 'function'; |
204 | + } |
205 | + el = null; |
206 | + return isSupported; |
207 | + } |
208 | + |
209 | + function resolveAlias(aliasStr, options, opts) { |
210 | + var aliasDefinition = opts.aliases[aliasStr]; |
211 | + if (aliasDefinition) { |
212 | + if (aliasDefinition.alias) resolveAlias(aliasDefinition.alias, undefined, opts); //alias is another alias |
213 | + $.extend(true, opts, aliasDefinition); //merge alias definition in the options |
214 | + $.extend(true, opts, options); //reapply extra given options |
215 | + return true; |
216 | + } |
217 | + return false; |
218 | + } |
219 | + |
220 | + function generateMaskSet(opts) { |
221 | + var ms = []; |
222 | + |
223 | + function analyseMask(mask) { |
224 | + var tokenizer = /(?:[?*+]|\{[0-9]+(?:,[0-9\+\*]*)?\})\??|[^.?*+^${[]()|\\]+|./g, |
225 | + escaped = false; |
226 | + |
227 | + function maskToken(isGroup, isOptional, isQuantifier, isAlternator) { |
228 | + this.matches = []; |
229 | + this.isGroup = isGroup || false; |
230 | + this.isOptional = isOptional || false; |
231 | + this.isQuantifier = isQuantifier || false; |
232 | + this.isAlternator = isAlternator || false; |
233 | + this.quantifier = { min: 1, max: 1 }; |
234 | + }; |
235 | + |
236 | + //test definition => {fn: RegExp/function, cardinality: int, optionality: bool, newBlockMarker: bool, offset: int, casing: null/upper/lower, def: definitionSymbol} |
237 | + function insertTestDefinition(mtoken, element, position) { |
238 | + var maskdef = opts.definitions[element]; |
239 | + var newBlockMarker = mtoken.matches.length == 0; |
240 | + position = position != undefined ? position : mtoken.matches.length; |
241 | + if (maskdef && !escaped) { |
242 | + var prevalidators = maskdef["prevalidator"], prevalidatorsL = prevalidators ? prevalidators.length : 0; |
243 | + for (var i = 1; i < maskdef.cardinality; i++) { |
244 | + var prevalidator = prevalidatorsL >= i ? prevalidators[i - 1] : [], validator = prevalidator["validator"], cardinality = prevalidator["cardinality"]; |
245 | + mtoken.matches.splice(position++, 0, { fn: validator ? typeof validator == 'string' ? new RegExp(validator) : new function () { this.test = validator; } : new RegExp("."), cardinality: cardinality ? cardinality : 1, optionality: mtoken.isOptional, newBlockMarker: newBlockMarker, casing: maskdef["casing"], def: maskdef["definitionSymbol"] || element }); |
246 | + } |
247 | + mtoken.matches.splice(position++, 0, { fn: maskdef.validator ? typeof maskdef.validator == 'string' ? new RegExp(maskdef.validator) : new function () { this.test = maskdef.validator; } : new RegExp("."), cardinality: maskdef.cardinality, optionality: mtoken.isOptional, newBlockMarker: newBlockMarker, casing: maskdef["casing"], def: maskdef["definitionSymbol"] || element }); |
248 | + } else { |
249 | + mtoken.matches.splice(position++, 0, { fn: null, cardinality: 0, optionality: mtoken.isOptional, newBlockMarker: newBlockMarker, casing: null, def: element }); |
250 | + escaped = false; |
251 | + } |
252 | + } |
253 | + |
254 | + var currentToken = new maskToken(), |
255 | + match, |
256 | + m, |
257 | + openenings = [], |
258 | + maskTokens = []; |
259 | + |
260 | + while (match = tokenizer.exec(mask)) { |
261 | + m = match[0]; |
262 | + switch (m.charAt(0)) { |
263 | + case opts.optionalmarker.end: |
264 | + // optional closing |
265 | + case opts.groupmarker.end: |
266 | + // Group closing |
267 | + var openingToken = openenings.pop(); |
268 | + if (openenings.length > 0) { |
269 | + openenings[openenings.length - 1]["matches"].push(openingToken); |
270 | + } else { |
271 | + currentToken.matches.push(openingToken); |
272 | + } |
273 | + break; |
274 | + case opts.optionalmarker.start: |
275 | + // optional opening |
276 | + openenings.push(new maskToken(false, true)); |
277 | + break; |
278 | + case opts.groupmarker.start: |
279 | + // Group opening |
280 | + openenings.push(new maskToken(true)); |
281 | + break; |
282 | + case opts.quantifiermarker.start: |
283 | + //Quantifier |
284 | + var quantifier = new maskToken(false, false, true); |
285 | + |
286 | + m = m.replace(/[{}]/g, ""); |
287 | + var mq = m.split(","), mq0 = isNaN(mq[0]) ? mq[0] : parseInt(mq[0]), mq1 = mq.length == 1 ? mq0 : (isNaN(mq[1]) ? mq[1] : parseInt(mq[1])); |
288 | + quantifier.quantifier = { min: mq0, max: mq1 }; |
289 | + if (mq1 == "*" || mq1 == "+") opts.greedy = false; |
290 | + if (openenings.length > 0) { |
291 | + var matches = openenings[openenings.length - 1]["matches"]; |
292 | + var match = matches.pop(); |
293 | + if (!match["isGroup"]) { |
294 | + var groupToken = new maskToken(true); |
295 | + groupToken.matches.push(match); |
296 | + match = groupToken; |
297 | + } |
298 | + matches.push(match); |
299 | + matches.push(quantifier); |
300 | + } else { |
301 | + var match = currentToken.matches.pop(); |
302 | + if (!match["isGroup"]) { |
303 | + var groupToken = new maskToken(true); |
304 | + groupToken.matches.push(match); |
305 | + match = groupToken; |
306 | + } |
307 | + currentToken.matches.push(match); |
308 | + currentToken.matches.push(quantifier); |
309 | + } |
310 | + break; |
311 | + case opts.escapeChar: |
312 | + escaped = true; |
313 | + break; |
314 | + case opts.alternatormarker: |
315 | + |
316 | + break; |
317 | + default: |
318 | + if (openenings.length > 0) { |
319 | + insertTestDefinition(openenings[openenings.length - 1], m); |
320 | + } else { |
321 | + if (currentToken.matches.length > 0) { |
322 | + var lastMatch = currentToken.matches[currentToken.matches.length - 1]; |
323 | + if (lastMatch["isGroup"]) { //this is not a group but a normal mask => convert |
324 | + lastMatch.isGroup = false; |
325 | + insertTestDefinition(lastMatch, opts.groupmarker.start, 0); |
326 | + insertTestDefinition(lastMatch, opts.groupmarker.end); |
327 | + } |
328 | + } |
329 | + insertTestDefinition(currentToken, m); |
330 | + } |
331 | + } |
332 | + } |
333 | + |
334 | + if (currentToken.matches.length > 0) |
335 | + maskTokens.push(currentToken); |
336 | + |
337 | + //console.log(JSON.stringify(maskTokens)); |
338 | + return maskTokens; |
339 | + } |
340 | + |
341 | + function generateMask(mask, metadata) { |
342 | + if (opts.numericInput) { //TODO FIXME for dynamic masks |
343 | + mask = mask.split('').reverse().join(''); |
344 | + } |
345 | + if (mask == undefined || mask == "") |
346 | + return undefined; |
347 | + else { |
348 | + if (opts.repeat > 0 || opts.repeat == "*" || opts.repeat == "+") { |
349 | + var repeatStart = opts.repeat == "*" ? 0 : (opts.repeat == "+" ? 1 : opts.repeat); |
350 | + mask = opts.groupmarker.start + mask + opts.groupmarker.end + opts.quantifiermarker.start + repeatStart + "," + opts.repeat + opts.quantifiermarker.end; |
351 | + } |
352 | + if ($.inputmask.masksCache[mask] == undefined) { |
353 | + $.inputmask.masksCache[mask] = { |
354 | + "mask": mask, |
355 | + "maskToken": analyseMask(mask), |
356 | + "validPositions": {}, |
357 | + "_buffer": undefined, |
358 | + "buffer": undefined, |
359 | + "tests": {}, |
360 | + "metadata": metadata |
361 | + }; |
362 | + } |
363 | + return $.extend(true, {}, $.inputmask.masksCache[mask]); |
364 | + } |
365 | + } |
366 | + |
367 | + if ($.isFunction(opts.mask)) { //allow mask to be a preprocessing fn - should return a valid mask |
368 | + opts.mask = opts.mask.call(this, opts); |
369 | + } |
370 | + if ($.isArray(opts.mask)) { |
371 | + $.each(opts.mask, function (ndx, msk) { |
372 | + if (msk["mask"] != undefined) { |
373 | + ms.push(generateMask(msk["mask"].toString(), msk)); |
374 | + } else { |
375 | + ms.push(generateMask(msk.toString())); |
376 | + } |
377 | + }); |
378 | + } else { |
379 | + if (opts.mask.length == 1 && opts.greedy == false && opts.repeat != 0) { |
380 | + opts.placeholder = ""; |
381 | + } //hide placeholder with single non-greedy mask |
382 | + if (opts.mask["mask"] != undefined) { |
383 | + ms = generateMask(opts.mask["mask"].toString(), opts.mask); |
384 | + } else { |
385 | + ms = generateMask(opts.mask.toString()); |
386 | + } |
387 | + } |
388 | + return ms; |
389 | + } |
390 | + |
391 | + var msie1x = typeof ScriptEngineMajorVersion === "function" |
392 | + ? ScriptEngineMajorVersion() //IE11 detection |
393 | + : new Function("/*@cc_on return @_jscript_version; @*/")() >= 10, //conditional compilation from mickeysoft trick |
394 | + ua = navigator.userAgent, |
395 | + iphone = ua.match(new RegExp("iphone", "i")) !== null, |
396 | + android = ua.match(new RegExp("android.*safari.*", "i")) !== null, |
397 | + androidchrome = ua.match(new RegExp("android.*chrome.*", "i")) !== null, |
398 | + androidfirefox = ua.match(new RegExp("android.*firefox.*", "i")) !== null, |
399 | + kindle = /Kindle/i.test(ua) || /Silk/i.test(ua) || /KFTT/i.test(ua) || /KFOT/i.test(ua) || /KFJWA/i.test(ua) || /KFJWI/i.test(ua) || /KFSOWI/i.test(ua) || /KFTHWA/i.test(ua) || /KFTHWI/i.test(ua) || /KFAPWA/i.test(ua) || /KFAPWI/i.test(ua), |
400 | + PasteEventType = isInputEventSupported('paste') ? 'paste' : isInputEventSupported('input') ? 'input' : "propertychange"; |
401 | + |
402 | + //if (androidchrome) { |
403 | + // var browser = navigator.userAgent.match(new RegExp("chrome.*", "i")), |
404 | + // version = parseInt(new RegExp(/[0-9]+/).exec(browser)); |
405 | + // androidchrome32 = (version == 32); |
406 | + //} |
407 | + |
408 | + //masking scope |
409 | + //actionObj definition see below |
410 | + function maskScope(maskset, opts, actionObj) { |
411 | + var isRTL = false, |
412 | + valueOnFocus = getBuffer().join(''), |
413 | + $el, |
414 | + skipKeyPressEvent = false, //Safari 5.1.x - modal dialog fires keypress twice workaround |
415 | + skipInputEvent = false, //skip when triggered from within inputmask |
416 | + ignorable = false, |
417 | + maxLength; |
418 | + |
419 | + //maskset helperfunctions |
420 | + function getMaskTemplate(baseOnInput, minimalPos, includeInput) { |
421 | + minimalPos = minimalPos || 0; |
422 | + var maskTemplate = [], ndxIntlzr, pos = 0, test; |
423 | + do { |
424 | + if (baseOnInput === true && getMaskSet()['validPositions'][pos]) { |
425 | + var validPos = getMaskSet()['validPositions'][pos]; |
426 | + test = validPos["match"]; |
427 | + ndxIntlzr = validPos["locator"].slice(); |
428 | + maskTemplate.push(test["fn"] == null ? test["def"] : (includeInput === true ? validPos["input"] : opts.placeholder.charAt(pos % opts.placeholder.length))); |
429 | + } else { |
430 | + var testPos = getTests(pos, ndxIntlzr, pos - 1), firstMatch = testPos[0]["match"]; |
431 | + testPos = testPos[(minimalPos > pos || (opts.greedy || (firstMatch.optionality === true && firstMatch.newBlockMarker === false && firstMatch.optionalQuantifier !== true))) ? 0 : (testPos.length - 1)]; |
432 | + test = testPos["match"]; |
433 | + ndxIntlzr = testPos["locator"].slice(); |
434 | + maskTemplate.push(test["fn"] == null ? test["def"] : opts.placeholder.charAt(pos % opts.placeholder.length)); |
435 | + } |
436 | + pos++; |
437 | + } while ((maxLength == undefined || pos - 1 < maxLength) && test["fn"] != null || (test["fn"] == null && test["def"] != "") || minimalPos >= pos); |
438 | + maskTemplate.pop(); //drop the last one which is empty |
439 | + return maskTemplate; |
440 | + } |
441 | + |
442 | + function getMaskSet() { |
443 | + return maskset; |
444 | + } |
445 | + |
446 | + function resetMaskSet(soft) { |
447 | + var maskset = getMaskSet(); |
448 | + maskset["buffer"] = undefined; |
449 | + maskset["tests"] = {}; |
450 | + if (soft !== true) { |
451 | + maskset["_buffer"] = undefined; |
452 | + maskset["validPositions"] = {}; |
453 | + maskset["p"] = -1; |
454 | + } |
455 | + } |
456 | + |
457 | + function getLastValidPosition(closestTo) { //TODO implement closest to |
458 | + var maskset = getMaskSet(); |
459 | + var lastValidPosition = -1, valids = maskset["validPositions"]; |
460 | + for (var posNdx in valids) { |
461 | + var psNdx = parseInt(posNdx); |
462 | + if (psNdx > lastValidPosition) lastValidPosition = psNdx; |
463 | + } |
464 | + return lastValidPosition; |
465 | + } |
466 | + |
467 | + function setValidPosition(pos, validTest, strict, fromSetValid) { |
468 | + if (opts.insertMode && getMaskSet()["validPositions"][pos] != undefined && fromSetValid == undefined) { |
469 | + //reposition & revalidate others |
470 | + var positionsClone = $.extend(true, {}, getMaskSet()["validPositions"]), lvp = getLastValidPosition(), i; |
471 | + for (i = pos; i <= lvp; i++) { //clear selection |
472 | + delete getMaskSet()["validPositions"][i]; |
473 | + } |
474 | + getMaskSet()["validPositions"][pos] = validTest; |
475 | + var valid = true; |
476 | + for (i = pos; i <= lvp ;) { |
477 | + var j = seekNext(i); |
478 | + var t = positionsClone[i]; |
479 | + if (t != undefined) { |
480 | + var nextTest = getTest(j); |
481 | + if (nextTest.fn == null && nextTest.def == "") |
482 | + valid = false; |
483 | + else if (t["match"].fn == null || t["match"].def == nextTest.def) { |
484 | + valid = valid && isValid(j, t["input"], strict, true) !== false; |
485 | + } |
486 | + } |
487 | + i = j; |
488 | + } |
489 | + |
490 | + if (!valid) { |
491 | + getMaskSet()["validPositions"] = $.extend(true, {}, positionsClone); |
492 | + return false; |
493 | + } |
494 | + } else |
495 | + getMaskSet()["validPositions"][pos] = validTest; |
496 | + |
497 | + return true; |
498 | + } |
499 | + |
500 | + function stripValidPositions(start, end) { |
501 | + var i, ml, startPos = seekNext(start - 1), lvp; |
502 | + for (i = start; i < end; i++) { //clear selection |
503 | + delete getMaskSet()["validPositions"][i]; |
504 | + } |
505 | + |
506 | + for (i = seekNext(end - 1) ; i <= getLastValidPosition() ; i = seekNext(i)) { |
507 | + var t = getMaskSet()["validPositions"][i]; |
508 | + var s = getMaskSet()["validPositions"][startPos]; |
509 | + if (t != undefined && s == undefined) { |
510 | + if (getTest(startPos).def == t.match.def && isValid(startPos, t["input"], true) !== false) { |
511 | + delete getMaskSet()["validPositions"][i]; |
512 | + } |
513 | + startPos = seekNext(startPos); |
514 | + } |
515 | + } |
516 | + var lvp = getLastValidPosition(); |
517 | + //catchup |
518 | + while (lvp > 0 && (getMaskSet()["validPositions"][lvp] == undefined || getMaskSet()["validPositions"][lvp].match.fn == null)) { |
519 | + delete getMaskSet()["validPositions"][lvp]; |
520 | + lvp--; |
521 | + } |
522 | + resetMaskSet(true); |
523 | + } |
524 | + |
525 | + function getTest(pos) { |
526 | + if (getMaskSet()['validPositions'][pos]) { |
527 | + return getMaskSet()['validPositions'][pos]["match"]; |
528 | + } |
529 | + return getTests(pos)[0]["match"]; |
530 | + } |
531 | + |
532 | + function getTests(pos, ndxIntlzr, tstPs) { |
533 | + var maskTokens = getMaskSet()["maskToken"], testPos = ndxIntlzr ? tstPs : 0, ndxInitializer = ndxIntlzr || [0], matches = [], insertStop = false; |
534 | + |
535 | + function ResolveTestFromToken(maskToken, ndxInitializer, loopNdx, quantifierRecurse) { //ndxInitilizer contains a set of indexes to speedup searches in the mtokens |
536 | + |
537 | + function handleMatch(match, loopNdx, quantifierRecurse) { |
538 | + if (testPos == pos && match.matches == undefined) { |
539 | + matches.push({ "match": match, "locator": loopNdx.reverse() }); |
540 | + return true; |
541 | + } else if (match.matches != undefined) { |
542 | + if (match.isGroup && quantifierRecurse !== true) { //when a group pass along to the quantifier |
543 | + match = handleMatch(maskToken.matches[tndx + 1], loopNdx); |
544 | + if (match) return true; |
545 | + } else if (match.isOptional) { |
546 | + var optionalToken = match; |
547 | + match = ResolveTestFromToken(match, ndxInitializer, loopNdx, quantifierRecurse); |
548 | + if (match) { |
549 | + var latestMatch = matches[matches.length - 1]["match"]; |
550 | + var isFirstMatch = (optionalToken.matches.indexOf(latestMatch) == 0); |
551 | + if (isFirstMatch) { |
552 | + insertStop = true; //insert a stop for non greedy |
553 | + } |
554 | + testPos = pos; //match the position after the group |
555 | + } |
556 | + } else if (match.isAlternator) { |
557 | + //TODO |
558 | + } else if (match.isQuantifier && quantifierRecurse !== true) { |
559 | + var qt = match; |
560 | + for (var qndx = (ndxInitializer.length > 0 && quantifierRecurse !== true) ? ndxInitializer.shift() : 0; (qndx < (isNaN(qt.quantifier.max) ? qndx + 1 : qt.quantifier.max)) && testPos <= pos; qndx++) { |
561 | + var tokenGroup = maskToken.matches[maskToken.matches.indexOf(qt) - 1]; |
562 | + match = handleMatch(tokenGroup, [qndx].concat(loopNdx), true); |
563 | + if (match) { |
564 | + //get latest match |
565 | + var latestMatch = matches[matches.length - 1]["match"]; |
566 | + latestMatch.optionalQuantifier = qndx > qt.quantifier.min - 1; |
567 | + var isFirstMatch = (tokenGroup.matches.indexOf(latestMatch) == 0); |
568 | + if (isFirstMatch) { //search for next possible match |
569 | + if (qndx > qt.quantifier.min - 1) { |
570 | + insertStop = true; |
571 | + testPos = pos; //match the position after the group |
572 | + break; //stop quantifierloop |
573 | + } else return true; |
574 | + } else { |
575 | + return true; |
576 | + } |
577 | + } |
578 | + } |
579 | + } else { |
580 | + match = ResolveTestFromToken(match, ndxInitializer, loopNdx, quantifierRecurse); |
581 | + if (match) |
582 | + return true; |
583 | + } |
584 | + } else testPos++; |
585 | + } |
586 | + |
587 | + for (var tndx = (ndxInitializer.length > 0 ? ndxInitializer.shift() : 0) ; tndx < maskToken.matches.length; tndx++) { |
588 | + if (maskToken.matches[tndx]["isQuantifier"] !== true) { |
589 | + var match = handleMatch(maskToken.matches[tndx], [tndx].concat(loopNdx), quantifierRecurse); |
590 | + if (match && testPos == pos) { |
591 | + return match; |
592 | + } else if (testPos > pos) { |
593 | + break; |
594 | + } |
595 | + } |
596 | + } |
597 | + } |
598 | + |
599 | + //if (disableCache !== true && getMaskSet()['tests'][pos] && !getMaskSet()['validPositions'][pos]) { |
600 | + // return getMaskSet()['tests'][pos]; |
601 | + //} |
602 | + if (ndxIntlzr == undefined) { |
603 | + var previousPos = pos - 1, test; |
604 | + while ((test = getMaskSet()['validPositions'][previousPos]) == undefined && previousPos > -1) { |
605 | + previousPos--; |
606 | + } |
607 | + if (test != undefined && previousPos > -1) { |
608 | + testPos = previousPos; |
609 | + ndxInitializer = test["locator"].slice(); |
610 | + } else { |
611 | + previousPos = pos - 1; |
612 | + while ((test = getMaskSet()['tests'][previousPos]) == undefined && previousPos > -1) { |
613 | + previousPos--; |
614 | + } |
615 | + if (test != undefined && previousPos > -1) { |
616 | + testPos = previousPos; |
617 | + ndxInitializer = test[0]["locator"].slice(); |
618 | + } |
619 | + } |
620 | + } |
621 | + for (var mtndx = ndxInitializer.shift() ; mtndx < maskTokens.length; mtndx++) { |
622 | + var match = ResolveTestFromToken(maskTokens[mtndx], ndxInitializer, [mtndx]); |
623 | + if ((match && testPos == pos) || testPos > pos) { |
624 | + break; |
625 | + } |
626 | + } |
627 | + if (matches.length == 0 || (insertStop && matches.length < 2)) |
628 | + matches.push({ "match": { fn: null, cardinality: 0, optionality: true, casing: null, def: "" }, "locator": [] }); |
629 | + |
630 | + getMaskSet()['tests'][pos] = matches; |
631 | + //console.log(pos + " - " + JSON.stringify(matches)); |
632 | + return matches; |
633 | + } |
634 | + |
635 | + function getBufferTemplate() { |
636 | + if (getMaskSet()['_buffer'] == undefined) { |
637 | + //generate template |
638 | + getMaskSet()["_buffer"] = getMaskTemplate(false, 1); |
639 | + } |
640 | + return getMaskSet()['_buffer']; |
641 | + } |
642 | + |
643 | + function getBuffer() { |
644 | + if (getMaskSet()['buffer'] == undefined) { |
645 | + getMaskSet()['buffer'] = getMaskTemplate(true, getLastValidPosition(), true); |
646 | + } |
647 | + return getMaskSet()['buffer']; |
648 | + } |
649 | + |
650 | + function refreshFromBuffer(start, end) { |
651 | + var buffer = getBuffer().slice(); //work on clone |
652 | + for (var i = start; i < end; i++) { |
653 | + if (buffer[i] != getPlaceholder(i) && buffer[i] != opts.skipOptionalPartCharacter) { |
654 | + isValid(i, buffer[i], true, true); |
655 | + } |
656 | + } |
657 | + } |
658 | + |
659 | + function casing(elem, test) { |
660 | + switch (test.casing) { |
661 | + case "upper": |
662 | + elem = elem.toUpperCase(); |
663 | + break; |
664 | + case "lower": |
665 | + elem = elem.toLowerCase(); |
666 | + break; |
667 | + } |
668 | + |
669 | + return elem; |
670 | + } |
671 | + |
672 | + function isValid(pos, c, strict, fromSetValid) { //strict true ~ no correction or autofill |
673 | + strict = strict === true; //always set a value to strict to prevent possible strange behavior in the extensions |
674 | + |
675 | + function _isValid(position, c, strict, fromSetValid) { |
676 | + |
677 | + var rslt = false; |
678 | + $.each(getTests(position), function (ndx, tst) { |
679 | + var test = tst["match"]; |
680 | + var loopend = c ? 1 : 0, chrs = '', buffer = getBuffer(); |
681 | + for (var i = test.cardinality; i > loopend; i--) { |
682 | + chrs += getBufferElement(position - (i - 1)); |
683 | + } |
684 | + if (c) { |
685 | + chrs += c; |
686 | + } |
687 | + |
688 | + //return is false or a json object => { pos: ??, c: ??} or true |
689 | + rslt = test.fn != null ? |
690 | + test.fn.test(chrs, buffer, position, strict, opts) |
691 | + : (c == test["def"] || c == opts.skipOptionalPartCharacter) && test["def"] != "" ? //non mask |
692 | + { c: test["def"], pos: position } |
693 | + : false; |
694 | + |
695 | + if (rslt !== false) { |
696 | + var elem = rslt.c != undefined ? rslt.c : c; |
697 | + elem = (elem == opts.skipOptionalPartCharacter && test["fn"] === null) ? test["def"] : elem; |
698 | + |
699 | + var validatedPos = position; |
700 | + if (rslt["refreshFromBuffer"]) { |
701 | + var refresh = rslt["refreshFromBuffer"]; |
702 | + strict = true; |
703 | + if (refresh === true) { |
704 | + getMaskSet()["validPositions"] = {}; |
705 | + getMaskSet()["tests"] = {}; |
706 | + refreshFromBuffer(0, getBuffer().length); |
707 | + } |
708 | + else { |
709 | + refreshFromBuffer(refresh["start"], refresh["end"]); |
710 | + } |
711 | + if (rslt.pos == undefined) { |
712 | + rslt.pos = getLastValidPosition(); |
713 | + return false;//breakout if refreshFromBuffer && nothing to insert |
714 | + } |
715 | + validatedPos = rslt.pos != undefined ? rslt.pos : position; |
716 | + tst = getTests(validatedPos)[0]; //possible mismatch TODO |
717 | + |
718 | + } else if (rslt !== true && rslt["pos"] != position) { //their is a position offset |
719 | + validatedPos = rslt["pos"]; |
720 | + refreshFromBuffer(position, validatedPos); |
721 | + tst = getTests(validatedPos)[0]; //possible mismatch TODO |
722 | + } |
723 | + if (ndx > 0) { |
724 | + resetMaskSet(true); |
725 | + } |
726 | + if (!setValidPosition(validatedPos, $.extend({}, tst, { "input": casing(elem, test) }), strict, fromSetValid)) |
727 | + rslt = false; |
728 | + return false; //break from $.each |
729 | + } |
730 | + }); |
731 | + |
732 | + return rslt; |
733 | + } |
734 | + |
735 | + var maskPos = pos; |
736 | + var result = _isValid(maskPos, c, strict, fromSetValid); |
737 | + if (!strict && (opts.insertMode || getMaskSet()["validPositions"][seekNext(maskPos)] == undefined) && result === false && !isMask(maskPos)) { //does the input match on a further position? |
738 | + for (var nPos = maskPos + 1, snPos = seekNext(maskPos) ; nPos <= snPos; nPos++) { |
739 | + result = _isValid(nPos, c, strict, fromSetValid); |
740 | + if (result !== false) { |
741 | + maskPos = nPos; |
742 | + break; |
743 | + } |
744 | + } |
745 | + } |
746 | + |
747 | + if (result === true) result = { "pos": maskPos }; |
748 | + return result; |
749 | + } |
750 | + |
751 | + function isMask(pos) { |
752 | + var test = getTest(pos); |
753 | + return test.fn != null ? test.fn : false; |
754 | + } |
755 | + |
756 | + function getMaskLength() { |
757 | + var maskLength; |
758 | + maxLength = $el.prop('maxLength'); |
759 | + if (maxLength == -1) maxLength = undefined; /* FF sets no defined max length to -1 */ |
760 | + if (opts.greedy == false) { //TODO FIXME OPTIMIZE ME |
761 | + var lvp = getLastValidPosition() + 1, |
762 | + test = getTest(lvp); |
763 | + while (!(test.fn == null && test.def == "")) { //determine last possible position |
764 | + test = getTest(++lvp); |
765 | + if (test.optionality !== true) { |
766 | + var tests = getTests(lvp); |
767 | + test = tests[tests.length - 1]["match"]; |
768 | + } |
769 | + } |
770 | + maskLength = getMaskTemplate(true, lvp).length; |
771 | + getMaskSet()["tests"] = {}; //cleanup tests |
772 | + } else |
773 | + maskLength = getBuffer().length; |
774 | + |
775 | + return (maxLength == undefined || maskLength < maxLength) ? maskLength : maxLength; |
776 | + } |
777 | + |
778 | + function seekNext(pos) { |
779 | + var maskL = getMaskLength(); |
780 | + if (pos >= maskL) return maskL; |
781 | + var position = pos; |
782 | + while (++position < maskL && !isMask(position) && (opts.nojumps !== true || opts.nojumpsThreshold > position)) { |
783 | + } |
784 | + return position; |
785 | + } |
786 | + |
787 | + function seekPrevious(pos) { |
788 | + var position = pos; |
789 | + if (position <= 0) return 0; |
790 | + |
791 | + while (--position > 0 && !isMask(position)) { |
792 | + }; |
793 | + return position; |
794 | + } |
795 | + |
796 | + function getBufferElement(position) { |
797 | + return getMaskSet()["validPositions"][position] == undefined ? getPlaceholder(position) : getMaskSet()["validPositions"][position]["input"]; |
798 | + } |
799 | + |
800 | + function writeBuffer(input, buffer, caretPos) { |
801 | + input._valueSet(buffer.join('')); |
802 | + if (caretPos != undefined) { |
803 | + caret(input, caretPos); |
804 | + } |
805 | + } |
806 | + |
807 | + function getPlaceholder(pos, test) { |
808 | + test = test || getTest(pos); |
809 | + return test["fn"] == null ? test["def"] : opts.placeholder.charAt(pos % opts.placeholder.length); |
810 | + } |
811 | + |
812 | + function checkVal(input, writeOut, strict, nptvl, intelliCheck) { |
813 | + var inputValue = nptvl != undefined ? nptvl.slice() : truncateInput(input._valueGet()).split(''); |
814 | + resetMaskSet(); |
815 | + if (writeOut) input._valueSet(""); //initial clear |
816 | + $.each(inputValue, function (ndx, charCode) { |
817 | + if (intelliCheck === true) { |
818 | + var p = getMaskSet()["p"], |
819 | + lvp = p == -1 ? p : seekPrevious(p), |
820 | + pos = lvp == -1 ? ndx : seekNext(lvp); |
821 | + if ($.inArray(charCode, getBufferTemplate().slice(lvp + 1, pos)) == -1) { |
822 | + keypressEvent.call(input, undefined, true, charCode.charCodeAt(0), false, strict, ndx); |
823 | + } |
824 | + } else { |
825 | + keypressEvent.call(input, undefined, true, charCode.charCodeAt(0), false, strict, ndx); |
826 | + strict = strict || (ndx > 0 && ndx > getMaskSet()["p"]); |
827 | + } |
828 | + }); |
829 | + if (writeOut) |
830 | + writeBuffer(input, getBuffer(), seekNext(getLastValidPosition())); |
831 | + } |
832 | + |
833 | + function escapeRegex(str) { |
834 | + return $.inputmask.escapeRegex.call(this, str); |
835 | + } |
836 | + |
837 | + function truncateInput(inputValue) { |
838 | + return inputValue.replace(new RegExp("(" + escapeRegex(getBufferTemplate().join('')) + ")*$"), ""); |
839 | + } |
840 | + |
841 | + function clearOptionalTail(input) { |
842 | + var buffer = getBuffer(), tmpBuffer = buffer.slice(), |
843 | + pos, lvp = getLastValidPosition(), positions = {}, |
844 | + ndxIntlzr = getMaskSet()["validPositions"][lvp]["locator"].slice(), testPos; |
845 | + for (pos = lvp + 1; pos < tmpBuffer.length; pos++) { |
846 | + testPos = getTests(pos, ndxIntlzr, pos - 1); |
847 | + var firstMatch = testPos[0]["match"]; |
848 | + testPos = testPos[(opts.greedy || (firstMatch.optionality === true && firstMatch.newBlockMarker === false && firstMatch.optionalQuantifier !== true)) ? 0 : (testPos.length - 1)]; |
849 | + positions[pos] = testPos; |
850 | + ndxIntlzr = testPos["locator"].slice(); |
851 | + } |
852 | + |
853 | + for (pos = tmpBuffer.length - 1; pos > lvp; pos--) { |
854 | + testPos = positions[pos]["match"]; |
855 | + if (testPos.optionality && tmpBuffer[pos] == getPlaceholder(pos, testPos)) { |
856 | + tmpBuffer.pop(); |
857 | + } else break; |
858 | + } |
859 | + writeBuffer(input, tmpBuffer); |
860 | + } |
861 | + |
862 | + function unmaskedvalue($input, skipDatepickerCheck) { |
863 | + if ($input.data('_inputmask') && (skipDatepickerCheck === true || !$input.hasClass('hasDatepicker'))) { |
864 | + var umValue = $.map(getBuffer(), function (element, index) { |
865 | + return isMask(index) && isValid(index, element, true) ? element : null; |
866 | + }); |
867 | + var unmaskedValue = (isRTL ? umValue.reverse() : umValue).join(''); |
868 | + var bufferValue = (isRTL ? getBuffer().reverse() : getBuffer()).join(''); |
869 | + return $.isFunction(opts.onUnMask) ? opts.onUnMask.call($input, bufferValue, unmaskedValue, opts) : unmaskedValue; |
870 | + } else { |
871 | + return $input[0]._valueGet(); |
872 | + } |
873 | + } |
874 | + |
875 | + function TranslatePosition(pos) { |
876 | + if (isRTL && typeof pos == 'number' && (!opts.greedy || opts.placeholder != "")) { |
877 | + var bffrLght = getBuffer().length; |
878 | + pos = bffrLght - pos; |
879 | + } |
880 | + return pos; |
881 | + } |
882 | + |
883 | + function caret(input, begin, end) { |
884 | + var npt = input.jquery && input.length > 0 ? input[0] : input, range; |
885 | + if (typeof begin == 'number') { |
886 | + begin = TranslatePosition(begin); |
887 | + end = TranslatePosition(end); |
888 | + end = (typeof end == 'number') ? end : begin; |
889 | + |
890 | + //store caret for multi scope |
891 | + var data = $(npt).data('_inputmask') || {}; |
892 | + data["caret"] = { "begin": begin, "end": end }; |
893 | + $(npt).data('_inputmask', data); |
894 | + |
895 | + if (!$(npt).is(':visible')) { |
896 | + return; |
897 | + } |
898 | + |
899 | + npt.scrollLeft = npt.scrollWidth; |
900 | + if (opts.insertMode == false && begin == end) end++; //set visualization for insert/overwrite mode |
901 | + if (npt.setSelectionRange) { |
902 | + npt.selectionStart = begin; |
903 | + npt.selectionEnd = end; |
904 | + |
905 | + } else if (npt.createTextRange) { |
906 | + range = npt.createTextRange(); |
907 | + range.collapse(true); |
908 | + range.moveEnd('character', end); |
909 | + range.moveStart('character', begin); |
910 | + range.select(); |
911 | + } |
912 | + } else { |
913 | + var data = $(npt).data('_inputmask'); |
914 | + if (!$(npt).is(':visible') && data && data["caret"] != undefined) { |
915 | + begin = data["caret"]["begin"]; |
916 | + end = data["caret"]["end"]; |
917 | + } else if (npt.setSelectionRange) { |
918 | + begin = npt.selectionStart; |
919 | + end = npt.selectionEnd; |
920 | + } else if (document.selection && document.selection.createRange) { |
921 | + range = document.selection.createRange(); |
922 | + begin = 0 - range.duplicate().moveStart('character', -100000); |
923 | + end = begin + range.text.length; |
924 | + } |
925 | + begin = TranslatePosition(begin); |
926 | + end = TranslatePosition(end); |
927 | + return { "begin": begin, "end": end }; |
928 | + } |
929 | + } |
930 | + |
931 | + function isComplete(buffer) { //return true / false / undefined (repeat *) |
932 | + if ($.isFunction(opts.isComplete)) return opts.isComplete.call($el, buffer, opts); |
933 | + if (opts.repeat == "*") return undefined; |
934 | + var complete = false, |
935 | + aml = seekPrevious(getMaskLength()); |
936 | + if (getLastValidPosition() == aml) { |
937 | + complete = true; |
938 | + for (var i = 0; i <= aml; i++) { |
939 | + var mask = isMask(i); |
940 | + if ((mask && (buffer[i] == undefined || buffer[i] == getPlaceholder(i))) || (!mask && buffer[i] != getPlaceholder(i))) { |
941 | + complete = false; |
942 | + break; |
943 | + } |
944 | + } |
945 | + } |
946 | + return complete; |
947 | + } |
948 | + |
949 | + function isSelection(begin, end) { |
950 | + return isRTL ? (begin - end) > 1 || ((begin - end) == 1 && opts.insertMode) : |
951 | + (end - begin) > 1 || ((end - begin) == 1 && opts.insertMode); |
952 | + } |
953 | + |
954 | + function installEventRuler(npt) { |
955 | + var events = $._data(npt).events; |
956 | + |
957 | + $.each(events, function (eventType, eventHandlers) { |
958 | + $.each(eventHandlers, function (ndx, eventHandler) { |
959 | + if (eventHandler.namespace == "inputmask") { |
960 | + if (eventHandler.type != "setvalue") { |
961 | + var handler = eventHandler.handler; |
962 | + eventHandler.handler = function (e) { |
963 | + if (this.readOnly || this.disabled) |
964 | + e.preventDefault; |
965 | + else |
966 | + return handler.apply(this, arguments); |
967 | + }; |
968 | + } |
969 | + } |
970 | + }); |
971 | + }); |
972 | + } |
973 | + |
974 | + function patchValueProperty(npt) { |
975 | + |
976 | + function PatchValhook(type) { |
977 | + if ($.valHooks[type] == undefined || $.valHooks[type].inputmaskpatch != true) { |
978 | + var valueGet = $.valHooks[type] && $.valHooks[type].get ? $.valHooks[type].get : function (elem) { return elem.value; }; |
979 | + var valueSet = $.valHooks[type] && $.valHooks[type].set ? $.valHooks[type].set : function (elem, value) { |
980 | + elem.value = value; |
981 | + return elem; |
982 | + }; |
983 | + |
984 | + $.valHooks[type] = { |
985 | + get: function (elem) { |
986 | + var $elem = $(elem); |
987 | + if ($elem.data('_inputmask')) { |
988 | + if ($elem.data('_inputmask')['opts'].autoUnmask) |
989 | + return $elem.inputmask('unmaskedvalue'); |
990 | + else { |
991 | + var result = valueGet(elem), |
992 | + inputData = $elem.data('_inputmask'), |
993 | + maskset = inputData['maskset'], |
994 | + bufferTemplate = maskset['_buffer']; |
995 | + bufferTemplate = bufferTemplate ? bufferTemplate.join('') : ''; |
996 | + return result != bufferTemplate ? result : ''; |
997 | + } |
998 | + } else return valueGet(elem); |
999 | + }, |
1000 | + set: function (elem, value) { |
1001 | + var $elem = $(elem); |
1002 | + var result = valueSet(elem, value); |
1003 | + if ($elem.data('_inputmask')) $elem.triggerHandler('setvalue.inputmask'); |
1004 | + return result; |
1005 | + }, |
1006 | + inputmaskpatch: true |
1007 | + }; |
1008 | + } |
1009 | + } |
1010 | + |
1011 | + var valueProperty; |
1012 | + if (Object.getOwnPropertyDescriptor) |
1013 | + valueProperty = Object.getOwnPropertyDescriptor(npt, "value"); |
1014 | + if (valueProperty && valueProperty.get) { |
1015 | + if (!npt._valueGet) { |
1016 | + var valueGet = valueProperty.get; |
1017 | + var valueSet = valueProperty.set; |
1018 | + npt._valueGet = function () { |
1019 | + return isRTL ? valueGet.call(this).split('').reverse().join('') : valueGet.call(this); |
1020 | + }; |
1021 | + npt._valueSet = function (value) { |
1022 | + valueSet.call(this, isRTL ? value.split('').reverse().join('') : value); |
1023 | + }; |
1024 | + |
1025 | + Object.defineProperty(npt, "value", { |
1026 | + get: function () { |
1027 | + var $self = $(this), inputData = $(this).data('_inputmask'), maskset = inputData['maskset']; |
1028 | + return inputData && inputData['opts'].autoUnmask ? $self.inputmask('unmaskedvalue') : valueGet.call(this) != maskset['_buffer'].join('') ? valueGet.call(this) : ''; |
1029 | + }, |
1030 | + set: function (value) { |
1031 | + valueSet.call(this, value); |
1032 | + $(this).triggerHandler('setvalue.inputmask'); |
1033 | + } |
1034 | + }); |
1035 | + } |
1036 | + } else if (document.__lookupGetter__ && npt.__lookupGetter__("value")) { |
1037 | + if (!npt._valueGet) { |
1038 | + var valueGet = npt.__lookupGetter__("value"); |
1039 | + var valueSet = npt.__lookupSetter__("value"); |
1040 | + npt._valueGet = function () { |
1041 | + return isRTL ? valueGet.call(this).split('').reverse().join('') : valueGet.call(this); |
1042 | + }; |
1043 | + npt._valueSet = function (value) { |
1044 | + valueSet.call(this, isRTL ? value.split('').reverse().join('') : value); |
1045 | + }; |
1046 | + |
1047 | + npt.__defineGetter__("value", function () { |
1048 | + var $self = $(this), inputData = $(this).data('_inputmask'), maskset = inputData['maskset']; |
1049 | + return inputData && inputData['opts'].autoUnmask ? $self.inputmask('unmaskedvalue') : valueGet.call(this) != maskset['_buffer'].join('') ? valueGet.call(this) : ''; |
1050 | + }); |
1051 | + npt.__defineSetter__("value", function (value) { |
1052 | + valueSet.call(this, value); |
1053 | + $(this).triggerHandler('setvalue.inputmask'); |
1054 | + }); |
1055 | + } |
1056 | + } else { |
1057 | + if (!npt._valueGet) { |
1058 | + npt._valueGet = function () { return isRTL ? this.value.split('').reverse().join('') : this.value; }; |
1059 | + npt._valueSet = function (value) { this.value = isRTL ? value.split('').reverse().join('') : value; }; |
1060 | + } |
1061 | + PatchValhook(npt.type); |
1062 | + } |
1063 | + } |
1064 | + |
1065 | + function HandleRemove(input, k, pos) { |
1066 | + if (opts.numericInput || isRTL) { |
1067 | + switch (k) { |
1068 | + case opts.keyCode.BACKSPACE: |
1069 | + k = opts.keyCode.DELETE; |
1070 | + break; |
1071 | + case opts.keyCode.DELETE: |
1072 | + k = opts.keyCode.BACKSPACE; |
1073 | + break; |
1074 | + } |
1075 | + if (isRTL) { |
1076 | + var pend = pos.end; |
1077 | + pos.end = pos.begin; |
1078 | + pos.begin = pend; |
1079 | + } |
1080 | + } |
1081 | + |
1082 | + if (pos.begin == pos.end) { |
1083 | + var posBegin = k == opts.keyCode.BACKSPACE ? pos.begin - 1 : pos.begin; |
1084 | + if (opts.isNumeric && opts.radixPoint != "" && getBuffer()[posBegin] == opts.radixPoint) { |
1085 | + pos.begin = (getBuffer().length - 1 == posBegin) /* radixPoint is latest? delete it */ ? pos.begin : k == opts.keyCode.BACKSPACE ? posBegin : seekNext(posBegin); |
1086 | + pos.end = pos.begin; |
1087 | + } |
1088 | + if (k == opts.keyCode.BACKSPACE) |
1089 | + pos.begin = seekPrevious(pos.begin); |
1090 | + else if (k == opts.keyCode.DELETE) |
1091 | + pos.end++; |
1092 | + } else if (pos.end - pos.begin == 1 && !opts.insertMode) { |
1093 | + if (k == opts.keyCode.BACKSPACE) |
1094 | + pos.begin--; |
1095 | + } |
1096 | + |
1097 | + stripValidPositions(pos.begin, pos.end); |
1098 | + var firstMaskPos = seekNext(-1); |
1099 | + if (getLastValidPosition() < firstMaskPos) { |
1100 | + getMaskSet()["p"] = firstMaskPos; |
1101 | + } else { |
1102 | + getMaskSet()["p"] = pos.begin; |
1103 | + } |
1104 | + } |
1105 | + |
1106 | + function keydownEvent(e) { |
1107 | + //Safari 5.1.x - modal dialog fires keypress twice workaround |
1108 | + skipKeyPressEvent = false; |
1109 | + var input = this, $input = $(input), k = e.keyCode, pos = caret(input); |
1110 | + |
1111 | + //backspace, delete, and escape get special treatment |
1112 | + if (k == opts.keyCode.BACKSPACE || k == opts.keyCode.DELETE || (iphone && k == 127) || e.ctrlKey && k == 88) { //backspace/delete |
1113 | + e.preventDefault(); //stop default action but allow propagation |
1114 | + if (k == 88) valueOnFocus = getBuffer().join(''); |
1115 | + HandleRemove(input, k, pos); |
1116 | + writeBuffer(input, getBuffer(), getMaskSet()["p"]); |
1117 | + if (input._valueGet() == getBufferTemplate().join('')) |
1118 | + $input.trigger('cleared'); |
1119 | + |
1120 | + if (opts.showTooltip) { //update tooltip |
1121 | + $input.prop("title", getMaskSet()["mask"]); |
1122 | + } |
1123 | + } else if (k == opts.keyCode.END || k == opts.keyCode.PAGE_DOWN) { //when END or PAGE_DOWN pressed set position at lastmatch |
1124 | + setTimeout(function () { |
1125 | + var caretPos = seekNext(getLastValidPosition()); |
1126 | + if (!opts.insertMode && caretPos == getMaskLength() && !e.shiftKey) caretPos--; |
1127 | + caret(input, e.shiftKey ? pos.begin : caretPos, caretPos); |
1128 | + }, 0); |
1129 | + } else if ((k == opts.keyCode.HOME && !e.shiftKey) || k == opts.keyCode.PAGE_UP) { //Home or page_up |
1130 | + caret(input, 0, e.shiftKey ? pos.begin : 0); |
1131 | + } else if (k == opts.keyCode.ESCAPE || (k == 90 && e.ctrlKey)) { //escape && undo |
1132 | + checkVal(input, true, false, valueOnFocus.split('')); |
1133 | + $input.click(); |
1134 | + } else if (k == opts.keyCode.INSERT && !(e.shiftKey || e.ctrlKey)) { //insert |
1135 | + opts.insertMode = !opts.insertMode; |
1136 | + caret(input, !opts.insertMode && pos.begin == getMaskLength() ? pos.begin - 1 : pos.begin); |
1137 | + } else if (opts.insertMode == false && !e.shiftKey) { |
1138 | + if (k == opts.keyCode.RIGHT) { |
1139 | + setTimeout(function () { |
1140 | + var caretPos = caret(input); |
1141 | + caret(input, caretPos.begin); |
1142 | + }, 0); |
1143 | + } else if (k == opts.keyCode.LEFT) { |
1144 | + setTimeout(function () { |
1145 | + var caretPos = caret(input); |
1146 | + caret(input, caretPos.begin - 1); |
1147 | + }, 0); |
1148 | + } |
1149 | + } |
1150 | + |
1151 | + var currentCaretPos = caret(input); |
1152 | + var keydownResult = opts.onKeyDown.call(this, e, getBuffer(), opts); |
1153 | + if (keydownResult && keydownResult["refreshFromBuffer"] === true) { //extra stuff to execute on keydown |
1154 | + getMaskSet()["validPositions"] = {}; |
1155 | + refreshFromBuffer(0, getBuffer().length); |
1156 | + caret(input, currentCaretPos.begin, currentCaretPos.end); |
1157 | + } |
1158 | + ignorable = $.inArray(k, opts.ignorables) != -1; |
1159 | + } |
1160 | + |
1161 | + function keypressEvent(e, checkval, k, writeOut, strict, ndx) { |
1162 | + //Safari 5.1.x - modal dialog fires keypress twice workaround |
1163 | + if (k == undefined && skipKeyPressEvent) return false; |
1164 | + skipKeyPressEvent = true; |
1165 | + |
1166 | + var input = this, $input = $(input); |
1167 | + |
1168 | + e = e || window.event; |
1169 | + var k = checkval ? k : (e.which || e.charCode || e.keyCode); |
1170 | + |
1171 | + if (checkval !== true && (!(e.ctrlKey && e.altKey) && (e.ctrlKey || e.metaKey || ignorable))) { |
1172 | + return true; |
1173 | + } else { |
1174 | + if (k) { |
1175 | + //special treat the decimal separator |
1176 | + if (checkval !== true && k == 46 && e.shiftKey == false && opts.radixPoint == ",") k = 44; |
1177 | + |
1178 | + var pos, forwardPosition, c = String.fromCharCode(k); |
1179 | + if (checkval) { |
1180 | + var pcaret = strict ? ndx : getLastValidPosition() + 1; |
1181 | + pos = { begin: pcaret, end: pcaret }; |
1182 | + } else { |
1183 | + pos = caret(input); |
1184 | + } |
1185 | + |
1186 | + //should we clear a possible selection?? |
1187 | + var isSlctn = isSelection(pos.begin, pos.end); |
1188 | + if (isSlctn) { |
1189 | + getMaskSet()["undoPositions"] = $.extend(true, {}, getMaskSet()["validPositions"]); //init undobuffer for recovery when not valid |
1190 | + HandleRemove(input, opts.keyCode.DELETE, pos); |
1191 | + if (!opts.insertMode) { //preserve some space |
1192 | + opts.insertMode = !opts.insertMode; |
1193 | + setValidPosition(pos.begin, undefined, strict); |
1194 | + opts.insertMode = !opts.insertMode; |
1195 | + } |
1196 | + isSlctn = !opts.multi; |
1197 | + } |
1198 | + |
1199 | + var radixPosition = getBuffer().join('').indexOf(opts.radixPoint); |
1200 | + if (opts.isNumeric && checkval !== true && radixPosition != -1) { |
1201 | + if (opts.greedy && pos.begin <= radixPosition) { |
1202 | + pos.begin = seekPrevious(pos.begin); |
1203 | + pos.end = pos.begin; |
1204 | + } else if (c == opts.radixPoint) { |
1205 | + pos.begin = radixPosition; |
1206 | + pos.end = pos.begin; |
1207 | + } |
1208 | + } |
1209 | + |
1210 | + getMaskSet()["writeOutBuffer"] = true; |
1211 | + var p = pos.begin; |
1212 | + var valResult = isValid(p, c, strict); |
1213 | + if (valResult !== false) { |
1214 | + if (valResult !== true) { |
1215 | + p = valResult.pos != undefined ? valResult.pos : p; //set new position from isValid |
1216 | + c = valResult.c != undefined ? valResult.c : c; //set new char from isValid |
1217 | + } |
1218 | + resetMaskSet(true); |
1219 | + forwardPosition = valResult.caret != undefined ? valResult.caret : seekNext(p); |
1220 | + getMaskSet()["p"] = forwardPosition; //needed for checkval |
1221 | + } |
1222 | + |
1223 | + if (writeOut !== false) { |
1224 | + var self = this; |
1225 | + setTimeout(function () { opts.onKeyValidation.call(self, valResult, opts); }, 0); |
1226 | + if (getMaskSet()["writeOutBuffer"] && valResult !== false) { |
1227 | + var buffer = getBuffer(); |
1228 | + |
1229 | + var newCaretPosition; |
1230 | + if (checkval) { |
1231 | + newCaretPosition = undefined; |
1232 | + } else if (opts.numericInput) { |
1233 | + if (p > radixPosition) { |
1234 | + newCaretPosition = seekPrevious(forwardPosition); |
1235 | + } else if (c == opts.radixPoint) { |
1236 | + newCaretPosition = forwardPosition - 1; |
1237 | + } else newCaretPosition = seekPrevious(forwardPosition - 1); |
1238 | + } else { |
1239 | + newCaretPosition = forwardPosition; |
1240 | + } |
1241 | + |
1242 | + writeBuffer(input, buffer, newCaretPosition); |
1243 | + if (checkval !== true) { |
1244 | + setTimeout(function () { //timeout needed for IE |
1245 | + if (isComplete(buffer) === true) |
1246 | + $input.trigger("complete"); |
1247 | + skipInputEvent = true; |
1248 | + $input.trigger("input"); |
1249 | + }, 0); |
1250 | + } |
1251 | + } else if (isSlctn) { |
1252 | + getMaskSet()["buffer"] = undefined; |
1253 | + getMaskSet()["validPositions"] = getMaskSet()["undoPositions"]; |
1254 | + } |
1255 | + } else if (isSlctn) { |
1256 | + getMaskSet()["buffer"] = undefined; |
1257 | + getMaskSet()["validPositions"] = getMaskSet()["undoPositions"]; |
1258 | + } |
1259 | + |
1260 | + |
1261 | + if (opts.showTooltip) { //update tooltip |
1262 | + $input.prop("title", getMaskSet()["mask"]); |
1263 | + } |
1264 | + |
1265 | + //needed for IE8 and below |
1266 | + if (e && checkval != true) e.preventDefault ? e.preventDefault() : e.returnValue = false; |
1267 | + } |
1268 | + } |
1269 | + } |
1270 | + |
1271 | + function keyupEvent(e) { |
1272 | + var $input = $(this), input = this, k = e.keyCode, buffer = getBuffer(); |
1273 | + |
1274 | + var keyupResult = opts.onKeyUp.call(this, e, buffer, opts); |
1275 | + if (keyupResult && keyupResult["refreshFromBuffer"] === true) { |
1276 | + getMaskSet()["validPositions"] = {}; |
1277 | + refreshFromBuffer(0, getBuffer().length); |
1278 | + } |
1279 | + if (k == opts.keyCode.TAB && opts.showMaskOnFocus) { |
1280 | + if ($input.hasClass('focus.inputmask') && input._valueGet().length == 0) { |
1281 | + resetMaskSet(); |
1282 | + buffer = getBuffer(); |
1283 | + writeBuffer(input, buffer); |
1284 | + caret(input, 0); |
1285 | + valueOnFocus = getBuffer().join(''); |
1286 | + } else { |
1287 | + writeBuffer(input, buffer); |
1288 | + if (buffer.join('') == getBufferTemplate().join('') && $.inArray(opts.radixPoint, buffer) != -1) { |
1289 | + caret(input, TranslatePosition(0)); |
1290 | + $input.click(); |
1291 | + } else |
1292 | + caret(input, TranslatePosition(0), TranslatePosition(getMaskLength())); |
1293 | + } |
1294 | + } |
1295 | + } |
1296 | + |
1297 | + function pasteEvent(e) { |
1298 | + if (skipInputEvent === true && e.type == "input") { |
1299 | + skipInputEvent = false; |
1300 | + return true; |
1301 | + } |
1302 | + |
1303 | + var input = this, $input = $(input); |
1304 | + //paste event for IE8 and lower I guess ;-) |
1305 | + if (e.type == "propertychange" && input._valueGet().length <= getMaskLength()) { |
1306 | + return true; |
1307 | + } |
1308 | + setTimeout(function () { |
1309 | + var pasteValue = $.isFunction(opts.onBeforePaste) ? opts.onBeforePaste.call(input, input._valueGet(), opts) : input._valueGet(); |
1310 | + checkVal(input, true, false, pasteValue.split(''), true); |
1311 | + if (isComplete(getBuffer()) === true) |
1312 | + $input.trigger("complete"); |
1313 | + $input.click(); |
1314 | + }, 0); |
1315 | + } |
1316 | + function mobileInputEvent(e) { |
1317 | + var input = this, $input = $(input); |
1318 | + |
1319 | + //backspace in chrome32 only fires input event - detect & treat |
1320 | + var caretPos = caret(input), |
1321 | + currentValue = input._valueGet(); |
1322 | + |
1323 | + currentValue = currentValue.replace(new RegExp("(" + escapeRegex(getBufferTemplate().join('')) + ")*"), ""); |
1324 | + //correct caretposition for chrome |
1325 | + if (caretPos.begin > currentValue.length) { |
1326 | + caret(input, currentValue.length); |
1327 | + caretPos = caret(input); |
1328 | + } |
1329 | + if ((getBuffer().length - currentValue.length) == 1 && currentValue.charAt(caretPos.begin) != getBuffer()[caretPos.begin] |
1330 | + && currentValue.charAt(caretPos.begin + 1) != getBuffer()[caretPos.begin] |
1331 | + && !isMask(caretPos.begin)) { |
1332 | + e.keyCode = opts.keyCode.BACKSPACE; |
1333 | + keydownEvent.call(input, e); |
1334 | + } else { //nonnumerics don't fire keypress |
1335 | + checkVal(input, true, false, currentValue.split('')); |
1336 | + if (isComplete(getBuffer()) === true) |
1337 | + $input.trigger("complete"); |
1338 | + $input.click(); |
1339 | + } |
1340 | + e.preventDefault(); |
1341 | + } |
1342 | + |
1343 | + function mask(el) { |
1344 | + $el = $(el); |
1345 | + if ($el.is(":input")) { |
1346 | + //store tests & original buffer in the input element - used to get the unmasked value |
1347 | + $el.data('_inputmask', { |
1348 | + 'maskset': maskset, |
1349 | + 'opts': opts, |
1350 | + 'isRTL': false |
1351 | + }); |
1352 | + |
1353 | + //show tooltip |
1354 | + if (opts.showTooltip) { |
1355 | + $el.prop("title", getMaskSet()["mask"]); |
1356 | + } |
1357 | + |
1358 | + patchValueProperty(el); |
1359 | + |
1360 | + if (opts.numericInput) opts.isNumeric = opts.numericInput; |
1361 | + if (el.dir == "rtl" || (opts.numericInput && opts.rightAlignNumerics) || (opts.isNumeric && opts.rightAlignNumerics)) |
1362 | + $el.css("text-align", "right"); |
1363 | + |
1364 | + if (el.dir == "rtl" || opts.numericInput) { |
1365 | + el.dir = "ltr"; |
1366 | + $el.removeAttr("dir"); |
1367 | + var inputData = $el.data('_inputmask'); |
1368 | + inputData['isRTL'] = true; |
1369 | + $el.data('_inputmask', inputData); |
1370 | + isRTL = true; |
1371 | + } |
1372 | + |
1373 | + //unbind all events - to make sure that no other mask will interfere when re-masking |
1374 | + $el.unbind(".inputmask"); |
1375 | + $el.removeClass('focus.inputmask'); |
1376 | + //bind events |
1377 | + $el.closest('form').bind("submit", function () { //trigger change on submit if any |
1378 | + if (valueOnFocus != getBuffer().join('')) { |
1379 | + $el.change(); |
1380 | + } |
1381 | + }).bind('reset', function () { |
1382 | + setTimeout(function () { |
1383 | + $el.trigger("setvalue"); |
1384 | + }, 0); |
1385 | + }); |
1386 | + $el.bind("mouseenter.inputmask", function () { |
1387 | + var $input = $(this), input = this; |
1388 | + if (!$input.hasClass('focus.inputmask') && opts.showMaskOnHover) { |
1389 | + if (input._valueGet() != getBuffer().join('')) { |
1390 | + writeBuffer(input, getBuffer()); |
1391 | + } |
1392 | + } |
1393 | + }).bind("blur.inputmask", function () { |
1394 | + var $input = $(this), input = this, nptValue = input._valueGet(), buffer = getBuffer(); |
1395 | + $input.removeClass('focus.inputmask'); |
1396 | + if (valueOnFocus != getBuffer().join('')) { |
1397 | + $input.change(); |
1398 | + } |
1399 | + if (opts.clearMaskOnLostFocus && nptValue != '') { |
1400 | + if (nptValue == getBufferTemplate().join('')) |
1401 | + input._valueSet(''); |
1402 | + else { //clearout optional tail of the mask |
1403 | + clearOptionalTail(input); |
1404 | + } |
1405 | + } |
1406 | + if (isComplete(buffer) === false) { |
1407 | + $input.trigger("incomplete"); |
1408 | + if (opts.clearIncomplete) { |
1409 | + resetMaskSet(); |
1410 | + if (opts.clearMaskOnLostFocus) |
1411 | + input._valueSet(''); |
1412 | + else { |
1413 | + buffer = getBufferTemplate().slice(); |
1414 | + writeBuffer(input, buffer); |
1415 | + } |
1416 | + } |
1417 | + } |
1418 | + }).bind("focus.inputmask", function () { |
1419 | + var $input = $(this), input = this, nptValue = input._valueGet(); |
1420 | + if (opts.showMaskOnFocus && !$input.hasClass('focus.inputmask') && (!opts.showMaskOnHover || (opts.showMaskOnHover && nptValue == ''))) { |
1421 | + if (input._valueGet() != getBuffer().join('')) { |
1422 | + writeBuffer(input, getBuffer(), seekNext(getLastValidPosition())); |
1423 | + } |
1424 | + } |
1425 | + $input.addClass('focus.inputmask'); |
1426 | + valueOnFocus = getBuffer().join(''); |
1427 | + }).bind("mouseleave.inputmask", function () { |
1428 | + var $input = $(this), input = this; |
1429 | + if (opts.clearMaskOnLostFocus) { |
1430 | + if (!$input.hasClass('focus.inputmask') && input._valueGet() != $input.attr("placeholder")) { |
1431 | + if (input._valueGet() == getBufferTemplate().join('') || input._valueGet() == '') |
1432 | + input._valueSet(''); |
1433 | + else { //clearout optional tail of the mask |
1434 | + clearOptionalTail(input); |
1435 | + } |
1436 | + } |
1437 | + } |
1438 | + }).bind("click.inputmask", function () { |
1439 | + var input = this; |
1440 | + setTimeout(function () { |
1441 | + var selectedCaret = caret(input), buffer = getBuffer(); |
1442 | + if (selectedCaret.begin == selectedCaret.end) { |
1443 | + var clickPosition = isRTL ? TranslatePosition(selectedCaret.begin) : selectedCaret.begin, |
1444 | + lvp = getLastValidPosition(clickPosition), |
1445 | + lastPosition; |
1446 | + if (opts.isNumeric) { |
1447 | + lastPosition = opts.skipRadixDance === false && opts.radixPoint != "" && $.inArray(opts.radixPoint, buffer) != -1 ? |
1448 | + (opts.numericInput ? seekNext($.inArray(opts.radixPoint, buffer)) : $.inArray(opts.radixPoint, buffer)) : |
1449 | + seekNext(lvp); |
1450 | + } else { |
1451 | + lastPosition = seekNext(lvp); |
1452 | + } |
1453 | + if (clickPosition < lastPosition) { |
1454 | + if (isMask(clickPosition)) |
1455 | + caret(input, clickPosition); |
1456 | + else caret(input, seekNext(clickPosition)); |
1457 | + } else |
1458 | + caret(input, lastPosition); |
1459 | + } |
1460 | + }, 0); |
1461 | + }).bind('dblclick.inputmask', function () { |
1462 | + var input = this; |
1463 | + setTimeout(function () { |
1464 | + caret(input, 0, seekNext(getLastValidPosition())); |
1465 | + }, 0); |
1466 | + }).bind(PasteEventType + ".inputmask dragdrop.inputmask drop.inputmask", pasteEvent |
1467 | + ).bind('setvalue.inputmask', function () { |
1468 | + var input = this; |
1469 | + checkVal(input, true); |
1470 | + valueOnFocus = getBuffer().join(''); |
1471 | + if (input._valueGet() == getBufferTemplate().join('')) |
1472 | + input._valueSet(''); |
1473 | + }).bind('complete.inputmask', opts.oncomplete |
1474 | + ).bind('incomplete.inputmask', opts.onincomplete |
1475 | + ).bind('cleared.inputmask', opts.oncleared); |
1476 | + |
1477 | + $el.bind("keydown.inputmask", keydownEvent |
1478 | + ).bind("keypress.inputmask", keypressEvent |
1479 | + ).bind("keyup.inputmask", keyupEvent); |
1480 | + |
1481 | + // as the other inputevents aren't reliable for the moment we only base on the input event |
1482 | + // needs follow-up |
1483 | + if (android || androidfirefox || androidchrome || kindle) { |
1484 | + $el.attr("autocomplete", "off") |
1485 | + .attr("autocorrect", "off") |
1486 | + .attr("autocapitalize", "off") |
1487 | + .attr("spellcheck", false); |
1488 | + |
1489 | + if (androidfirefox || kindle) { |
1490 | + $el.unbind("keydown.inputmask", keydownEvent |
1491 | + ).unbind("keypress.inputmask", keypressEvent |
1492 | + ).unbind("keyup.inputmask", keyupEvent); |
1493 | + if (PasteEventType == "input") { |
1494 | + $el.unbind(PasteEventType + ".inputmask"); |
1495 | + } |
1496 | + $el.bind("input.inputmask", mobileInputEvent); |
1497 | + } |
1498 | + } |
1499 | + |
1500 | + if (msie1x) |
1501 | + $el.bind("input.inputmask", pasteEvent); |
1502 | + |
1503 | + //apply mask |
1504 | + var initialValue = $.isFunction(opts.onBeforeMask) ? opts.onBeforeMask.call(el, el._valueGet(), opts) : el._valueGet(); |
1505 | + checkVal(el, true, false, initialValue.split(''), true); |
1506 | + valueOnFocus = getBuffer().join(''); |
1507 | + // Wrap document.activeElement in a try/catch block since IE9 throw "Unspecified error" if document.activeElement is undefined when we are in an IFrame. |
1508 | + var activeElement; |
1509 | + try { |
1510 | + activeElement = document.activeElement; |
1511 | + } catch (e) { |
1512 | + } |
1513 | + if (activeElement === el) { //position the caret when in focus |
1514 | + $el.addClass('focus.inputmask'); |
1515 | + caret(el, seekNext(getLastValidPosition())); |
1516 | + } else if (opts.clearMaskOnLostFocus) { |
1517 | + if (getBuffer().join('') == getBufferTemplate().join('')) { |
1518 | + el._valueSet(''); |
1519 | + } else { |
1520 | + clearOptionalTail(el); |
1521 | + } |
1522 | + } else { |
1523 | + writeBuffer(el, getBuffer()); |
1524 | + } |
1525 | + |
1526 | + installEventRuler(el); |
1527 | + } |
1528 | + } |
1529 | + |
1530 | + //action object |
1531 | + if (actionObj != undefined) { |
1532 | + switch (actionObj["action"]) { |
1533 | + case "isComplete": |
1534 | + $el = $(actionObj["el"]); |
1535 | + return isComplete(actionObj["buffer"]); |
1536 | + case "unmaskedvalue": |
1537 | + $el = actionObj["$input"]; |
1538 | + isRTL = actionObj["$input"].data('_inputmask')['isRTL']; |
1539 | + return unmaskedvalue(actionObj["$input"], actionObj["skipDatepickerCheck"]); |
1540 | + case "mask": |
1541 | + mask(actionObj["el"]); |
1542 | + break; |
1543 | + case "format": |
1544 | + $el = $({}); |
1545 | + $el.data('_inputmask', { |
1546 | + 'maskset': maskset, |
1547 | + 'opts': opts, |
1548 | + 'isRTL': opts.numericInput |
1549 | + }); |
1550 | + if (opts.numericInput) { |
1551 | + opts.isNumeric = opts.numericInput; |
1552 | + isRTL = true; |
1553 | + } |
1554 | + var valueBuffer = actionObj["value"].split(''); |
1555 | + checkVal($el, false, false, isRTL ? valueBuffer.reverse() : valueBuffer, true); |
1556 | + return isRTL ? getBuffer().reverse().join('') : getBuffer().join(''); |
1557 | + case "isValid": |
1558 | + $el = $({}); |
1559 | + $el.data('_inputmask', { |
1560 | + 'maskset': maskset, |
1561 | + 'opts': opts, |
1562 | + 'isRTL': opts.numericInput |
1563 | + }); |
1564 | + if (opts.numericInput) { |
1565 | + opts.isNumeric = opts.numericInput; |
1566 | + isRTL = true; |
1567 | + } |
1568 | + var valueBuffer = actionObj["value"].split(''); |
1569 | + checkVal($el, false, true, isRTL ? valueBuffer.reverse() : valueBuffer); |
1570 | + return isComplete(getBuffer()); |
1571 | + } |
1572 | + } |
1573 | + }; |
1574 | + |
1575 | + function multiMaskScope(el, masksets, opts) { |
1576 | + function PatchValhookMulti(type) { |
1577 | + if ($.valHooks[type] == undefined || $.valHooks[type].inputmaskmultipatch != true) { |
1578 | + var valueGet = $.valHooks[type] && $.valHooks[type].get ? $.valHooks[type].get : function (elem) { return elem.value; }; |
1579 | + var valueSet = $.valHooks[type] && $.valHooks[type].set ? $.valHooks[type].set : function (elem, value) { |
1580 | + elem.value = value; |
1581 | + return elem; |
1582 | + }; |
1583 | + |
1584 | + $.valHooks[type] = { |
1585 | + get: function (elem) { |
1586 | + var $elem = $(elem); |
1587 | + if ($elem.data('_inputmask-multi')) { |
1588 | + var data = $elem.data('_inputmask-multi'); |
1589 | + return valueGet(data["elmasks"][data["activeMasksetIndex"]]); |
1590 | + } else return valueGet(elem); |
1591 | + }, |
1592 | + set: function (elem, value) { |
1593 | + var $elem = $(elem); |
1594 | + var result = valueSet(elem, value); |
1595 | + if ($elem.data('_inputmask-multi')) $elem.triggerHandler('setvalue'); |
1596 | + return result; |
1597 | + }, |
1598 | + inputmaskmultipatch: true |
1599 | + }; |
1600 | + } |
1601 | + } |
1602 | + function mcaret(input, begin, end) { |
1603 | + var npt = input.jquery && input.length > 0 ? input[0] : input, range; |
1604 | + if (typeof begin == 'number') { |
1605 | + begin = TranslatePosition(begin); |
1606 | + end = TranslatePosition(end); |
1607 | + end = (typeof end == 'number') ? end : begin; |
1608 | + |
1609 | + //store caret for multi scope |
1610 | + if (npt != el) { |
1611 | + var data = $(npt).data('_inputmask') || {}; |
1612 | + data["caret"] = { "begin": begin, "end": end }; |
1613 | + $(npt).data('_inputmask', data); |
1614 | + } |
1615 | + if (!$(npt).is(':visible')) { |
1616 | + return; |
1617 | + } |
1618 | + |
1619 | + npt.scrollLeft = npt.scrollWidth; |
1620 | + if (opts.insertMode == false && begin == end) end++; //set visualization for insert/overwrite mode |
1621 | + if (npt.setSelectionRange) { |
1622 | + npt.selectionStart = begin; |
1623 | + npt.selectionEnd = end; |
1624 | + |
1625 | + } else if (npt.createTextRange) { |
1626 | + range = npt.createTextRange(); |
1627 | + range.collapse(true); |
1628 | + range.moveEnd('character', end); |
1629 | + range.moveStart('character', begin); |
1630 | + range.select(); |
1631 | + } |
1632 | + } else { |
1633 | + if (!$(npt).is(':visible') && $(npt).data('_inputmask')["caret"] != undefined) { |
1634 | + var data = $(npt).data('_inputmask'); |
1635 | + begin = data["caret"]["begin"]; |
1636 | + end = data["caret"]["end"]; |
1637 | + } else if (npt.setSelectionRange) { |
1638 | + begin = npt.selectionStart; |
1639 | + end = npt.selectionEnd; |
1640 | + } else if (document.selection && document.selection.createRange) { |
1641 | + range = document.selection.createRange(); |
1642 | + begin = 0 - range.duplicate().moveStart('character', -100000); |
1643 | + end = begin + range.text.length; |
1644 | + } |
1645 | + begin = TranslatePosition(begin); |
1646 | + end = TranslatePosition(end); |
1647 | + return { "begin": begin, "end": end }; |
1648 | + } |
1649 | + } |
1650 | + function TranslatePosition(pos) { |
1651 | + if (isRTL && typeof pos == 'number' && (!opts.greedy || opts.placeholder != "")) { |
1652 | + var bffrLght = el.value.length; |
1653 | + pos = bffrLght - pos; |
1654 | + } |
1655 | + return pos; |
1656 | + } |
1657 | + function determineActiveMask(eventType, elmasks) { |
1658 | + if (eventType != "multiMaskScope") { |
1659 | + var lpc = -1, cp = -1, lvp = -1;; |
1660 | + $.each(elmasks, function (ndx, lmsk) { |
1661 | + var data = $(lmsk).data('_inputmask'); |
1662 | + var maskset = data["maskset"]; |
1663 | + var lastValidPosition = -1, validPositionCount = 0, caretPos = mcaret(lmsk).begin; |
1664 | + for (var posNdx in maskset["validPositions"]) { |
1665 | + var psNdx = parseInt(posNdx); |
1666 | + if (psNdx > lastValidPosition) lastValidPosition = psNdx; |
1667 | + validPositionCount++; |
1668 | + } |
1669 | + if (validPositionCount > lpc |
1670 | + || (validPositionCount == lpc && cp > caretPos && lvp > lastValidPosition) |
1671 | + || (validPositionCount == lpc && cp == caretPos && lvp < lastValidPosition) |
1672 | + ) { |
1673 | + //console.log("lvp " + lastValidPosition + " vpc " + validPositionCount + " caret " + caretPos + " ams " + ndx); |
1674 | + lpc = validPositionCount; |
1675 | + cp = caretPos; |
1676 | + activeMasksetIndex = ndx; |
1677 | + lvp = lastValidPosition; |
1678 | + } |
1679 | + }); |
1680 | + |
1681 | + if ($.isFunction(opts.determineActiveMasksetIndex)) activeMasksetIndex = opts.determineActiveMasksetIndex.call($el, eventType, elmasks); |
1682 | + |
1683 | + var data = $el.data('_inputmask-multi') || { "activeMasksetIndex": 0, "elmasks": elmasks }; |
1684 | + data["activeMasksetIndex"] = activeMasksetIndex; |
1685 | + $el.data('_inputmask-multi', data); |
1686 | + } |
1687 | + |
1688 | + if (["focus"].indexOf(eventType) == -1 && el.value != elmasks[activeMasksetIndex]._valueGet()) { |
1689 | + var value = $(elmasks[activeMasksetIndex]).val() == "" ? elmasks[activeMasksetIndex]._valueGet() : $(elmasks[activeMasksetIndex]).val(); |
1690 | + el.value = value; |
1691 | + } |
1692 | + if (["blur", "focus"].indexOf(eventType) == -1) { |
1693 | + if ($(elmasks[activeMasksetIndex]).hasClass("focus.inputmask")) { |
1694 | + var activeCaret = mcaret(elmasks[activeMasksetIndex]); |
1695 | + mcaret(el, activeCaret.begin, activeCaret.end); |
1696 | + } |
1697 | + } |
1698 | + } |
1699 | + opts.multi = true; |
1700 | + var $el = $(el), isRTL = el.dir == "rtl" || opts.numericInput; |
1701 | + var activeMasksetIndex = 0, |
1702 | + elmasks = $.map(masksets, function (msk, ndx) { |
1703 | + var elMaskStr = '<input type="text" '; |
1704 | + if ($el.attr("value")) elMaskStr += 'value="' + $el.attr("value") + '" '; |
1705 | + if ($el.attr("dir")) elMaskStr += 'dir="' + $el.attr("dir") + '" '; |
1706 | + elMaskStr += '/>'; |
1707 | + var elmask = $(elMaskStr)[0]; |
1708 | + maskScope($.extend(true, {}, msk), opts, { "action": "mask", "el": elmask }); |
1709 | + return elmask; |
1710 | + }); |
1711 | + |
1712 | + $el.data('_inputmask-multi', { "activeMasksetIndex": 0, "elmasks": elmasks }); |
1713 | + if (el.dir == "rtl" || (opts.numericInput && opts.rightAlignNumerics) || (opts.isNumeric && opts.rightAlignNumerics)) |
1714 | + $el.css("text-align", "right"); |
1715 | + el.dir = "ltr"; |
1716 | + $el.removeAttr("dir"); |
1717 | + if ($el.attr("value") != "") { |
1718 | + determineActiveMask("init", elmasks); |
1719 | + } |
1720 | + |
1721 | + $el.bind("mouseenter blur focus mouseleave click dblclick keydown keypress keypress", function (e) { |
1722 | + var caretPos = mcaret(el), k, goDetermine = true; |
1723 | + if (e.type == "keydown") { |
1724 | + k = e.keyCode; |
1725 | + if (k == opts.keyCode.DOWN && activeMasksetIndex < elmasks.length - 1) { |
1726 | + activeMasksetIndex++; |
1727 | + determineActiveMask("multiMaskScope", elmasks); |
1728 | + return false; |
1729 | + } else if (k == opts.keyCode.UP && activeMasksetIndex > 0) { |
1730 | + activeMasksetIndex--; |
1731 | + determineActiveMask("multiMaskScope", elmasks); |
1732 | + return false; |
1733 | + } if (e.ctrlKey || e.shiftKey || e.altKey) { |
1734 | + return true; |
1735 | + } |
1736 | + } else if (e.type == "keypress" && (e.ctrlKey || e.shiftKey || e.altKey)) { |
1737 | + return true; |
1738 | + } |
1739 | + $.each(elmasks, function (ndx, lmnt) { |
1740 | + if (e.type == "keydown") { |
1741 | + k = e.keyCode; |
1742 | + |
1743 | + if (k == opts.keyCode.BACKSPACE && lmnt._valueGet().length < caretPos.begin) { |
1744 | + return; |
1745 | + } else if (k == opts.keyCode.TAB) { |
1746 | + goDetermine = false; |
1747 | + } else if (k == opts.keyCode.RIGHT) { |
1748 | + mcaret(lmnt, caretPos.begin + 1, caretPos.end + 1); |
1749 | + goDetermine = false; |
1750 | + return; |
1751 | + } else if (k == opts.keyCode.LEFT) { |
1752 | + mcaret(lmnt, caretPos.begin - 1, caretPos.end - 1); |
1753 | + goDetermine = false; |
1754 | + return; |
1755 | + } |
1756 | + } |
1757 | + if (["click"].indexOf(e.type) != -1) { |
1758 | + mcaret(lmnt, TranslatePosition(caretPos.begin), TranslatePosition(caretPos.end)); |
1759 | + if (caretPos.begin != caretPos.end) { |
1760 | + goDetermine = false; |
1761 | + return; |
1762 | + } |
1763 | + } |
1764 | + |
1765 | + if (["keydown"].indexOf(e.type) != -1 && caretPos.begin != caretPos.end) { |
1766 | + mcaret(lmnt, caretPos.begin, caretPos.end); |
1767 | + } |
1768 | + |
1769 | + $(lmnt).triggerHandler(e); |
1770 | + }); |
1771 | + if (goDetermine) { |
1772 | + setTimeout(function () { |
1773 | + determineActiveMask(e.type, elmasks); |
1774 | + }, 0); |
1775 | + } |
1776 | + }); |
1777 | + $el.bind(PasteEventType + " dragdrop drop setvalue", function (e) { |
1778 | + var caretPos = mcaret(el); |
1779 | + setTimeout(function () { |
1780 | + $.each(elmasks, function (ndx, lmnt) { |
1781 | + lmnt._valueSet(el.value); |
1782 | + $(lmnt).triggerHandler(e); |
1783 | + }); |
1784 | + setTimeout(function () { |
1785 | + determineActiveMask(e.type, elmasks); |
1786 | + }, 0); |
1787 | + }, 0); |
1788 | + }); |
1789 | + PatchValhookMulti(el.type); |
1790 | + }; |
1791 | + |
1792 | + $.inputmask = { |
1793 | + //options default |
1794 | + defaults: { |
1795 | + placeholder: "_", |
1796 | + optionalmarker: { start: "[", end: "]" }, |
1797 | + quantifiermarker: { start: "{", end: "}" }, |
1798 | + groupmarker: { start: "(", end: ")" }, |
1799 | + alternatormarker: "|", |
1800 | + escapeChar: "\\", |
1801 | + mask: null, |
1802 | + oncomplete: $.noop, //executes when the mask is complete |
1803 | + onincomplete: $.noop, //executes when the mask is incomplete and focus is lost |
1804 | + oncleared: $.noop, //executes when the mask is cleared |
1805 | + repeat: 0, //repetitions of the mask: * ~ forever, otherwise specify an integer |
1806 | + greedy: true, //true: allocated buffer for the mask and repetitions - false: allocate only if needed |
1807 | + autoUnmask: false, //automatically unmask when retrieving the value with $.fn.val or value if the browser supports __lookupGetter__ or getOwnPropertyDescriptor |
1808 | + clearMaskOnLostFocus: true, |
1809 | + insertMode: true, //insert the input or overwrite the input |
1810 | + clearIncomplete: false, //clear the incomplete input on blur |
1811 | + aliases: {}, //aliases definitions => see jquery.inputmask.extensions.js |
1812 | + onKeyUp: $.noop, //override to implement autocomplete on certain keys for example |
1813 | + onKeyDown: $.noop, //override to implement autocomplete on certain keys for example |
1814 | + onBeforeMask: undefined, //executes before masking the initial value to allow preprocessing of the initial value. args => initialValue, opts => return processedValue |
1815 | + onBeforePaste: undefined, //executes before masking the pasted value to allow preprocessing of the pasted value. args => pastedValue, opts => return processedValue |
1816 | + onUnMask: undefined, //executes after unmasking to allow postprocessing of the unmaskedvalue. args => maskedValue, unmaskedValue, opts |
1817 | + showMaskOnFocus: true, //show the mask-placeholder when the input has focus |
1818 | + showMaskOnHover: true, //show the mask-placeholder when hovering the empty input |
1819 | + onKeyValidation: $.noop, //executes on every key-press with the result of isValid. Params: result, opts |
1820 | + skipOptionalPartCharacter: " ", //a character which can be used to skip an optional part of a mask |
1821 | + showTooltip: false, //show the activemask as tooltip |
1822 | + numericInput: false, //numericInput input direction style (input shifts to the left while holding the caret position) |
1823 | + //numeric basic properties |
1824 | + isNumeric: false, //enable numeric features |
1825 | + radixPoint: "", //".", // | "," |
1826 | + skipRadixDance: false, //disable radixpoint caret positioning |
1827 | + rightAlignNumerics: true, //align numerics to the right |
1828 | + //numeric basic properties |
1829 | + definitions: { |
1830 | + '9': { |
1831 | + validator: "[0-9]", |
1832 | + cardinality: 1, |
1833 | + definitionSymbol: "*" |
1834 | + }, |
1835 | + 'a': { |
1836 | + validator: "[A-Za-z\u0410-\u044F\u0401\u0451]", |
1837 | + cardinality: 1, |
1838 | + definitionSymbol: "*" |
1839 | + }, |
1840 | + '*': { |
1841 | + validator: "[A-Za-z\u0410-\u044F\u0401\u04510-9]", |
1842 | + cardinality: 1 |
1843 | + } |
1844 | + }, |
1845 | + keyCode: { |
1846 | + 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, |
1847 | + 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 |
1848 | + }, |
1849 | + //specify keycodes which should not be considered in the keypress event, otherwise the preventDefault will stop their default behavior especially in FF |
1850 | + 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], |
1851 | + isComplete: undefined, //override for isComplete - args => buffer, opts - return true || false |
1852 | + //multi-masks |
1853 | + multi: false, //do not alter - internal use |
1854 | + nojumps: false, //do not jump over fixed parts in the mask |
1855 | + nojumpsThreshold: 0, //start nojumps as of |
1856 | + determineActiveMasksetIndex: undefined //override determineActiveMasksetIndex - args => eventType, elmasks - return int |
1857 | + }, |
1858 | + masksCache: {}, |
1859 | + escapeRegex: function (str) { |
1860 | + var specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\']; |
1861 | + return str.replace(new RegExp('(\\' + specials.join('|\\') + ')', 'gim'), '\\$1'); |
1862 | + }, |
1863 | + format: function (value, options) { |
1864 | + var opts = $.extend(true, {}, $.inputmask.defaults, options); |
1865 | + resolveAlias(opts.alias, options, opts); |
1866 | + return maskScope(generateMaskSet(opts), opts, { "action": "format", "value": value }); |
1867 | + }, |
1868 | + isValid: function (value, options) { |
1869 | + var opts = $.extend(true, {}, $.inputmask.defaults, options); |
1870 | + resolveAlias(opts.alias, options, opts); |
1871 | + return maskScope(generateMaskSet(opts), opts, { "action": "isValid", "value": value }); |
1872 | + } |
1873 | + }; |
1874 | + $.fn.inputmask = function (fn, options) { |
1875 | + function importAttributeOptions(npt, opts) { |
1876 | + var $npt = $(npt); |
1877 | + for (var option in opts) { |
1878 | + var optionData = $npt.data("inputmask-" + option.toLowerCase()); |
1879 | + if (optionData != undefined) |
1880 | + opts[option] = optionData; |
1881 | + } |
1882 | + return opts; |
1883 | + } |
1884 | + var opts = $.extend(true, {}, $.inputmask.defaults, options), |
1885 | + maskset; |
1886 | + |
1887 | + if (typeof fn === "string") { |
1888 | + switch (fn) { |
1889 | + case "mask": |
1890 | + //resolve possible aliases given by options |
1891 | + resolveAlias(opts.alias, options, opts); |
1892 | + maskset = generateMaskSet(opts); |
1893 | + if (maskset.length == 0) { return this; } |
1894 | + |
1895 | + return this.each(function () { |
1896 | + if ($.isArray(maskset)) { |
1897 | + multiMaskScope(this, maskset, importAttributeOptions(this, opts)); |
1898 | + } else |
1899 | + maskScope($.extend(true, {}, maskset), importAttributeOptions(this, opts), { "action": "mask", "el": this }); |
1900 | + }); |
1901 | + case "unmaskedvalue": |
1902 | + var $input = $(this), input = this; |
1903 | + if ($input.data('_inputmask')) { |
1904 | + maskset = $input.data('_inputmask')['maskset']; |
1905 | + opts = $input.data('_inputmask')['opts']; |
1906 | + return maskScope(maskset, opts, { "action": "unmaskedvalue", "$input": $input }); |
1907 | + } else return $input.val(); |
1908 | + case "remove": |
1909 | + return this.each(function () { |
1910 | + var $input = $(this), input = this; |
1911 | + if ($input.data('_inputmask')) { |
1912 | + maskset = $input.data('_inputmask')['maskset']; |
1913 | + opts = $input.data('_inputmask')['opts']; |
1914 | + //writeout the unmaskedvalue |
1915 | + input._valueSet(maskScope(maskset, opts, { "action": "unmaskedvalue", "$input": $input, "skipDatepickerCheck": true })); |
1916 | + //clear data |
1917 | + $input.removeData('_inputmask'); |
1918 | + //unbind all events |
1919 | + $input.unbind(".inputmask"); |
1920 | + $input.removeClass('focus.inputmask'); |
1921 | + //restore the value property |
1922 | + var valueProperty; |
1923 | + if (Object.getOwnPropertyDescriptor) |
1924 | + valueProperty = Object.getOwnPropertyDescriptor(input, "value"); |
1925 | + if (valueProperty && valueProperty.get) { |
1926 | + if (input._valueGet) { |
1927 | + Object.defineProperty(input, "value", { |
1928 | + get: input._valueGet, |
1929 | + set: input._valueSet |
1930 | + }); |
1931 | + } |
1932 | + } else if (document.__lookupGetter__ && input.__lookupGetter__("value")) { |
1933 | + if (input._valueGet) { |
1934 | + input.__defineGetter__("value", input._valueGet); |
1935 | + input.__defineSetter__("value", input._valueSet); |
1936 | + } |
1937 | + } |
1938 | + try { //try catch needed for IE7 as it does not supports deleting fns |
1939 | + delete input._valueGet; |
1940 | + delete input._valueSet; |
1941 | + } catch (e) { |
1942 | + input._valueGet = undefined; |
1943 | + input._valueSet = undefined; |
1944 | + |
1945 | + } |
1946 | + } |
1947 | + }); |
1948 | + break; |
1949 | + case "getemptymask": //return the default (empty) mask value, usefull for setting the default value in validation |
1950 | + if (this.data('_inputmask')) { |
1951 | + maskset = this.data('_inputmask')['maskset']; |
1952 | + return maskset['_buffer'].join(''); |
1953 | + } |
1954 | + else return ""; |
1955 | + case "hasMaskedValue": //check wheter the returned value is masked or not; currently only works reliable when using jquery.val fn to retrieve the value |
1956 | + return this.data('_inputmask') ? !this.data('_inputmask')['opts'].autoUnmask : false; |
1957 | + case "isComplete": |
1958 | + if (this.data('_inputmask')) { |
1959 | + maskset = this.data('_inputmask')['maskset']; |
1960 | + opts = this.data('_inputmask')['opts']; |
1961 | + return maskScope(maskset, opts, { "action": "isComplete", "buffer": this[0]._valueGet().split(''), "el": this }); |
1962 | + } else return true; |
1963 | + case "getmetadata": //return mask metadata if exists |
1964 | + if (this.data('_inputmask')) { |
1965 | + maskset = this.data('_inputmask')['maskset']; |
1966 | + return maskset['metadata']; |
1967 | + } |
1968 | + else return undefined; |
1969 | + default: |
1970 | + //check if the fn is an alias |
1971 | + if (!resolveAlias(fn, options, opts)) { |
1972 | + //maybe fn is a mask so we try |
1973 | + //set mask |
1974 | + opts.mask = fn; |
1975 | + } |
1976 | + maskset = generateMaskSet(opts); |
1977 | + if (maskset == undefined) { return this; } |
1978 | + return this.each(function () { |
1979 | + if ($.isArray(maskset)) { |
1980 | + multiMaskScope(this, maskset, importAttributeOptions(this, opts)); |
1981 | + } else |
1982 | + maskScope($.extend(true, {}, maskset), importAttributeOptions(this, opts), { "action": "mask", "el": this }); |
1983 | + }); |
1984 | + |
1985 | + break; |
1986 | + } |
1987 | + } else if (typeof fn == "object") { |
1988 | + opts = $.extend(true, {}, $.inputmask.defaults, fn); |
1989 | + |
1990 | + resolveAlias(opts.alias, fn, opts); //resolve aliases |
1991 | + maskset = generateMaskSet(opts); |
1992 | + if (maskset == undefined) { return this; } |
1993 | + return this.each(function () { |
1994 | + if ($.isArray(maskset)) { |
1995 | + multiMaskScope(this, maskset, importAttributeOptions(this, opts)); |
1996 | + } else |
1997 | + maskScope($.extend(true, {}, maskset), importAttributeOptions(this, opts), { "action": "mask", "el": this }); |
1998 | + }); |
1999 | + } else if (fn == undefined) { |
2000 | + //look for data-inputmask atribute - the attribute should only contain optipns |
2001 | + return this.each(function () { |
2002 | + var attrOptions = $(this).attr("data-inputmask"); |
2003 | + if (attrOptions && attrOptions != "") { |
2004 | + try { |
2005 | + attrOptions = attrOptions.replace(new RegExp("'", "g"), '"'); |
2006 | + var dataoptions = $.parseJSON("{" + attrOptions + "}"); |
2007 | + $.extend(true, dataoptions, options); |
2008 | + opts = $.extend(true, {}, $.inputmask.defaults, dataoptions); |
2009 | + resolveAlias(opts.alias, dataoptions, opts); |
2010 | + opts.alias = undefined; |
2011 | + $(this).inputmask(opts); |
2012 | + } catch (ex) { } //need a more relax parseJSON |
2013 | + } |
2014 | + }); |
2015 | + } |
2016 | + }; |
2017 | + } |
2018 | +})(jQuery); |
2019 | |
2020 | === added file 'web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.numeric.extensions.js' |
2021 | --- web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.numeric.extensions.js 1970-01-01 00:00:00 +0000 |
2022 | +++ web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.numeric.extensions.js 2014-05-20 21:16:10 +0000 |
2023 | @@ -0,0 +1,263 @@ |
2024 | +/* |
2025 | +Input Mask plugin extensions |
2026 | +http://github.com/RobinHerbots/jquery.inputmask |
2027 | +Copyright (c) 2010 - 2014 Robin Herbots |
2028 | +Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php) |
2029 | +Version: 0.0.0 |
2030 | + |
2031 | +Optional extensions on the jquery.inputmask base |
2032 | +*/ |
2033 | +(function ($) { |
2034 | + //number aliases |
2035 | + $.extend($.inputmask.defaults.aliases, { |
2036 | + 'numeric': { |
2037 | + mask: function (opts) { |
2038 | + var mask = opts.prefix; |
2039 | + mask += "[+]~{1," + opts.integerDigits + "}"; |
2040 | + mask += "[" + opts.radixPoint + "~{" + opts.digits + "}]"; |
2041 | + mask += opts.suffix; |
2042 | + return mask; |
2043 | + }, |
2044 | + placeholder: "", |
2045 | + greedy: false, |
2046 | + numericInput: false, |
2047 | + isNumeric: false, |
2048 | + digits: "2", //number of fractionalDigits |
2049 | + groupSeparator: "",//",", // | "." |
2050 | + radixPoint: ".", |
2051 | + groupSize: 3, |
2052 | + autoGroup: false, |
2053 | + allowPlus: true, |
2054 | + allowMinus: true, |
2055 | + integerDigits: "20", //number of integerDigits |
2056 | + defaultValue: "", |
2057 | + prefix: "", |
2058 | + suffix: "", |
2059 | + postFormat: function (buffer, pos, reformatOnly, opts) { |
2060 | + if (opts.groupSeparator == "") return pos; |
2061 | + var cbuf = buffer.slice(), |
2062 | + radixPos = $.inArray(opts.radixPoint, buffer); |
2063 | + if (!reformatOnly) { |
2064 | + cbuf.splice(pos, 0, "?"); //set position indicator |
2065 | + } |
2066 | + var bufVal = cbuf.join(''); |
2067 | + if (opts.autoGroup || (reformatOnly && bufVal.indexOf(opts.groupSeparator) != -1)) { |
2068 | + var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, opts.groupSeparator); |
2069 | + bufVal = bufVal.replace(new RegExp(escapedGroupSeparator, "g"), ''); |
2070 | + var radixSplit = bufVal.split(opts.radixPoint); |
2071 | + bufVal = radixSplit[0]; |
2072 | + var reg = new RegExp('([-\+]?[\\d\?]+)([\\d\?]{' + opts.groupSize + '})'); |
2073 | + while (reg.test(bufVal)) { |
2074 | + bufVal = bufVal.replace(reg, '$1' + opts.groupSeparator + '$2'); |
2075 | + bufVal = bufVal.replace(opts.groupSeparator + opts.groupSeparator, opts.groupSeparator); |
2076 | + } |
2077 | + if (radixSplit.length > 1) |
2078 | + bufVal += opts.radixPoint + radixSplit[1]; |
2079 | + } |
2080 | + buffer.length = bufVal.length; //align the length |
2081 | + for (var i = 0, l = bufVal.length; i < l; i++) { |
2082 | + buffer[i] = bufVal.charAt(i); |
2083 | + } |
2084 | + var newPos = $.inArray("?", buffer); |
2085 | + if (!reformatOnly) buffer.splice(newPos, 1); |
2086 | + |
2087 | + return reformatOnly ? pos : newPos; |
2088 | + }, |
2089 | + regex: { |
2090 | + integerPart: function (opts) { return new RegExp('[-\+]?\\d+'); } |
2091 | + }, |
2092 | + definitions: { |
2093 | + '~': { |
2094 | + validator: function (chrs, buffer, pos, strict, opts) { |
2095 | + if (!strict && chrs === "-") { |
2096 | + var matchRslt = buffer.join('').match(opts.regex.integerPart(opts)); |
2097 | + |
2098 | + if (matchRslt.length > 0) { |
2099 | + if (buffer[matchRslt.index] == "+") { |
2100 | + buffer.splice(matchRslt.index, 1); |
2101 | + return { "pos": matchRslt.index, "c": "-", "refreshFromBuffer": true, "caret": pos }; |
2102 | + } else if (buffer[matchRslt.index] == "-") { |
2103 | + buffer.splice(matchRslt.index, 1); |
2104 | + return { "refreshFromBuffer": true, "caret": pos - 1 }; |
2105 | + } else { |
2106 | + return { "pos": matchRslt.index, "c": "-", "caret": pos + 1 }; |
2107 | + } |
2108 | + } |
2109 | + } |
2110 | + var isValid = new RegExp("[0-9]").test(chrs); |
2111 | + return isValid; |
2112 | + }, |
2113 | + cardinality: 1, |
2114 | + prevalidator: null |
2115 | + }, |
2116 | + '+': { |
2117 | + validator: function (chrs, buffer, pos, strict, opts) { |
2118 | + var signed = "["; |
2119 | + if (opts.allowMinus === true) signed += "-"; |
2120 | + if (opts.allowPlus === true) signed += "\+"; |
2121 | + signed += "]"; |
2122 | + var isValid = new RegExp(signed).test(chrs); |
2123 | + return isValid; |
2124 | + }, |
2125 | + cardinality: 1, |
2126 | + prevalidator: null |
2127 | + } |
2128 | + }, |
2129 | + insertMode: true, |
2130 | + autoUnmask: false |
2131 | + }, |
2132 | + 'decimal': { |
2133 | + mask: "~", |
2134 | + placeholder: "", |
2135 | + repeat: "*", |
2136 | + greedy: false, |
2137 | + numericInput: false, |
2138 | + isNumeric: true, |
2139 | + digits: "*", //number of fractionalDigits |
2140 | + groupSeparator: "",//",", // | "." |
2141 | + radixPoint: ".", |
2142 | + groupSize: 3, |
2143 | + autoGroup: false, |
2144 | + allowPlus: true, |
2145 | + allowMinus: true, |
2146 | + //todo |
2147 | + integerDigits: "*", //number of integerDigits |
2148 | + defaultValue: "", |
2149 | + prefix: "", |
2150 | + suffix: "", |
2151 | + postFormat: function (buffer, pos, reformatOnly, opts) { |
2152 | + if (opts.groupSeparator == "") return pos; |
2153 | + var cbuf = buffer.slice(), |
2154 | + radixPos = $.inArray(opts.radixPoint, buffer); |
2155 | + if (!reformatOnly) { |
2156 | + cbuf.splice(pos, 0, "?"); //set position indicator |
2157 | + } |
2158 | + var bufVal = cbuf.join(''); |
2159 | + if (opts.autoGroup || (reformatOnly && bufVal.indexOf(opts.groupSeparator) != -1)) { |
2160 | + var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, opts.groupSeparator); |
2161 | + bufVal = bufVal.replace(new RegExp(escapedGroupSeparator, "g"), ''); |
2162 | + var radixSplit = bufVal.split(opts.radixPoint); |
2163 | + bufVal = radixSplit[0]; |
2164 | + var reg = new RegExp('([-\+]?[\\d\?]+)([\\d\?]{' + opts.groupSize + '})'); |
2165 | + while (reg.test(bufVal)) { |
2166 | + bufVal = bufVal.replace(reg, '$1' + opts.groupSeparator + '$2'); |
2167 | + bufVal = bufVal.replace(opts.groupSeparator + opts.groupSeparator, opts.groupSeparator); |
2168 | + } |
2169 | + if (radixSplit.length > 1) |
2170 | + bufVal += opts.radixPoint + radixSplit[1]; |
2171 | + } |
2172 | + buffer.length = bufVal.length; //align the length |
2173 | + for (var i = 0, l = bufVal.length; i < l; i++) { |
2174 | + buffer[i] = bufVal.charAt(i); |
2175 | + } |
2176 | + var newPos = $.inArray("?", buffer); |
2177 | + if (!reformatOnly) buffer.splice(newPos, 1); |
2178 | + |
2179 | + return reformatOnly ? pos : newPos; |
2180 | + }, |
2181 | + regex: { |
2182 | + number: function (opts) { |
2183 | + var escapedRadixPoint = $.inputmask.escapeRegex.call(this, opts.radixPoint); |
2184 | + var digitExpression = isNaN(opts.digits) ? opts.digits : '{0,' + opts.digits + '}'; |
2185 | + var integerExpression = isNaN(opts.integerDigits) ? opts.integerDigits : '{1,' + opts.integerDigits + '}'; |
2186 | + var signedExpression = opts.allowPlus || opts.allowMinus ? "[" + (opts.allowPlus ? "\+" : "") + (opts.allowMinus ? "-" : "") + "]?" : ""; |
2187 | + |
2188 | + var currentRegExp = "^" + signedExpression + "\\d" + integerExpression + "(" + escapedRadixPoint + "\\d" + digitExpression + ")?$"; |
2189 | + return new RegExp(currentRegExp); |
2190 | + |
2191 | + } |
2192 | + }, |
2193 | + onKeyDown: function (e, buffer, opts) { |
2194 | + var $input = $(this), input = this; |
2195 | + if (e.keyCode == opts.keyCode.TAB) { |
2196 | + var radixPosition = $.inArray(opts.radixPoint, buffer); |
2197 | + if (radixPosition != -1) { |
2198 | + var masksets = $input.data('_inputmask')['masksets']; |
2199 | + var activeMasksetIndex = $input.data('_inputmask')['activeMasksetIndex']; |
2200 | + for (var i = 1; i <= opts.digits && i < opts.getMaskLength(masksets[activeMasksetIndex]["_buffer"], opts.greedy, opts.repeat, buffer, opts) ; i++) { |
2201 | + if (buffer[radixPosition + i] == undefined || buffer[radixPosition + i] == "") buffer[radixPosition + i] = "0"; |
2202 | + } |
2203 | + return { "refreshFromBuffer": true }; |
2204 | + } |
2205 | + } else if (e.keyCode == opts.keyCode.DELETE || e.keyCode == opts.keyCode.BACKSPACE) { |
2206 | + opts.postFormat(buffer, 0, true, opts); |
2207 | + input._valueSet(buffer.join('')); |
2208 | + return { "refreshFromBuffer": true }; |
2209 | + } |
2210 | + }, |
2211 | + definitions: { |
2212 | + '~': { //real number |
2213 | + validator: function (chrs, buffer, pos, strict, opts) { |
2214 | + var iopts = $.extend({}, opts, { digits: strict ? "*" : opts.digits }); |
2215 | + if (chrs == "") return false; |
2216 | + if (!strict && pos <= 1 && buffer[0] === '0' && new RegExp("[\\d-]").test(chrs) && buffer.join('').length == 1) { //handle first char |
2217 | + buffer[0] = ""; |
2218 | + return { "pos": 0 }; |
2219 | + } |
2220 | + |
2221 | + var cbuf = strict ? buffer.slice(0, pos) : buffer.slice(); |
2222 | + |
2223 | + cbuf.splice(pos, 0, chrs); |
2224 | + var bufferStr = cbuf.join(''); |
2225 | + |
2226 | + //strip groupseparator |
2227 | + var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, opts.groupSeparator); |
2228 | + bufferStr = bufferStr.replace(new RegExp(escapedGroupSeparator, "g"), ''); |
2229 | + if (strict && bufferStr.lastIndexOf(opts.radixPoint) == bufferStr.length - 1) { |
2230 | + var escapedRadixPoint = $.inputmask.escapeRegex.call(this, opts.radixPoint); |
2231 | + bufferStr = bufferStr.replace(new RegExp(escapedRadixPoint, "g"), ''); |
2232 | + } |
2233 | + if (!strict && bufferStr == "") return false; |
2234 | + |
2235 | + var isValid = opts.regex.number(iopts).test(bufferStr); |
2236 | + if (!isValid) { |
2237 | + //let's help the regex a bit |
2238 | + bufferStr += "0"; |
2239 | + isValid = opts.regex.number(iopts).test(bufferStr); |
2240 | + if (!isValid) { |
2241 | + //make a valid group |
2242 | + var lastGroupSeparator = bufferStr.lastIndexOf(opts.groupSeparator); |
2243 | + for (var i = bufferStr.length - lastGroupSeparator; i <= 3; i++) { |
2244 | + bufferStr += "0"; |
2245 | + } |
2246 | + |
2247 | + isValid = opts.regex.number(iopts).test(bufferStr); |
2248 | + if (!isValid && !strict) { |
2249 | + if (chrs == opts.radixPoint) { |
2250 | + isValid = opts.regex.number(iopts).test("0" + bufferStr + "0"); |
2251 | + if (isValid) { |
2252 | + buffer[pos] = "0"; |
2253 | + pos++; |
2254 | + return { "pos": pos }; |
2255 | + } |
2256 | + } |
2257 | + } |
2258 | + } |
2259 | + } |
2260 | + |
2261 | + if (isValid != false && !strict && chrs != opts.radixPoint) { |
2262 | + var newPos = opts.postFormat(buffer, pos, (chrs == "-" || chrs == "+") ? true : false, opts); |
2263 | + return { "pos": newPos, "refreshFromBuffer": true }; |
2264 | + } |
2265 | + |
2266 | + return isValid; |
2267 | + }, |
2268 | + cardinality: 1, |
2269 | + prevalidator: null |
2270 | + } |
2271 | + }, |
2272 | + insertMode: true, |
2273 | + autoUnmask: false |
2274 | + }, |
2275 | + 'integer': { |
2276 | + regex: { |
2277 | + number: function (opts) { |
2278 | + var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, opts.groupSeparator); |
2279 | + var signedExpression = opts.allowPlus || opts.allowMinus ? "[" + (opts.allowPlus ? "\+" : "") + (opts.allowMinus ? "-" : "") + "]?" : ""; |
2280 | + return new RegExp("^" + signedExpression + "(\\d+|\\d{1," + opts.groupSize + "}((" + escapedGroupSeparator + "\\d{" + opts.groupSize + "})?)+)$"); |
2281 | + } |
2282 | + }, |
2283 | + alias: "decimal" |
2284 | + } |
2285 | + }); |
2286 | +})(jQuery); |
2287 | |
2288 | === added file 'web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.regex.extensions.js' |
2289 | --- web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.regex.extensions.js 1970-01-01 00:00:00 +0000 |
2290 | +++ web_fields_masks/static/lib/jquery.inputmask/jquery.inputmask.regex.extensions.js 2014-05-20 21:16:10 +0000 |
2291 | @@ -0,0 +1,187 @@ |
2292 | +/* |
2293 | +Input Mask plugin extensions |
2294 | +http://github.com/RobinHerbots/jquery.inputmask |
2295 | +Copyright (c) 2010 - 2014 Robin Herbots |
2296 | +Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php) |
2297 | +Version: 0.0.0 |
2298 | + |
2299 | +Regex extensions on the jquery.inputmask base |
2300 | +Allows for using regular expressions as a mask |
2301 | +*/ |
2302 | +(function ($) { |
2303 | + $.extend($.inputmask.defaults.aliases, { // $(selector).inputmask("Regex", { regex: "[0-9]*"} |
2304 | + 'Regex': { |
2305 | + mask: "r", |
2306 | + greedy: false, |
2307 | + repeat: "*", |
2308 | + regex: null, |
2309 | + regexTokens: null, |
2310 | + //Thx to https://github.com/slevithan/regex-colorizer for the tokenizer regex |
2311 | + tokenizer: /\[\^?]?(?:[^\\\]]+|\\[\S\s]?)*]?|\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9][0-9]*|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)|\((?:\?[:=!]?)?|(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??|[^.?*+^${[()|\\]+|./g, |
2312 | + quantifierFilter: /[0-9]+[^,]/, |
2313 | + isComplete: function(buffer, opts){ |
2314 | + return new RegExp(opts.regex).test(buffer.join('')); |
2315 | + }, |
2316 | + definitions: { |
2317 | + 'r': { |
2318 | + validator: function (chrs, buffer, pos, strict, opts) { |
2319 | + function regexToken(isGroup, isQuantifier) { |
2320 | + this.matches = []; |
2321 | + this.isGroup = isGroup || false; |
2322 | + this.isQuantifier = isQuantifier || false; |
2323 | + this.quantifier = { min: 1, max: 1 }; |
2324 | + this.repeaterPart = undefined; |
2325 | + } |
2326 | + function analyseRegex() { |
2327 | + var currentToken = new regexToken(), match, m, opengroups = []; |
2328 | + |
2329 | + opts.regexTokens = []; |
2330 | + |
2331 | + // The tokenizer regex does most of the tokenization grunt work |
2332 | + while (match = opts.tokenizer.exec(opts.regex)) { |
2333 | + m = match[0]; |
2334 | + switch (m.charAt(0)) { |
2335 | + case "(": // Group opening |
2336 | + opengroups.push(new regexToken(true)); |
2337 | + break; |
2338 | + case ")": // Group closing |
2339 | + var groupToken = opengroups.pop(); |
2340 | + if (opengroups.length > 0) { |
2341 | + opengroups[opengroups.length - 1]["matches"].push(groupToken); |
2342 | + } else { |
2343 | + currentToken.matches.push(groupToken); |
2344 | + } |
2345 | + break; |
2346 | + case "{": case "+": case "*": //Quantifier |
2347 | + var quantifierToken = new regexToken(false, true); |
2348 | + m = m.replace(/[{}]/g, ""); |
2349 | + var mq = m.split(","), mq0 = isNaN(mq[0]) ? mq[0] : parseInt(mq[0]), mq1 = mq.length == 1 ? mq0 : (isNaN(mq[1]) ? mq[1] : parseInt(mq[1])); |
2350 | + quantifierToken.quantifier = { min: mq0, max: mq1 }; |
2351 | + if (opengroups.length > 0) { |
2352 | + var matches = opengroups[opengroups.length - 1]["matches"]; |
2353 | + match = matches.pop(); |
2354 | + if (!match["isGroup"]) { |
2355 | + var groupToken = new regexToken(true); |
2356 | + groupToken.matches.push(match); |
2357 | + match = groupToken; |
2358 | + } |
2359 | + matches.push(match); |
2360 | + matches.push(quantifierToken); |
2361 | + } else { |
2362 | + match = currentToken.matches.pop(); |
2363 | + if (!match["isGroup"]) { |
2364 | + var groupToken = new regexToken(true); |
2365 | + groupToken.matches.push(match); |
2366 | + match = groupToken; |
2367 | + } |
2368 | + currentToken.matches.push(match); |
2369 | + currentToken.matches.push(quantifierToken); |
2370 | + } |
2371 | + break; |
2372 | + default: |
2373 | + if (opengroups.length > 0) { |
2374 | + opengroups[opengroups.length - 1]["matches"].push(m); |
2375 | + } else { |
2376 | + currentToken.matches.push(m); |
2377 | + } |
2378 | + break; |
2379 | + } |
2380 | + } |
2381 | + |
2382 | + if (currentToken.matches.length > 0) |
2383 | + opts.regexTokens.push(currentToken); |
2384 | + }; |
2385 | + |
2386 | + function validateRegexToken(token, fromGroup) { |
2387 | + var isvalid = false; |
2388 | + if (fromGroup) { |
2389 | + regexPart += "("; |
2390 | + openGroupCount++; |
2391 | + } |
2392 | + for (var mndx = 0; mndx < token["matches"].length; mndx++) { |
2393 | + var matchToken = token["matches"][mndx]; |
2394 | + if (matchToken["isGroup"] == true) { |
2395 | + isvalid = validateRegexToken(matchToken, true); |
2396 | + } else if (matchToken["isQuantifier"] == true) { |
2397 | + var crrntndx = token["matches"].indexOf(matchToken), |
2398 | + matchGroup = token["matches"][crrntndx - 1]; |
2399 | + var regexPartBak = regexPart; |
2400 | + if (isNaN(matchToken.quantifier.max)) { |
2401 | + while (matchToken["repeaterPart"] && matchToken["repeaterPart"] != regexPart && matchToken["repeaterPart"].length > regexPart.length) { |
2402 | + isvalid = validateRegexToken(matchGroup, true); |
2403 | + if (isvalid) break; |
2404 | + } |
2405 | + isvalid = isvalid || validateRegexToken(matchGroup, true); |
2406 | + if (isvalid) matchToken["repeaterPart"] = regexPart; |
2407 | + regexPart = regexPartBak + matchToken.quantifier.max; |
2408 | + } else { |
2409 | + for (var i = 0, qm = matchToken.quantifier.max - 1; i < qm; i++) { |
2410 | + isvalid = validateRegexToken(matchGroup, true); |
2411 | + if (isvalid) break; |
2412 | + } |
2413 | + regexPart = regexPartBak + "{" + matchToken.quantifier.min + "," + matchToken.quantifier.max + "}"; |
2414 | + } |
2415 | + } else if (matchToken["matches"] != undefined) { |
2416 | + for (var k = 0; k < matchToken.length; k++) { |
2417 | + isvalid = validateRegexToken(matchToken[k], fromGroup); |
2418 | + if (isvalid) break; |
2419 | + } |
2420 | + } else { |
2421 | + var testExp; |
2422 | + if (matchToken[0] == "[") { |
2423 | + testExp = regexPart; |
2424 | + testExp += matchToken; |
2425 | + for (var j = 0; j < openGroupCount; j++) { |
2426 | + testExp += ")"; |
2427 | + } |
2428 | + var exp = new RegExp("^(" + testExp + ")$"); |
2429 | + isvalid = exp.test(bufferStr); |
2430 | + } else { |
2431 | + for (var l = 0, tl = matchToken.length; l < tl; l++) { |
2432 | + if (matchToken[l] == "\\") continue; |
2433 | + testExp = regexPart; |
2434 | + testExp += matchToken.substr(0, l + 1); |
2435 | + testExp = testExp.replace(/\|$/, ""); |
2436 | + for (var j = 0; j < openGroupCount; j++) { |
2437 | + testExp += ")"; |
2438 | + } |
2439 | + var exp = new RegExp("^(" + testExp + ")$"); |
2440 | + isvalid = exp.test(bufferStr); |
2441 | + if (isvalid) break; |
2442 | + } |
2443 | + } |
2444 | + regexPart += matchToken; |
2445 | + } |
2446 | + if (isvalid) break; |
2447 | + } |
2448 | + |
2449 | + if (fromGroup) { |
2450 | + regexPart += ")"; |
2451 | + openGroupCount--; |
2452 | + } |
2453 | + |
2454 | + return isvalid; |
2455 | + } |
2456 | + |
2457 | + |
2458 | + if (opts.regexTokens == null) { |
2459 | + analyseRegex(); |
2460 | + } |
2461 | + |
2462 | + var cbuffer = buffer.slice(), regexPart = "", isValid = false, openGroupCount = 0; |
2463 | + cbuffer.splice(pos, 0, chrs); |
2464 | + var bufferStr = cbuffer.join(''); |
2465 | + for (var i = 0; i < opts.regexTokens.length; i++) { |
2466 | + var regexToken = opts.regexTokens[i]; |
2467 | + isValid = validateRegexToken(regexToken, regexToken["isGroup"]); |
2468 | + if (isValid) break; |
2469 | + } |
2470 | + |
2471 | + return isValid; |
2472 | + }, |
2473 | + cardinality: 1 |
2474 | + } |
2475 | + } |
2476 | + } |
2477 | + }); |
2478 | +})(jQuery); |
2479 | |
2480 | === added directory 'web_fields_masks/static/src' |
2481 | === added directory 'web_fields_masks/static/src/css' |
2482 | === added directory 'web_fields_masks/static/src/js' |
2483 | === added file 'web_fields_masks/static/src/js/main.js' |
2484 | --- web_fields_masks/static/src/js/main.js 1970-01-01 00:00:00 +0000 |
2485 | +++ web_fields_masks/static/src/js/main.js 2014-05-20 21:16:10 +0000 |
2486 | @@ -0,0 +1,27 @@ |
2487 | +openerp.web_fields_masks = function (instance) { |
2488 | + instance.web.form.FieldChar.include({ |
2489 | + mask: '', |
2490 | + init: function(field_manager, node) { |
2491 | + this._super(field_manager, node); |
2492 | + if (_.has(this.node.attrs, 'data-inputmask')) { |
2493 | + this.mask = this.node.attrs['data-inputmask']; |
2494 | + } |
2495 | + }, |
2496 | + |
2497 | + render_value: function () { |
2498 | + var self = this; |
2499 | + this._super(); |
2500 | + if (this.mask !== '') { |
2501 | + this.$('input').attr('data-inputmask', this.mask); |
2502 | + this.$('input').inputmask(undefined, { |
2503 | + onincomplete: function () { |
2504 | + self.$el.addClass('oe_form_invalid'); |
2505 | + }, |
2506 | + oncomplete: function () { |
2507 | + self.$el.removeClass('oe_form_invalid'); |
2508 | + }, |
2509 | + }); |
2510 | + } |
2511 | + }, |
2512 | + }); |
2513 | +} |
You should put library files into /static/lib (why? If another module uses the same library, it would be loaded twice otherwise and is likely to clash)
Further, #2492 means we can't have apostrophes or quotes in the input mask. Why don't you simply eval() this attribute? This way, the user can fill in either a simple input mask or an object as applicable?
What would be nice is if you set the standard OpenERP error class (oe_form_invalid) if the user's input doesn't match the mask.