CVS: Tapestry/contrib/src/net/sf/tapestry/contrib/form MaskEdit.script,NONE,1.1 MaskEdit.java,NONE,1.1 MaskEdit.js,NONE,1.1 MaskEdit.jwc,NONE,1.1 MaskEdit.html,NONE,1.1

Malcolm Edgar <[email protected]>
Newsgroups gmane.comp.java.tapestry.cvs
Message-ID <[email protected]>
Update of /cvsroot/tapestry/Tapestry/contrib/src/net/sf/tapestry/contrib/form
In directory sc8-pr-cvs1:/tmp/cvs-serv21755/contrib/src/net/sf/tapestry/contrib/form

Added Files:
	MaskEdit.script MaskEdit.java MaskEdit.js MaskEdit.jwc 
	MaskEdit.html 
Log Message:
Moved MaskEdit to contrib

--- NEW FILE: MaskEdit.script ---
<?xml version="1.0" encoding="UTF-8"?>
<!-- $Id: MaskEdit.script,v 1.1 2002/12/22 06:28:00 malcolm_edgar Exp $ -->
<!DOCTYPE script PUBLIC
	"-//Howard Lewis Ship//Tapestry Script 1.2//EN"
	"http://tapestry.sf.net/dtd/Script_1_2.dtd">
  
<script>

<include-script resource-path="/net/sf/tapestry/form/MaskEdit.js"/>

<input-symbol key="maskEdit" class="net.sf.tapestry.form.TextField" required="yes"/>
<input-symbol key="maskValue" class="net.sf.tapestry.form.Hidden" required="yes"/>

<let key="formName">
  ${maskEdit.form.name}
</let>

<let key="functionName">
  ${maskEdit.name}_init
</let>


<body>
function ${functionName}() {
  initMask(document.${formName}.${maskEdit.name},
           document.${formName}.${maskValue.name});
}
</body>

<initialization>
  ${functionName}();
</initialization>

</script>


--- NEW FILE: MaskEdit.java ---
package net.sf.tapestry.contrib.form;

import net.sf.tapestry.BaseComponent;
import net.sf.tapestry.IBinding;

/**
 * Provides a mask edit HTML &lt;input type="text"&gt; form element.
 * <p>
 * Mask edit field validates the text the user enters against a 
 * mask that encodes the valid forms the text can take. The mask can 
 * also format text that is displayed to the user.
 * <p>
 * <table border="1" cellpadding="2">
 *  <tr>
 *   <th>Mask character</th><th>Meaning in mask</th>
 *  </tr>
 *  <tr>
 *   <td>&nbsp;l</td><td>&nbsp;Mixed case letter character [a..z, A..Z]</td>
 *  </tr>
 *  <tr>
 *   <td>&nbsp;L</td><td>&nbsp;Upper case letter character [A..Z]</td>
 *  </tr>
 *  <tr>
 *   <td>&nbsp;a</td><td>&nbsp;Mixed case alpha numeric character [a..z, A..Z, 0..1]</td>
 *  </tr>
 *  <tr>
 *   <td>&nbsp;A</td><td>&nbsp;Upper case alpha numeric character [A..Z, 0..9]</td>
 *  </tr>
 *  <tr>
 *   <td>&nbsp;#</td><td>&nbsp;Numeric character [0..9]</td>
 *  </tr>
 *  <tr>
 *   <td>&nbsp;_</td><td>&nbsp;Reserved character for display, do not use.</td>
 *  </tr>
 *  <tr>
 *   <td>&nbsp;others</td><td>&nbsp;Non editable character for display.</td>
 *  </tr>
 * </table> 
 * <p>
 * This component requires JavaScript to be enabled in the client browser.
 * <p>
 * [<a href="../../../../../ComponentReference/MaskEdit.html">Component Reference</a>]
 *
 * @author Malcolm Edgar
 * @version $Id: MaskEdit.java,v 1.1 2002/12/22 06:28:00 malcolm_edgar Exp $
 * @since 2.3
 *
 **/

public class MaskEdit extends BaseComponent
{
    private String _mask;
    private IBinding _valueBinding;
    private boolean _disabled;

    public String getMask()
    {
        return _mask;
    }

    public void setMask(String mask)
    {
        _mask = mask;
    }
    
    public String getValue()
    {
        if (_valueBinding != null) {
            return _valueBinding.getString();
        } else {
            return null;
        }
    }

    public void setValue(String value)
    {
        _valueBinding.setString(value);
    }

    public IBinding getValueBinding()
    {
        return _valueBinding;
    }

    public void setValueBinding(IBinding valueBinding)
    {
        _valueBinding = valueBinding;
    }

    public boolean isDisabled()
    {
        return _disabled;
    }

    public void setDisabled(boolean disabled)
    {
        _disabled = disabled;
    }        
}

--- NEW FILE: MaskEdit.js ---
/**
 *  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="&nbsp;";
        }
        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);
    }
}

--- NEW FILE: MaskEdit.jwc ---
<?xml version="1.0" encoding="UTF-8"?>
<!-- $Id: MaskEdit.jwc,v 1.1 2002/12/22 06:28:00 malcolm_edgar Exp $ -->
<!DOCTYPE component-specification PUBLIC 
	"-//Howard Lewis Ship//Tapestry Specification 1.3//EN"
	"http://tapestry.sf.net/dtd/Tapestry_1_3.dtd">

<component-specification class="net.sf.tapestry.contrib.form.MaskEdit" allow-informal-parameters="no">

  <parameter name="mask" direction="in" java-type="java.lang.String" required="yes"/>
  <parameter name="value" direction="custom" java-type="java.lang.String" required="yes"/>
  <parameter name="disabled" direction="in" java-type="boolean" required="no"/>
  
  <component id="maskEdit" type="TextField">
    <binding name="value" expression="value"/>
    <binding name="maxlength" expression="mask.length()"/>
    <binding name="size" expression="mask.length()"/>        
    <binding name="disabled" expression="disabled"/>
  </component>

  <component id="maskValue" type="Hidden">
    <binding name="value" expression="mask"/>
    <binding name="encode" expression="false"/>
  </component>

  <component id="maskEditScript" type="Script">
    <binding name="maskEdit" expression="components.maskEdit"/>
    <binding name="maskValue" expression="components.maskValue"/>
    <binding name="script" expression='"/net/sf/tapestry/contrib/form/MaskEdit.script"'/>
  </component>
        
</component-specification>

--- NEW FILE: MaskEdit.html ---
<input jwcid="maskEdit" type="text"/>
<input jwcid="maskValue" type="hidden"/>
<span jwcid="maskEditScript"/>





-------------------------------------------------------
This SF.NET email is sponsored by: Order your Holiday Geek Presents Now!
Green Lasers, Hip Geek T-Shirts, Remote Control Tanks, Caffeinated Soap,
MP3 Players,  XBox Games,  Flying Saucers,  WebCams,  Smart Putty.
T H I N K G E E K . C O M       http://www.thinkgeek.com/sf/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.