You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Steve K <sh...@mm.st> on 2003/11/22 21:17:55 UTC
Keeping JavaScript out of the HTML (was Re: Refactoring woody styling)
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:field[@style-hint = '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>