If the goal of Woody is to include some rich client side functionality, I would like to throw my two cents in with a little experience I've had implementing something similar. I created a form framework that required some support for non-standard HTML widgets, for example, a multi-select drop down (MSDD). I also wanted to keep the javascript code as separate as possible so it could be easily maintained, and make it easily reusable so having many MSDDs on one page would be trivial to do.

What I wound up doing is implementing the controller code for the MSDD as a JavaScript class. The class would take references to the three elements participating in the UI of the MSDD (a select box to handle the actual selection, a text input field to show the comma-separated list of selected items, and a button to toggle the appearance of the select box). It would then dynamically attach the various event handlers to the UI elements to methods in the class. This way the controller code remains loosely coupled with the HTML -- there is no need to attach onXXX attributes to the HTML elements. This also allowed me to keep the class in a separate source file to be included via XSLT or a client side <script> tag.

In retrospect, one thing I would probably do differently is have the javascript dynamically create the additional UI elements needed for the display of the MSDD (text field, button). This way a browser that does not support javascript would only see the select field and not the additional elements needed to produce the MSDD effect.

So the form's xslt would have to do 2 things. First, see if there are any MSDDs in the form, and if so, include the MSDD class either directly or produce a <script> tag that includes it:

** Note that these code samples taken from the XSLT of my custom form stuff and are not intended to have anything to do with woody **

<xsl:if test="form:fields/form:[EMAIL PROTECTED] = 'multidropdown']">
    <xsl:call-template name="multidropdown_js"/>
</xsl:if>

Second, it needs to create an instance of the class for each use of the MSDD. So the following code would have to be generated for each MSDD element in a place that would be executed on load:

<xsl:for-each select="form:fields/form:field">
    <xsl:if test="@style-hint = 'multidropdown'">

var <xsl:value-of select="@name"/>_multidropdown = new Multidropdown(
    document.getElementById("<xsl:value-of select="@name"/>_input"),
    document.getElementById("<xsl:value-of select="@name"/>_button"),
    document.getElementById("<xsl:value-of select="@name"/>")
);
    </xsl:if>
</xsl:for-each>

And finally, I'll leave you with the implementation of the MSDD class. I hope that this can be of use to someone :)

<xsl:template name="multidropdown_js">
<![CDATA[
function Multidropdown(p_input, p_button, p_select) {

    var input  = p_input;
    var button = p_button;
    var select = p_select;

    this.visible = false;
    this.that    = this;

var input_position = getAbsolutePosition(input);

// select.style.display = "none";
select.style.top = input_position[1] + input.offsetHeight + input.style.borderWidth;
select.style.left = input_position[0];
select.style.width = input.offsetWidth;


    this.hide = function() {
        var that = this.that;
        select.style.display = "none";
        that.visible = false;
    }

    this.show = function() {
        var that = this.that;
        select.style.display = "block";
        select.focus();
        that.visible = true;
    }

    this.toggle = function() {
        var that = this.that;
        if(!that.visible)
            that.show();
        else
            that.hide();
    }

    this.update = function() {
        var a = [];
        var o = select.options;
        for(var i = 0; i < o.length; i++)
            if(o[i].selected)
                a.push(o[i].text);
        input.value = a.join(", ");
    }

    this.selectOnBlur = function(e) {
        var that = this.that;
        that.hide();
        that.update();
    }

    this.buttonOnClick = function(e) {
        var that = this.that;
        that.toggle();
    }

    this.selectOnChange = function() {
        var that = this.that;
        that.update();
    }

    button.that = this;
    button.onclick = this.buttonOnClick;

    select.that = this;
    select.onblur = this.selectOnBlur;

// select.onchange = this.selectOnChange;

    this.update();
}
]]>
</xsl:template>



Reply via email to