/** | |
* JavaScript Mask Edit control | |
* Paul Geerts | |
* Oct 2002 | |
* | |
* Note: This probably only works for English | |
* Other languages have been deprecated and will be removed in the | |
* next version of Speech (TM) | |
**/ | |
var dontDoIt; // hack for Moz because it won't cancel events properly | |
var isTab; // another Moz hack | |
// Init the mask edit field by creating a lookalike DIV | |
// and hiding the real one | |
function initMask(field, maskField) { | |
if (field.disabled == true) { | |
return; | |
} | |
var mask = maskField.value; | |
var val = field.value; | |
if (!val) { // if there's no val, init it with empty mask | |
val = displayMask(mask); | |
field.value = displayMask(mask); | |
} | |
// create a div and add a bunch of spans | |
// and edits to it. | |
div = document.createElement("div"); | |
div.style.backgroundColor = "white"; | |
for (var i = 0 ; i < mask.length ; i++) { | |
var ds = document.createElement("SPAN"); | |
var v = val.substr(i,1); | |
var m = mask.substr(i,1); | |
if (v==" ") { | |
v=" "; | |
} | |
ds.innerHTML = v; | |
ds.index = i; | |
ds.mask = m; | |
ds.div = div; | |
// if we can edit this char | |
// make a little tiny edit field | |
if (isEditChar(m)) { | |
var es = document.createElement("INPUT"); | |
es.style.width = "1px"; | |
es.style.border="0px"; | |
es.index = i; | |
es.field = field; | |
es.mask = m; | |
es.display = ds; | |
ds.editField = es; | |
es.div = div; | |
div.appendChild(es); // set up some events | |
if (navigator.appName == "Microsoft Internet Explorer") { | |
addEvent("keypress", es, changeBitIE); | |
} else { | |
addEvent("keypress", es, changeBitNS); | |
} | |
addEvent("keydown", es, specialKey); // keydown handles stuff like home, end etc | |
addEvent("click", ds, click); | |
} | |
div.appendChild(ds); | |
} | |
// the final edit field on the end | |
var es =document.createElement("INPUT"); | |
es.style.width = "1px"; | |
es.style.border="0px"; | |
es.div = div; | |
div.appendChild(es); | |
if (navigator.appName == "Microsoft Internet Explorer") { | |
addEvent("keypress", es, changeBitIE); | |
} else { | |
addEvent("keypress", es, changeBitNS); | |
} | |
addEvent("keydown", es, specialKey); | |
div.noWrap = true; // force single line display | |
formatDiv(div, field); // format the DIV to look like an edit box | |
field.style.display = 'none'; | |
field.parentNode.insertBefore(div, field); | |
addEvent("click", div, divClick); | |
} | |
function formatDiv(div, field) { | |
// make it look like an IE edit | |
if (navigator.appName == "Microsoft Internet Explorer") { | |
div.style.fontFamily="courier"; | |
div.style.fontSize="10pt"; | |
div.style.width = field.offsetWidth; | |
div.style.height = field.offsetHeight; | |
if (navigator.appVersion.match(/6.0/)) { // IE 6 is different | |
div.style.border = "1px solid #7F9DB9"; | |
} else { | |
div.style.borderLeft = "2px solid #606060"; | |
div.style.borderTop = "2px solid #606060"; | |
div.style.borderRight = "1px solid #aaaaaa"; | |
div.style.borderBottom = "1px solid #aaaaaa"; | |
} | |
} else { | |
// Mozilla edit look-a-like | |
div.style.fontFamily="courier"; | |
div.style.fontSize="10pt"; | |
div.style.border="2px inset #cccccc"; | |
if (field.size) { | |
div.style.widh = 13 * field.size; | |
} else { | |
div.style.width = "130px"; | |
} | |
} | |
} | |
function isEditChar(c) { // is this char a meaningful mask char | |
switch (c) { | |
case "_": | |
case "#": | |
case "a": | |
case "A": | |
case "l": | |
case "L": | |
return true; | |
default: | |
return false; | |
} | |
return false; | |
} | |
function displayMaskChar(c) { // display mask chars as _ | |
if (isEditChar(c)) { // otherwise just show normal char | |
return "_"; | |
} else { | |
return c; | |
} | |
} | |
function displayMask(mask) { // display entire mask using about subroutine | |
var d = ""; | |
for (var i = 0 ; i < mask.length ; i++) { | |
d+=displayMaskChar(mask.substr(i,1)); | |
} | |
return d; | |
} | |
function divClick(e) { // when the main DIV is clicked, focus the end of the edit | |
var d = getEventObject(e); | |
if (d && d.lastChild) { | |
try { | |
d.lastChild.focus(); | |
} catch (e) { | |
// nuffin | |
} | |
} | |
} | |
function specialKey(e) { // deal with special keys like backspace, delete etc | |
var s = getEventObject(e); | |
var code = e.keyCode; | |
dontDoIt = true; // Moz needs these, as I can't seem to cancel events properly | |
isTab = false; // Moz can't handle tabs well either | |
switch (code) { | |
case 8: // backspace | |
var b = getPrevEdit(s); | |
if (b) { | |
b.display.innerHTML = displayMaskChar(b.mask); | |
var i = b.index; | |
b.field.value = b.field.value.substr(0, i) + | |
displayMaskChar(b.mask) + b.field.value.substr(i+1, b.field.value.length - i); | |
b.focus(); | |
} | |
cancelEvent(e); | |
return false; | |
case 46: // delete | |
if (s.display) { | |
s.display.innerHTML = displayMaskChar(s.mask); | |
var i = s.index; | |
s.field.value = s.field.value.substr(0, i) + displayMaskChar(s.mask) + | |
s.field.value.substr(i+1, s.field.value.length - i); | |
} | |
cancelEvent(e); | |
return false; | |
break; | |
case 37: // left | |
var p = getPrevEdit(s); | |
if (p) { | |
p.focus(); | |
} | |
cancelEvent(e); | |
return false; | |
case 39: // right | |
var n = getNextEdit(s); | |
if (n) { | |
n.focus(); | |
} | |
cancelEvent(e); | |
return false; | |
case 36: // home | |
s.div.firstChild.focus(); | |
cancelEvent(e); | |
return false; | |
case 35: // end | |
s.div.lastChild.focus(); | |
cancelEvent(e); | |
return false; | |
case 9: // tab | |
if (navigator.appName == "Microsoft Internet Explorer") { | |
if (!e.shiftKey) { | |
s.div.lastChild.focus(); | |
} else { | |
s.div.firstChild.focus(); | |
} | |
return; | |
} else { // is mozilla/netscape | |
isTab = true; // best i can do really | |
} | |
break; | |
} | |
dontDoIt = false; | |
} | |
function moveForward(s) { // focus next edit | |
var b = getNextEdit(s); | |
if (b) { | |
b.focus(); | |
} | |
} | |
function moveBackward(s) { // focus previous edit | |
var b = getPrevEdit(s); | |
if (b) { | |
b.focus(); | |
} | |
} | |
function isInsertOK(code, s) { // check if you're good to insert a char | |
var mchar = s.mask; | |
switch (mchar) { | |
case "_": | |
return true; | |
break; | |
case "#": | |
return checkDigit(code); | |
break; | |
case "a": | |
return checkAlphaNumeric(code); | |
break; | |
case "A": | |
return checkUpCaseAlphaNumeric(code); | |
break; | |
case "l": | |
return checkAlpha(code); | |
break; | |
case "L": | |
return checkUpCaseAlpha(code); | |
break; | |
} | |
return false; | |
} | |
// functions to check the key code, good ol ASCII | |
// fairly straightforward | |
function checkDigit(code) { | |
if ((code>=48) && (code<=57)) { | |
return code; | |
} else { | |
return null; | |
} | |
} | |
function checkAlpha(code) { | |
if (((code>=65) && (code<=90)) || ((code>=97) && (code<=122))) { | |
return code; | |
} else { | |
return null; | |
} | |
} | |
function checkUpCaseAlpha(code) { | |
if ((code>=65) && (code<=90)) { | |
return code; | |
} else if ((code>=97) && (code<=122)) { | |
return code - 32; | |
} else { | |
return null; | |
} | |
} | |
function checkAlphaNumeric(code) { | |
if (((code>=65) && (code<=90)) || ((code>=97) && (code<=122)) || ((code>=48) && (code<=57))) { | |
return code; | |
} else { | |
return null; | |
} | |
} | |
function checkUpCaseAlphaNumeric(code) { | |
if ((code>=65) && (code<=90)) { | |
return code; | |
} else if ((code>=97) && (code<=122)) { | |
return code - 32; | |
} else if ((code>=48) && (code<=57)) { | |
return code; | |
} else { | |
return null; | |
} | |
} | |
function changeBitNS(e) { // handle key events in NS | |
var es = getEventObject(e); | |
if (!isTab) { | |
if (es.display) { | |
if (!dontDoIt) { | |
var code = e.charCode; | |
if (code = isInsertOK(code, es)) { | |
var c = String.fromCharCode(code); | |
es.display.innerHTML = c | |
var i = es.index; | |
es.field.value = es.field.value.substr(0, i) + c + es.field.value.substr(i+1, es.field.value.length - i); | |
moveForward(es); | |
} | |
} | |
es.value = ""; | |
cancelEvent(e); | |
} | |
return false; | |
} | |
} | |
function changeBitIE(e) { // handle key events in IE | |
var es = getEventObject(e); | |
if (es.display) { | |
var code = e.keyCode; | |
if (code = isInsertOK(code, es)) { | |
var c = String.fromCharCode(code); | |
es.display.innerHTML = c; | |
var i = es.index; | |
es.field.value = es.field.value.substr(0, i) + c + es.field.value.substr(i+1, es.field.value.length - i); | |
moveForward(es); | |
es.value = ""; | |
} | |
} | |
cancelEvent(e); | |
return false; | |
} | |
function click(e) { // clicking on a display span focuses the edit | |
var s = getEventObject(e); | |
s.editField.focus(); | |
cancelEvent(e); | |
return false; | |
} | |
function getPrevEdit(s) { // get previous input field | |
var b = s.previousSibling; | |
while (b && (b.tagName!="INPUT")) { | |
b = b.previousSibling; | |
} | |
return b; | |
} | |
function getNextEdit(s) { // get previous next field | |
var b = s.nextSibling; | |
while (b && (b.tagName!="INPUT")) { | |
b = b.nextSibling; | |
} | |
return b; | |
} | |
function cancelEvent(e) { // kill event propagation | |
e.cancelBubble = true; | |
e.cancel = true; | |
if (navigator.appName != "Microsoft Internet Explorer") { | |
e.stopPropagation(); // doesn't seem to work for key events | |
e.preventDefault(); | |
} | |
} | |
function getEventObject(e) { // utility function to retrieve object from event | |
if (navigator.appName == "Microsoft Internet Explorer") { | |
return e.srcElement; | |
} else { // is mozilla/netscape | |
// need to crawl up the tree to get the first "real" element | |
// i.e. a tag, not raw text | |
var o = e.target; | |
while (!o.tagName) { | |
o = o.parentNode; | |
} | |
return o; | |
} | |
} | |
function addEvent(name, obj, funct) { // utility function to add event handlers | |
if (navigator.appName == "Microsoft Internet Explorer") { | |
obj.attachEvent("on"+name, funct); | |
} else { // is mozilla/netscape | |
obj.addEventListener(name, funct, false); | |
} | |
} | |
function deleteEvent(name, obj, funct) { // utility function to delete event handlers | |
if (navigator.appName == "Microsoft Internet Explorer") { | |
obj.detachEvent("on"+name, funct); | |
} else { // is mozilla/netscape | |
obj.removeEventListener(name, funct, false); | |
} | |
} |