Javascript掩码输入
1 function _MaskAPI(){
2 this.version = "0.4b";
3 this.instances = 0;
4 this.objects = {};
5 }
6 MaskAPI = new _MaskAPI();
7
8 function Mask(m, t){
9 this.mask = m;
10 this.type = (typeof t == "string") ? t : "string";
11 this.error = [];
12 this.errorCodes = [];
13 this.value = "";
14 this.strippedValue = "";
15 this.allowPartial = false;
16 this.id = MaskAPI.instances++;
17 this.ref = "MaskAPI.objects['" + this.id + "']";
18 MaskAPI.objects[this.id] = this;
19 }
20
21 // define the attach(oElement) function
22 Mask.prototype.attach = function (o){
23 $addEvent(o, "onkeydown", "return " + this.ref + ".isAllowKeyPress(event, this);", true);
24 $addEvent(o, "onkeyup", "return " + this.ref + ".getKeyPress(event, this);", true);
25 $addEvent(o, "onblur", "this.value = " + this.ref + ".format(this.value);", true);
26 }
27
28 Mask.prototype.isAllowKeyPress = function (e, o){
29 if( this.type != "string" ) return true;
30 var xe = new qEvent(e);
31
32 if( ((xe.keyCode > 47) && (o.value.length >= this.mask.length)) && !xe.ctrlKey ) return false;
33 return true;
34 }
35
36 Mask.prototype.getKeyPress = function (e, o, _u){
37 this.allowPartial = true;
38 var xe = new qEvent(e);
39
40 // var k = String.fromCharCode(xe.keyCode);
41
42 if( (xe.keyCode > 47) || (_u == true) || (xe.keyCode == 8 || xe.keyCode == 46) ){
43 var v = o.value, d;
44 if( xe.keyCode == 8 || xe.keyCode == 46 ) d = true;
45 else d = false
46
47 if( this.type == "number" ) this.value = this.setNumber(v, d);
48 else if( this.type == "date" ) this.value = this.setDateKeyPress(v, d);
49 else this.value = this.setGeneric(v, d);
50
51 o.value = this.value;
52 }
53 /* */
54
55 this.allowPartial = false;
56 return true;
57 }
58
59 Mask.prototype.format = function (s){
60 if( this.type == "number" ) this.value = this.setNumber(s);
61 else if( this.type == "date" ) this.value = this.setDate(s);
62 else this.value = this.setGeneric(s);
63 return this.value;
64 }
65
66 Mask.prototype.throwError = function (c, e, v){
67 this.error[this.error.length] = e;
68 this.errorCodes[this.errorCodes.length] = c;
69 if( typeof v == "string" ) return v;
70 return true;
71 }
72
73 Mask.prototype.setGeneric = function (_v, _d){
74 var v = _v, m = this.mask;
75 var r = "x#*", rt = [], nv = "", t, x, a = [], j=0, rx = {"x": "A-Za-z", "#": "0-9", "*": "A-Za-z0-9" };
76
77 // strip out invalid characters
78 v = v.replace(new RegExp("[^" + rx["*"] + "]", "gi"), "");
79 if( (_d == true) && (v.length == this.strippedValue.length) ) v = v.substring(0, v.length-1);
80 this.strippedValue = v;
81 var b=[];
82 for( var i=0; i < m.length; i++ ){
83 // grab the current character
84 x = m.charAt(i);
85 // check to see if current character is a mask, escape commands are not a mask character
86 t = (r.indexOf(x) > -1);
87 // if the current character is an escape command, then grab the next character
88 if( x == "!" ) x = m.charAt(i++);
89 // build a regex to test against
90 if( (t && !this.allowPartial) || (t && this.allowPartial && (rt.length < v.length)) ) rt[rt.length] = "[" + rx[x] + "]";
91 // build mask definition table
92 a[a.length] = { "chr": x, "mask": t };
93 }
94
95 var hasOneValidChar = false;
96 // if the regex fails, return an error
97 if( !this.allowPartial && !(new RegExp(rt.join(""))).test(v) ) return this.throwError(1, "The value \"" + _v + "\" must be in the format " + this.mask + ".", _v);
98 // loop through the mask definition, and build the formatted string
99 else if( (this.allowPartial && (v.length > 0)) || !this.allowPartial ){
100 for( i=0; i < a.length; i++ ){
101 if( a[i].mask ){
102 while( v.length > 0 && !(new RegExp(rt[j])).test(v.charAt(j)) ) v = (v.length == 1) ? "" : v.substring(1);
103 if( v.length > 0 ){
104 nv += v.charAt(j);
105 hasOneValidChar = true;
106 }
107 j++;
108 } else nv += a[i].chr;
109 if( this.allowPartial && (j > v.length) ) break;
110 }
111 }
112
113 if( this.allowPartial && !hasOneValidChar ) nv = "";
114 if( this.allowPartial ){
115 if( nv.length < a.length ) this.nextValidChar = rx[a[nv.length].chr];
116 else this.nextValidChar = null;
117 }
118
119 return nv;
120 }
121
122 Mask.prototype.setNumber = function(_v, _d){
123 var v = String(_v).replace(/[^\d.-]*/gi, ""), m = this.mask;
124 // make sure there's only one decimal point
125 v = v.replace(/\./, "d").replace(/\./g, "").replace(/d/, ".");
126
127 // check to see if an invalid mask operation has been entered
128 if( !/^[\$]?((\$?[\+-]?([0#]{1,3},)?[0#]*(\.[0#]*)?)|([\+-]?\([\+-]?([0#]{1,3},)?[0#]*(\.[0#]*)?\)))$/.test(m) )
129 return this.throwError(1, "An invalid mask was specified for the \nMask constructor.", _v);
130
131 if( (_d == true) && (v.length == this.strippedValue.length) ) v = v.substring(0, v.length-1);
132
133 if( this.allowPartial && (v.replace(/[^0-9]/, "").length == 0) ) return v;
134 this.strippedValue = v;
135
136 if( v.length == 0 ) v = NaN;
137 var vn = Number(v);
138 if( isNaN(vn) ) return this.throwError(2, "The value entered was not a number.", _v);
139
140 // if no mask, stop processing
141 if( m.length == 0 ) return v;
142
143 // get the value before the decimal point
144 var vi = String(Math.abs((v.indexOf(".") > -1 ) ? v.split(".")[0] : v));
145 // get the value after the decimal point
146 var vd = (v.indexOf(".") > -1) ? v.split(".")[1] : "";
147 var _vd = vd;
148
149 var isNegative = (vn != 0 && Math.abs(vn)*-1 == vn);
150
151 // check for masking operations
152 var show = {
153 "$" : /^[\$]/.test(m),
154 "(": (isNegative && (m.indexOf("(") > -1)),
155 "+" : ( (m.indexOf("+") != -1) && !isNegative )
156 }
157 show["-"] = (isNegative && (!show["("] || (m.indexOf("-") != -1)));
158
159
160 // replace all non-place holders from the mask
161 m = m.replace(/[^#0.,]*/gi, "");
162
163 /*
164 make sure there are the correct number of decimal places
165 */
166 // get number of digits after decimal point in mask
167 var dm = (m.indexOf(".") > -1 ) ? m.split(".")[1] : "";
168 if( dm.length == 0 ){
169 vi = String(Math.round(Number(vi)));
170 vd = "";
171 } else {
172 // find the last zero, which indicates the minimum number
173 // of decimal places to show
174 var md = dm.lastIndexOf("0")+1;
175 // if the number of decimal places is greater than the mask, then round off
176 if( vd.length > dm.length ) vd = String(Math.round(Number(vd.substring(0, dm.length + 1))/10));
177 // otherwise, pad the string w/the required zeros
178 else while( vd.length < md ) vd += "0";
179 }
180
181 /*
182 pad the int with any necessary zeros
183 */
184 // get number of digits before decimal point in mask
185 var im = (m.indexOf(".") > -1 ) ? m.split(".")[0] : m;
186 im = im.replace(/[^0#]+/gi, "");
187 // find the first zero, which indicates the minimum length
188 // that the value must be padded w/zeros
189 var mv = im.indexOf("0")+1;
190 // if there is a zero found, make sure it's padded
191 if( mv > 0 ){
192 mv = im.length - mv + 1;
193 while( vi.length < mv ) vi = "0" + vi;
194 }
195
196
197 /*
198 check to see if we need commas in the thousands place holder
199 */
200 if( /[#0]+,[#0]{3}/.test(m) ){
201 // add the commas as the place holder
202 var x = [], i=0, n=Number(vi);
203 while( n > 999 ){
204 x[i] = "00" + String(n%1000);
205 x[i] = x[i].substring(x[i].length - 3);
206 n = Math.floor(n/1000);
207 i++;
208 }
209 x[i] = String(n%1000);
210 vi = x.reverse().join(",");
211 }
212
213
214 /*
215 combine the new value together
216 */
217 if( (vd.length > 0 && !this.allowPartial) || ((dm.length > 0) && this.allowPartial && (v.indexOf(".") > -1) && (_vd.length >= vd.length)) ){
218 v = vi + "." + vd;
219 } else if( (dm.length > 0) && this.allowPartial && (v.indexOf(".") > -1) && (_vd.length < vd.length) ){
220 v = vi + "." + _vd;
221 } else {
222 v = vi;
223 }
224
225 if( show["$"] ) v = this.mask.replace(/(^[\$])(.+)/gi, "$") + v;
226 if( show["+"] ) v = "+" + v;
227 if( show["-"] ) v = "-" + v;
228 if( show["("] ) v = "(" + v + ")";
229 return v;
230 }
231
232 Mask.prototype.setDate = function (_v){
233 var v = _v, m = this.mask;
234 var a, e, mm, dd, yy, x, s;
235
236 // split mask into array, to see position of each day, month & year
237 a = m.split(/[^mdy]+/);
238 // split mask into array, to get delimiters
239 s = m.split(/[mdy]+/);
240 // convert the string into an array in which digits are together
241 e = v.split(/[^0-9]/);
242
243 if( s[0].length == 0 ) s.splice(0, 1);
244
245 for( var i=0; i < a.length; i++ ){
246 x = a[i].charAt(0).toLowerCase();
247 if( x == "m" ) mm = parseInt(e[i], 10)-1;
248 else if( x == "d" ) dd = parseInt(e[i], 10);
249 else if( x == "y" ) yy = parseInt(e[i], 10);
250 }
251
252 // if year is abbreviated, guess at the year
253 if( String(yy).length < 3 ){
254 yy = 2000 + yy;
255 if( (new Date()).getFullYear()+5 < yy ) yy = yy - 100;
256 }
257
258 // create date object
259 var d = new Date(yy, mm, dd);
260
261 if( d.getDate() != dd ) return this.throwError(1, "An invalid day was entered.", _v);
262 else if( d.getMonth() != mm ) return this.throwError(2, "An invalid month was entered.", _v);
263
264 var nv = "";
265
266 for( i=0; i < a.length; i++ ){
267 x = a[i].charAt(0).toLowerCase();
268 if( x == "m" ){
269 mm++;
270 if( a[i].length == 2 ){
271 mm = "0" + mm;
272 mm = mm.substring(mm.length-2);
273 }
274 nv += mm;
275 } else if( x == "d" ){
276 if( a[i].length == 2 ){
277 dd = "0" + dd;
278 dd = dd.substring(dd.length-2);
279 }
280 nv += dd;
281 } else if( x == "y" ){
282 if( a[i].length == 2 ) nv += d.getYear();
283 else nv += d.getFullYear();
284 }
285
286 if( i < a.length-1 ) nv += s[i];
287 }
288
289 return nv;
290 }
291
292 Mask.prototype.setDateKeyPress = function (_v, _d){
293 var v = _v, m = this.mask, k = v.charAt(v.length-1);
294 var a, e, c, ml, vl, mm = "", dd = "", yy = "", x, p, z;
295
296 if( _d == true ){
297 while( (/[^0-9]/gi).test(v.charAt(v.length-1)) ) v = v.substring(0, v.length-1);
298 if( (/[^0-9]/gi).test(this.strippedValue.charAt(this.strippedValue.length-1)) ) v = v.substring(0, v.length-1);
299 if( v.length == 0 ) return "";
300 }
301
302 // split mask into array, to see position of each day, month & year
303 a = m.split(/[^mdy]/);
304 // split mask into array, to get delimiters
305 s = m.split(/[mdy]+/);
306 // mozilla wants to add an empty array element which needs removed
307 if( s[0].length == 0 ) s.splice(0,1);
308 // convert the string into an array in which digits are together
309 e = v.split(/[^0-9]/);
310 // position in mask
311 p = (e.length > 0) ? e.length-1 : 0;
312 // determine what mask value the user is currently entering
313 c = a[p].charAt(0);
314 // determine the length of the current mask value
315 ml = a[p].length;
316
317 for( var i=0; i < e.length; i++ ){
318 x = a[i].charAt(0).toLowerCase();
319 if( x == "m" ) mm = parseInt(e[i], 10)-1;
320 else if( x == "d" ) dd = parseInt(e[i], 10);
321 else if( x == "y" ) yy = parseInt(e[i], 10);
322 }
323
324
325 var nv = "";
326 var j=0;
327
328 for( i=0; i < e.length; i++ ){
329 x = a[i].charAt(0).toLowerCase();
330
331 if( x == "m" ){
332 z = ((/[^0-9]/).test(k) && c == "m");
333 mm++;
334 if( (e[i].length == 2 && mm < 10) || (a[i].length == 2 && c != "m") || (mm > 1 && c == "m") || (z && a[i].length == 2) ){
335 mm = "0" + mm;
336 mm = mm.substring(mm.length-2);
337 }
338 vl = String(mm).length;
339 ml = 2;
340 nv += mm;
341 } else if( x == "d" ){
342 z = ((/[^0-9]/).test(k) && c == "d");
343 if( (e[i].length == 2 && dd < 10) || (a[i].length == 2 && c != "d") || (dd > 3 && c == "d") || (z && a[i].length == 2) ){
344 dd = "0" + dd;
345 dd = dd.substring(dd.length-2);
346 }
347 vl = String(dd).length;
348 ml = 2;
349 nv += dd;
350 } else if( x == "y" ){
351 z = ((/[^0-9]/).test(k) && c == "y");
352 if( c == "y" ) yy = String(yy);
353 else {
354 if( a[i].length == 2 ) yy = d.getYear();
355 else yy = d.getFullYear();
356 }
357 if( (e[i].length == 2 && yy < 10) || (a[i].length == 2 && c != "y") || (z && a[i].length == 2) ){
358 yy = "0" + yy;
359 yy = yy.substring(yy.length-2);
360 }
361 ml = a[i].length;
362 vl = String(yy).length;
363 nv += yy;
364 }
365
366 if( ((ml == vl || z) && (x == c) && (i < s.length)) || (i < s.length && x != c ) ) nv += s[i];
367 }
368
369 if( nv.length > m.length ) nv = nv.substring(0, m.length);
370
371 this.strippedValue = (nv == "NaN") ? "" : nv;
372
373 return this.strippedValue;
374 }
375
376 function qEvent(e){
377 // routine for NS, Opera, etc DOM browsers
378 if( window.Event ){
379 var isKeyPress = (e.type.substring(0,3) == "key");
380
381 this.keyCode = (isKeyPress) ? parseInt(e.which, 10) : 0;
382 this.button = (!isKeyPress) ? parseInt(e.which, 10) : 0;
383 this.srcElement = e.target;
384 this.type = e.type;
385 this.x = e.pageX;
386 this.y = e.pageY;
387 this.screenX = e.screenX;
388 this.screenY = e.screenY;
389 if( document.layers ){
390 this.altKey = ((e.modifiers & Event.ALT_MASK) > 0);
391 this.ctrlKey = ((e.modifiers & Event.CONTROL_MASK) > 0);
392 this.shiftKey = ((e.modifiers & Event.SHIFT_MASK) > 0);
393 this.keyCode = this.translateKeyCode(this.keyCode);
394 } else {
395 this.altKey = e.altKey;
396 this.ctrlKey = e.ctrlKey;
397 this.shiftKey = e.shiftKey;
398 }
399 // routine for Internet Explorer DOM browsers
400 } else {
401 e = window.event;
402 this.keyCode = parseInt(e.keyCode, 10);
403 this.button = e.button;
404 this.srcElement = e.srcElement;
405 this.type = e.type;
406 if( document.all ){
407 this.x = e.clientX + document.body.scrollLeft;
408 this.y = e.clientY + document.body.scrollTop;
409 } else {
410 this.x = e.clientX;
411 this.y = e.clientY;
412 }
413 this.screenX = e.screenX;
414 this.screenY = e.screenY;
415 this.altKey = e.altKey;
416 this.ctrlKey = e.ctrlKey;
417 this.shiftKey = e.shiftKey;
418 }
419 if( this.button == 0 ){
420 this.setKeyPressed(this.keyCode);
421 this.keyChar = String.fromCharCode(this.keyCode);
422 }
423 }
424
425 // this method will try to remap the keycodes so the keycode value
426 // returned will be consistent. this doesn't work for all cases,
427 // since some browsers don't always return a unique value for a
428 // key press.
429 qEvent.prototype.translateKeyCode = function (i){
430 var l = {};
431 // remap NS4 keycodes to IE/W3C keycodes
432 if( !!document.layers ){
433 if( this.keyCode > 96 && this.keyCode < 123 ) return this.keyCode - 32;
434 l = {
435 96:192,126:192,33:49,64:50,35:51,36:52,37:53,94:54,38:55,42:56,40:57,41:48,92:220,124:220,125:221,
436 93:221,91:219,123:219,39:222,34:222,47:191,63:191,46:190,62:190,44:188,60:188,45:189,95:189,43:187,
437 61:187,59:186,58:186,
438 "null": null
439 }
440 }
441 return (!!l[i]) ? l[i] : i;
442 }
443
444 // try to determine the actual value of the key pressed
445 qEvent.prototype.setKP = function (i, s){
446 this.keyPressedCode = i;
447 this.keyNonChar = (typeof s == "string");
448 this.keyPressed = (this.keyNonChar) ? s : String.fromCharCode(i);
449 this.isNumeric = (parseInt(this.keyPressed, 10) == this.keyPressed);
450 this.isAlpha = ((this.keyCode > 64 && this.keyCode < 91) && !this.altKey && !this.ctrlKey);
451 return true;
452 }
453
454 // try to determine the actual value of the key pressed
455 qEvent.prototype.setKeyPressed = function (i){
456 var b = this.shiftKey;
457 if( !b && (i > 64 && i < 91) ) return this.setKP(i + 32);
458 if( i > 95 && i < 106 ) return this.setKP(i - 48);
459
460 switch( i ){
461 case 49: case 51: case 52: case 53: if( b ) i = i - 16; break;
462 case 50: if( b ) i = 64; break;
463 case 54: if( b ) i = 94; break;
464 case 55: if( b ) i = 38; break;
465 case 56: if( b ) i = 42; break;
466 case 57: if( b ) i = 40; break;
467 case 48: if( b ) i = 41; break;
468 case 192: if( b ) i = 126; else i = 96; break;
469 case 189: if( b ) i = 95; else i = 45; break;
470 case 187: if( b ) i = 43; else i = 61; break;
471 case 220: if( b ) i = 124; else i = 92; break;
472 case 221: if( b ) i = 125; else i = 93; break;
473 case 219: if( b ) i = 123; else i = 91; break;
474 case 222: if( b ) i = 34; else i = 39; break;
475 case 186: if( b ) i = 58; else i = 59; break;
476 case 191: if( b ) i = 63; else i = 47; break;
477 case 190: if( b ) i = 62; else i = 46; break;
478 case 188: if( b ) i = 60; else i = 44; break;
479
480 case 106: case 57379: i = 42; break;
481 case 107: case 57380: i = 43; break;
482 case 109: case 57381: i = 45; break;
483 case 110: i = 46; break;
484 case 111: case 57378: i = 47; break;
485
486 case 8: return this.setKP(i, "[backspace]");
487 case 9: return this.setKP(i, "[tab]");
488 case 13: return this.setKP(i, "[enter]");
489 case 16: case 57389: return this.setKP(i, "[shift]");
490 case 17: case 57390: return this.setKP(i, "[ctrl]");
491 case 18: case 57388: return this.setKP(i, "[alt]");
492 case 19: case 57402: return this.setKP(i, "[break]");
493 case 20: return this.setKP(i, "[capslock]");
494 case 32: return this.setKP(i, "[space]");
495 case 91: return this.setKP(i, "[windows]");
496 case 93: return this.setKP(i, "[properties]");
497
498 case 33: case 57371: return this.setKP(i*-1, "[pgup]");
499 case 34: case 57372: return this.setKP(i*-1, "[pgdown]");
500 case 35: case 57370: return this.setKP(i*-1, "[end]");
501 case 36: case 57369: return this.setKP(i*-1, "[home]");
502 case 37: case 57375: return this.setKP(i*-1, "[left]");
503 case 38: case 57373: return this.setKP(i*-1, "[up]");
504 case 39: case 57376: return this.setKP(i*-1, "[right]");
505 case 40: case 57374: return this.setKP(i*-1, "[down]");
506 case 45: case 57382: return this.setKP(i*-1, "[insert]");
507 case 46: case 57383: return this.setKP(i*-1, "[delete]");
508 case 144: case 57400: return this.setKP(i*-1, "[numlock]");
509 }
510
511 if( i > 111 && i < 124 ) return this.setKP(i*-1, "[f" + (i-111) + "]");
512
513 return this.setKP(i);
514 }
515
516 // define the addEvent(oElement, sEvent, sCmd, bAppend) function
517 function $addEvent(o, _e, c, _b){
518 var e = _e.toLowerCase(), b = (typeof _b == "boolean") ? _b : true, x = (o[e]) ? o[e].toString() : "";
519 // strip out the body of the function
520 x = x.substring(x.indexOf("{")+1, x.lastIndexOf("}"));
521 x = ((b) ? (x + c) : (c + x)) + "\n";
522 return o[e] = (!!window.Event) ? new Function("event", x) : new Function(x);
523 }
2 this.version = "0.4b";
3 this.instances = 0;
4 this.objects = {};
5 }
6 MaskAPI = new _MaskAPI();
7
8 function Mask(m, t){
9 this.mask = m;
10 this.type = (typeof t == "string") ? t : "string";
11 this.error = [];
12 this.errorCodes = [];
13 this.value = "";
14 this.strippedValue = "";
15 this.allowPartial = false;
16 this.id = MaskAPI.instances++;
17 this.ref = "MaskAPI.objects['" + this.id + "']";
18 MaskAPI.objects[this.id] = this;
19 }
20
21 // define the attach(oElement) function
22 Mask.prototype.attach = function (o){
23 $addEvent(o, "onkeydown", "return " + this.ref + ".isAllowKeyPress(event, this);", true);
24 $addEvent(o, "onkeyup", "return " + this.ref + ".getKeyPress(event, this);", true);
25 $addEvent(o, "onblur", "this.value = " + this.ref + ".format(this.value);", true);
26 }
27
28 Mask.prototype.isAllowKeyPress = function (e, o){
29 if( this.type != "string" ) return true;
30 var xe = new qEvent(e);
31
32 if( ((xe.keyCode > 47) && (o.value.length >= this.mask.length)) && !xe.ctrlKey ) return false;
33 return true;
34 }
35
36 Mask.prototype.getKeyPress = function (e, o, _u){
37 this.allowPartial = true;
38 var xe = new qEvent(e);
39
40 // var k = String.fromCharCode(xe.keyCode);
41
42 if( (xe.keyCode > 47) || (_u == true) || (xe.keyCode == 8 || xe.keyCode == 46) ){
43 var v = o.value, d;
44 if( xe.keyCode == 8 || xe.keyCode == 46 ) d = true;
45 else d = false
46
47 if( this.type == "number" ) this.value = this.setNumber(v, d);
48 else if( this.type == "date" ) this.value = this.setDateKeyPress(v, d);
49 else this.value = this.setGeneric(v, d);
50
51 o.value = this.value;
52 }
53 /* */
54
55 this.allowPartial = false;
56 return true;
57 }
58
59 Mask.prototype.format = function (s){
60 if( this.type == "number" ) this.value = this.setNumber(s);
61 else if( this.type == "date" ) this.value = this.setDate(s);
62 else this.value = this.setGeneric(s);
63 return this.value;
64 }
65
66 Mask.prototype.throwError = function (c, e, v){
67 this.error[this.error.length] = e;
68 this.errorCodes[this.errorCodes.length] = c;
69 if( typeof v == "string" ) return v;
70 return true;
71 }
72
73 Mask.prototype.setGeneric = function (_v, _d){
74 var v = _v, m = this.mask;
75 var r = "x#*", rt = [], nv = "", t, x, a = [], j=0, rx = {"x": "A-Za-z", "#": "0-9", "*": "A-Za-z0-9" };
76
77 // strip out invalid characters
78 v = v.replace(new RegExp("[^" + rx["*"] + "]", "gi"), "");
79 if( (_d == true) && (v.length == this.strippedValue.length) ) v = v.substring(0, v.length-1);
80 this.strippedValue = v;
81 var b=[];
82 for( var i=0; i < m.length; i++ ){
83 // grab the current character
84 x = m.charAt(i);
85 // check to see if current character is a mask, escape commands are not a mask character
86 t = (r.indexOf(x) > -1);
87 // if the current character is an escape command, then grab the next character
88 if( x == "!" ) x = m.charAt(i++);
89 // build a regex to test against
90 if( (t && !this.allowPartial) || (t && this.allowPartial && (rt.length < v.length)) ) rt[rt.length] = "[" + rx[x] + "]";
91 // build mask definition table
92 a[a.length] = { "chr": x, "mask": t };
93 }
94
95 var hasOneValidChar = false;
96 // if the regex fails, return an error
97 if( !this.allowPartial && !(new RegExp(rt.join(""))).test(v) ) return this.throwError(1, "The value \"" + _v + "\" must be in the format " + this.mask + ".", _v);
98 // loop through the mask definition, and build the formatted string
99 else if( (this.allowPartial && (v.length > 0)) || !this.allowPartial ){
100 for( i=0; i < a.length; i++ ){
101 if( a[i].mask ){
102 while( v.length > 0 && !(new RegExp(rt[j])).test(v.charAt(j)) ) v = (v.length == 1) ? "" : v.substring(1);
103 if( v.length > 0 ){
104 nv += v.charAt(j);
105 hasOneValidChar = true;
106 }
107 j++;
108 } else nv += a[i].chr;
109 if( this.allowPartial && (j > v.length) ) break;
110 }
111 }
112
113 if( this.allowPartial && !hasOneValidChar ) nv = "";
114 if( this.allowPartial ){
115 if( nv.length < a.length ) this.nextValidChar = rx[a[nv.length].chr];
116 else this.nextValidChar = null;
117 }
118
119 return nv;
120 }
121
122 Mask.prototype.setNumber = function(_v, _d){
123 var v = String(_v).replace(/[^\d.-]*/gi, ""), m = this.mask;
124 // make sure there's only one decimal point
125 v = v.replace(/\./, "d").replace(/\./g, "").replace(/d/, ".");
126
127 // check to see if an invalid mask operation has been entered
128 if( !/^[\$]?((\$?[\+-]?([0#]{1,3},)?[0#]*(\.[0#]*)?)|([\+-]?\([\+-]?([0#]{1,3},)?[0#]*(\.[0#]*)?\)))$/.test(m) )
129 return this.throwError(1, "An invalid mask was specified for the \nMask constructor.", _v);
130
131 if( (_d == true) && (v.length == this.strippedValue.length) ) v = v.substring(0, v.length-1);
132
133 if( this.allowPartial && (v.replace(/[^0-9]/, "").length == 0) ) return v;
134 this.strippedValue = v;
135
136 if( v.length == 0 ) v = NaN;
137 var vn = Number(v);
138 if( isNaN(vn) ) return this.throwError(2, "The value entered was not a number.", _v);
139
140 // if no mask, stop processing
141 if( m.length == 0 ) return v;
142
143 // get the value before the decimal point
144 var vi = String(Math.abs((v.indexOf(".") > -1 ) ? v.split(".")[0] : v));
145 // get the value after the decimal point
146 var vd = (v.indexOf(".") > -1) ? v.split(".")[1] : "";
147 var _vd = vd;
148
149 var isNegative = (vn != 0 && Math.abs(vn)*-1 == vn);
150
151 // check for masking operations
152 var show = {
153 "$" : /^[\$]/.test(m),
154 "(": (isNegative && (m.indexOf("(") > -1)),
155 "+" : ( (m.indexOf("+") != -1) && !isNegative )
156 }
157 show["-"] = (isNegative && (!show["("] || (m.indexOf("-") != -1)));
158
159
160 // replace all non-place holders from the mask
161 m = m.replace(/[^#0.,]*/gi, "");
162
163 /*
164 make sure there are the correct number of decimal places
165 */
166 // get number of digits after decimal point in mask
167 var dm = (m.indexOf(".") > -1 ) ? m.split(".")[1] : "";
168 if( dm.length == 0 ){
169 vi = String(Math.round(Number(vi)));
170 vd = "";
171 } else {
172 // find the last zero, which indicates the minimum number
173 // of decimal places to show
174 var md = dm.lastIndexOf("0")+1;
175 // if the number of decimal places is greater than the mask, then round off
176 if( vd.length > dm.length ) vd = String(Math.round(Number(vd.substring(0, dm.length + 1))/10));
177 // otherwise, pad the string w/the required zeros
178 else while( vd.length < md ) vd += "0";
179 }
180
181 /*
182 pad the int with any necessary zeros
183 */
184 // get number of digits before decimal point in mask
185 var im = (m.indexOf(".") > -1 ) ? m.split(".")[0] : m;
186 im = im.replace(/[^0#]+/gi, "");
187 // find the first zero, which indicates the minimum length
188 // that the value must be padded w/zeros
189 var mv = im.indexOf("0")+1;
190 // if there is a zero found, make sure it's padded
191 if( mv > 0 ){
192 mv = im.length - mv + 1;
193 while( vi.length < mv ) vi = "0" + vi;
194 }
195
196
197 /*
198 check to see if we need commas in the thousands place holder
199 */
200 if( /[#0]+,[#0]{3}/.test(m) ){
201 // add the commas as the place holder
202 var x = [], i=0, n=Number(vi);
203 while( n > 999 ){
204 x[i] = "00" + String(n%1000);
205 x[i] = x[i].substring(x[i].length - 3);
206 n = Math.floor(n/1000);
207 i++;
208 }
209 x[i] = String(n%1000);
210 vi = x.reverse().join(",");
211 }
212
213
214 /*
215 combine the new value together
216 */
217 if( (vd.length > 0 && !this.allowPartial) || ((dm.length > 0) && this.allowPartial && (v.indexOf(".") > -1) && (_vd.length >= vd.length)) ){
218 v = vi + "." + vd;
219 } else if( (dm.length > 0) && this.allowPartial && (v.indexOf(".") > -1) && (_vd.length < vd.length) ){
220 v = vi + "." + _vd;
221 } else {
222 v = vi;
223 }
224
225 if( show["$"] ) v = this.mask.replace(/(^[\$])(.+)/gi, "$") + v;
226 if( show["+"] ) v = "+" + v;
227 if( show["-"] ) v = "-" + v;
228 if( show["("] ) v = "(" + v + ")";
229 return v;
230 }
231
232 Mask.prototype.setDate = function (_v){
233 var v = _v, m = this.mask;
234 var a, e, mm, dd, yy, x, s;
235
236 // split mask into array, to see position of each day, month & year
237 a = m.split(/[^mdy]+/);
238 // split mask into array, to get delimiters
239 s = m.split(/[mdy]+/);
240 // convert the string into an array in which digits are together
241 e = v.split(/[^0-9]/);
242
243 if( s[0].length == 0 ) s.splice(0, 1);
244
245 for( var i=0; i < a.length; i++ ){
246 x = a[i].charAt(0).toLowerCase();
247 if( x == "m" ) mm = parseInt(e[i], 10)-1;
248 else if( x == "d" ) dd = parseInt(e[i], 10);
249 else if( x == "y" ) yy = parseInt(e[i], 10);
250 }
251
252 // if year is abbreviated, guess at the year
253 if( String(yy).length < 3 ){
254 yy = 2000 + yy;
255 if( (new Date()).getFullYear()+5 < yy ) yy = yy - 100;
256 }
257
258 // create date object
259 var d = new Date(yy, mm, dd);
260
261 if( d.getDate() != dd ) return this.throwError(1, "An invalid day was entered.", _v);
262 else if( d.getMonth() != mm ) return this.throwError(2, "An invalid month was entered.", _v);
263
264 var nv = "";
265
266 for( i=0; i < a.length; i++ ){
267 x = a[i].charAt(0).toLowerCase();
268 if( x == "m" ){
269 mm++;
270 if( a[i].length == 2 ){
271 mm = "0" + mm;
272 mm = mm.substring(mm.length-2);
273 }
274 nv += mm;
275 } else if( x == "d" ){
276 if( a[i].length == 2 ){
277 dd = "0" + dd;
278 dd = dd.substring(dd.length-2);
279 }
280 nv += dd;
281 } else if( x == "y" ){
282 if( a[i].length == 2 ) nv += d.getYear();
283 else nv += d.getFullYear();
284 }
285
286 if( i < a.length-1 ) nv += s[i];
287 }
288
289 return nv;
290 }
291
292 Mask.prototype.setDateKeyPress = function (_v, _d){
293 var v = _v, m = this.mask, k = v.charAt(v.length-1);
294 var a, e, c, ml, vl, mm = "", dd = "", yy = "", x, p, z;
295
296 if( _d == true ){
297 while( (/[^0-9]/gi).test(v.charAt(v.length-1)) ) v = v.substring(0, v.length-1);
298 if( (/[^0-9]/gi).test(this.strippedValue.charAt(this.strippedValue.length-1)) ) v = v.substring(0, v.length-1);
299 if( v.length == 0 ) return "";
300 }
301
302 // split mask into array, to see position of each day, month & year
303 a = m.split(/[^mdy]/);
304 // split mask into array, to get delimiters
305 s = m.split(/[mdy]+/);
306 // mozilla wants to add an empty array element which needs removed
307 if( s[0].length == 0 ) s.splice(0,1);
308 // convert the string into an array in which digits are together
309 e = v.split(/[^0-9]/);
310 // position in mask
311 p = (e.length > 0) ? e.length-1 : 0;
312 // determine what mask value the user is currently entering
313 c = a[p].charAt(0);
314 // determine the length of the current mask value
315 ml = a[p].length;
316
317 for( var i=0; i < e.length; i++ ){
318 x = a[i].charAt(0).toLowerCase();
319 if( x == "m" ) mm = parseInt(e[i], 10)-1;
320 else if( x == "d" ) dd = parseInt(e[i], 10);
321 else if( x == "y" ) yy = parseInt(e[i], 10);
322 }
323
324
325 var nv = "";
326 var j=0;
327
328 for( i=0; i < e.length; i++ ){
329 x = a[i].charAt(0).toLowerCase();
330
331 if( x == "m" ){
332 z = ((/[^0-9]/).test(k) && c == "m");
333 mm++;
334 if( (e[i].length == 2 && mm < 10) || (a[i].length == 2 && c != "m") || (mm > 1 && c == "m") || (z && a[i].length == 2) ){
335 mm = "0" + mm;
336 mm = mm.substring(mm.length-2);
337 }
338 vl = String(mm).length;
339 ml = 2;
340 nv += mm;
341 } else if( x == "d" ){
342 z = ((/[^0-9]/).test(k) && c == "d");
343 if( (e[i].length == 2 && dd < 10) || (a[i].length == 2 && c != "d") || (dd > 3 && c == "d") || (z && a[i].length == 2) ){
344 dd = "0" + dd;
345 dd = dd.substring(dd.length-2);
346 }
347 vl = String(dd).length;
348 ml = 2;
349 nv += dd;
350 } else if( x == "y" ){
351 z = ((/[^0-9]/).test(k) && c == "y");
352 if( c == "y" ) yy = String(yy);
353 else {
354 if( a[i].length == 2 ) yy = d.getYear();
355 else yy = d.getFullYear();
356 }
357 if( (e[i].length == 2 && yy < 10) || (a[i].length == 2 && c != "y") || (z && a[i].length == 2) ){
358 yy = "0" + yy;
359 yy = yy.substring(yy.length-2);
360 }
361 ml = a[i].length;
362 vl = String(yy).length;
363 nv += yy;
364 }
365
366 if( ((ml == vl || z) && (x == c) && (i < s.length)) || (i < s.length && x != c ) ) nv += s[i];
367 }
368
369 if( nv.length > m.length ) nv = nv.substring(0, m.length);
370
371 this.strippedValue = (nv == "NaN") ? "" : nv;
372
373 return this.strippedValue;
374 }
375
376 function qEvent(e){
377 // routine for NS, Opera, etc DOM browsers
378 if( window.Event ){
379 var isKeyPress = (e.type.substring(0,3) == "key");
380
381 this.keyCode = (isKeyPress) ? parseInt(e.which, 10) : 0;
382 this.button = (!isKeyPress) ? parseInt(e.which, 10) : 0;
383 this.srcElement = e.target;
384 this.type = e.type;
385 this.x = e.pageX;
386 this.y = e.pageY;
387 this.screenX = e.screenX;
388 this.screenY = e.screenY;
389 if( document.layers ){
390 this.altKey = ((e.modifiers & Event.ALT_MASK) > 0);
391 this.ctrlKey = ((e.modifiers & Event.CONTROL_MASK) > 0);
392 this.shiftKey = ((e.modifiers & Event.SHIFT_MASK) > 0);
393 this.keyCode = this.translateKeyCode(this.keyCode);
394 } else {
395 this.altKey = e.altKey;
396 this.ctrlKey = e.ctrlKey;
397 this.shiftKey = e.shiftKey;
398 }
399 // routine for Internet Explorer DOM browsers
400 } else {
401 e = window.event;
402 this.keyCode = parseInt(e.keyCode, 10);
403 this.button = e.button;
404 this.srcElement = e.srcElement;
405 this.type = e.type;
406 if( document.all ){
407 this.x = e.clientX + document.body.scrollLeft;
408 this.y = e.clientY + document.body.scrollTop;
409 } else {
410 this.x = e.clientX;
411 this.y = e.clientY;
412 }
413 this.screenX = e.screenX;
414 this.screenY = e.screenY;
415 this.altKey = e.altKey;
416 this.ctrlKey = e.ctrlKey;
417 this.shiftKey = e.shiftKey;
418 }
419 if( this.button == 0 ){
420 this.setKeyPressed(this.keyCode);
421 this.keyChar = String.fromCharCode(this.keyCode);
422 }
423 }
424
425 // this method will try to remap the keycodes so the keycode value
426 // returned will be consistent. this doesn't work for all cases,
427 // since some browsers don't always return a unique value for a
428 // key press.
429 qEvent.prototype.translateKeyCode = function (i){
430 var l = {};
431 // remap NS4 keycodes to IE/W3C keycodes
432 if( !!document.layers ){
433 if( this.keyCode > 96 && this.keyCode < 123 ) return this.keyCode - 32;
434 l = {
435 96:192,126:192,33:49,64:50,35:51,36:52,37:53,94:54,38:55,42:56,40:57,41:48,92:220,124:220,125:221,
436 93:221,91:219,123:219,39:222,34:222,47:191,63:191,46:190,62:190,44:188,60:188,45:189,95:189,43:187,
437 61:187,59:186,58:186,
438 "null": null
439 }
440 }
441 return (!!l[i]) ? l[i] : i;
442 }
443
444 // try to determine the actual value of the key pressed
445 qEvent.prototype.setKP = function (i, s){
446 this.keyPressedCode = i;
447 this.keyNonChar = (typeof s == "string");
448 this.keyPressed = (this.keyNonChar) ? s : String.fromCharCode(i);
449 this.isNumeric = (parseInt(this.keyPressed, 10) == this.keyPressed);
450 this.isAlpha = ((this.keyCode > 64 && this.keyCode < 91) && !this.altKey && !this.ctrlKey);
451 return true;
452 }
453
454 // try to determine the actual value of the key pressed
455 qEvent.prototype.setKeyPressed = function (i){
456 var b = this.shiftKey;
457 if( !b && (i > 64 && i < 91) ) return this.setKP(i + 32);
458 if( i > 95 && i < 106 ) return this.setKP(i - 48);
459
460 switch( i ){
461 case 49: case 51: case 52: case 53: if( b ) i = i - 16; break;
462 case 50: if( b ) i = 64; break;
463 case 54: if( b ) i = 94; break;
464 case 55: if( b ) i = 38; break;
465 case 56: if( b ) i = 42; break;
466 case 57: if( b ) i = 40; break;
467 case 48: if( b ) i = 41; break;
468 case 192: if( b ) i = 126; else i = 96; break;
469 case 189: if( b ) i = 95; else i = 45; break;
470 case 187: if( b ) i = 43; else i = 61; break;
471 case 220: if( b ) i = 124; else i = 92; break;
472 case 221: if( b ) i = 125; else i = 93; break;
473 case 219: if( b ) i = 123; else i = 91; break;
474 case 222: if( b ) i = 34; else i = 39; break;
475 case 186: if( b ) i = 58; else i = 59; break;
476 case 191: if( b ) i = 63; else i = 47; break;
477 case 190: if( b ) i = 62; else i = 46; break;
478 case 188: if( b ) i = 60; else i = 44; break;
479
480 case 106: case 57379: i = 42; break;
481 case 107: case 57380: i = 43; break;
482 case 109: case 57381: i = 45; break;
483 case 110: i = 46; break;
484 case 111: case 57378: i = 47; break;
485
486 case 8: return this.setKP(i, "[backspace]");
487 case 9: return this.setKP(i, "[tab]");
488 case 13: return this.setKP(i, "[enter]");
489 case 16: case 57389: return this.setKP(i, "[shift]");
490 case 17: case 57390: return this.setKP(i, "[ctrl]");
491 case 18: case 57388: return this.setKP(i, "[alt]");
492 case 19: case 57402: return this.setKP(i, "[break]");
493 case 20: return this.setKP(i, "[capslock]");
494 case 32: return this.setKP(i, "[space]");
495 case 91: return this.setKP(i, "[windows]");
496 case 93: return this.setKP(i, "[properties]");
497
498 case 33: case 57371: return this.setKP(i*-1, "[pgup]");
499 case 34: case 57372: return this.setKP(i*-1, "[pgdown]");
500 case 35: case 57370: return this.setKP(i*-1, "[end]");
501 case 36: case 57369: return this.setKP(i*-1, "[home]");
502 case 37: case 57375: return this.setKP(i*-1, "[left]");
503 case 38: case 57373: return this.setKP(i*-1, "[up]");
504 case 39: case 57376: return this.setKP(i*-1, "[right]");
505 case 40: case 57374: return this.setKP(i*-1, "[down]");
506 case 45: case 57382: return this.setKP(i*-1, "[insert]");
507 case 46: case 57383: return this.setKP(i*-1, "[delete]");
508 case 144: case 57400: return this.setKP(i*-1, "[numlock]");
509 }
510
511 if( i > 111 && i < 124 ) return this.setKP(i*-1, "[f" + (i-111) + "]");
512
513 return this.setKP(i);
514 }
515
516 // define the addEvent(oElement, sEvent, sCmd, bAppend) function
517 function $addEvent(o, _e, c, _b){
518 var e = _e.toLowerCase(), b = (typeof _b == "boolean") ? _b : true, x = (o[e]) ? o[e].toString() : "";
519 // strip out the body of the function
520 x = x.substring(x.indexOf("{")+1, x.lastIndexOf("}"));
521 x = ((b) ? (x + c) : (c + x)) + "\n";
522 return o[e] = (!!window.Event) ? new Function("event", x) : new Function(x);
523 }
Life is like a boat, and I'm at sea.