EventX
Examples
This page will explain the rules and functions used on the demo page. To see the demo page and this page side-by-side, please load the demo frame.
OK/Cancel box for links with class="offsite"
A.offsite { onclick: return confirm("You are leaving this site. Do you want to continue?") }
This rule assigns behaviour to all anchor tags (links) of the "offsite" class. When these links are clicked, a dialogue box informs the user that they are leaving your site and asks if they want to continue. [See the example]
New browser window for links with class="popup"
A.popup { onclick: window.open(this.href); return false }
With the above rule, we cause all anchor tags of the "popup" class to open in a new browser window. [See the example]
Add text to links with class="external"
A.external { oninit: this.appendChild(document.createTextNode(" (external)")) }
Here we see something new—the oninit trigger. This is a special EventX trigger that fires when the document loads (see Using oninit). This script appends the text "(external)" to inform the user that the link goes to an external web page. [See the example]
We can achieve this same result more conveniently (but less "properly") via the .innerHTML property:
A.external { oninit: this.innerHTML += " (external)" }
The HTML is simply:
<a class="external" href="http://someaddress">Link</a>
(Replacing :hover with .hover)
A { onmouseover: this.className += " hover" }
A { onmouseout: this.className = this.className.replace(/[ ]?\\bhover\\b/, "") }
These two rules are used to replace the :hover pseudo-class. They assign onmouseover and onmouseout events to all of the anchor tags. The second rule uses the .replace() method to preserve any pre-existing classes—this is much safer than using A { onmouseout: this.className = "" }.
In our CSS file, we write .hover { color: red } assigning a style to the class.
True .hover class for TR tags
TR { onmouseover: this.className += " hover" }
TR { onmouseout: this.className = this.className.replace(/[ ]?\\bhover\\b/, "") }
Now that we've defined a style for the "hover" class, we can assign it to any element we want. This can also be accomplished in browsers with respectable CSS2 support (via the :hover pseudo-class), but most people aren't using these browsers yet. This is a cross-browser solution.
[See the example]
Note: One user has reported glitchy .className-assignment behaviour in Mac/IE5. If anyone knows more about this, please contact me.
Rollovers for IMG tags with class="roll"
IMG.roll { oninit: loadRollovers(this, "1", "2") }
IMG.roll { onmouseover: rollover(this) }
IMG.roll { onmouseout: rollout(this) }
We use oninit to initialize our loadRollovers() function. This function is included in the EventX demo script (demo.js) below the ruleSets list. It loads the rollover images we need and attaches them to the IMG object. The first parameter is the targeted element (this). The second and third parameters are the rollover suffixes.
In the above example, our suffix parameters are "1" and "2" because our rollover images are named demo1.gif and demo2.gif. If we wanted to use the naming scheme: demo_off.gif and demo_on.gif, we would initialize our rollovers with loadRollovers(this, "_off", "_on"). If we wanted to use the naming scheme: demo.gif and demo.roll.gif, we would initialize our rollovers with loadRollovers(this, "", ".roll").
And finally, the rollover() and rollout() functions swap the images as needed. [See the example]
Note: One user has reported that these rollover functions don't work in Mac/IE5. If anyone can confirm or refute this, please let me know.
Collapsed content
Expanding and collapsing content is very behaviour/presentation/structure-specific. In our example, we will use the following markup:
<div class="collapsed">
<h2>Question</h2>
<p>The answer to the question.</p>
</div>
We use CSS styles to hide the content we want to collapse but reveal the heading tag (so we have something to click on).
.collapsed * { display: none }
.collapsed H2 { display: block }
And now we assign an EventX rule:
DIV.collapsed { onclick: removeClass(this, "collapsed") }
When we click on the object, the "collapsed" class is removed—revealing the hidden content. [See the example]
Note: To assure that the collapsing content degrades gracefully, it's best to write the display: none style with JavaScript in the HEAD tag:
var css = '.collapsed * { display: none }';
document.write('<style type="text/css" media="screen"><!--' + css + '--></style>');
Folding List
UL.folding > LI { oninit: addClass(this, "unfolded") }
UL.folding > LI { onclick: toggleClass(this, "unfolded", "folded") }
This example uses the oninit trigger and introduces the use of child selectors (>). The child selectors limit our behaviour to the immediate child nodes of the UL element. It is important to remember that child selectors shouldn't be used in style sheet rules because of Internet Explorer's lack of support although they work fine with Explorer as part of EventX rules.
To keep our markup simple, we use a single class="folding" attribute in the UL (see the demo.html source). We use oninit to assign an unfolded class to all of the LI tags that are the direct children of the "folding" parent element.
The second rule swaps the "unfolded" class with "folded". And the CSS style of the "folded" class is set with LI.folded UL { display: none } to hide the content.
Now using two final rules, we explicitly set the cursor styles for these elements:
UL.folding > LI { oninit: this.style.cursor = "pointer" }
UL.folding > LI * { oninit: this.style.cursor = "auto" }
The markup used follows:
<ul class="folding">
<li>Group A [click me]
<ul>
<li>Earth</li>
<li>Moon</li>
<li>Sun</li>
</ul>
</li>
<li>Group B [click me]
<ul>
<li>dog</li>
<li>cat</li>
<li>bird</li>
</ul>
</li>
<li>Group C [click me]
<ul>
<li>monitor</li>
<li>keyboard</li>
<li>mouse</li>
</ul>
</li>
</ul>
Append last modified date
#last_modified { oninit: appendLastModified(this) }
When EventX initializes, the rule above accesses the file's last modified date and appends it as a child node to the element with the "last_modified" id. [See the example]
The following markup is used:
<div id="last_modified"> </div>
The non-breaking space ( ) prevents rendering bugs in certain browsers.
Insert Menu
#menu { oninit: insertMenu(this) }
This rule is similar to the previous one. It inserts a list of links when EventX starts. [See the example]
The markup used follows:
<div id="menu">
<a href="http://someaddress">Non-JavaScript Menu Page</a>
<!-- The contents of this DIV are completely
replaced by the insertMenu() function. -->
</div>
Form Validation
Form validation on the demo page uses two custom functions—validate() and checkForm().
Validation requires the use of pattern-matching regular expressions. If you need to learn about regular expressions please see: Google's search results, John Robert Morris' Regular Expression Guide and Jan Goyvaerts' excellent Regular Expression Tester.
The validate() function accepts two parameters—a form element and a regular expression literal. The element's value is compared against the regular expression. If a match is not found, the element is assigned the "invalid" class.
To check for a valid US ZIP-Code, we can use the following rules:
INPUT.zip_code { onkeyup: validate(this, /^\\d{5}(-\\d{4})?$/) }
INPUT.zip_code { onchange: this.onkeyup() }
Please notice that the special character for digits (\d) is escaped with a second backslash. This is necessary because EventX rules are stored as strings. Using the onkeyup handler lets us provide as-you-type validation. To validate information that has been cut-and-pasted, we also map the onchange handler to the .onkeyup() method. [See the examples]
Our arrangement considers a field valid unless it is explicitly flagged with the "invalid" class, therefore it is necessary to call validate() when the page loads. This is done with the oninit trigger:
INPUT { oninit: if (this.onkeyup) this.onkeyup(); !important }
And finally, we attach the checkForm() function:
FORM { onsubmit: return checkForm(this) }
The checkForm() function scans our form looking for "invalid" fields. When one is found the function...
- cancels submission of the form,
- notifies the user of an error,
- sets the browser focus to the offending field
- and flags it with an "alert" class.
When all of the fields are valid, checkForm() disables the submit button (to prevent multiple submissions) and submits the form. [See the example]
Understanding validate()
As mentioned before, the validate() function accepts form elements (INPUT, TEXTAREA or SELECT) and regular expression literals (/pattern/). Different types of input trigger different events. It is important that you use handlers that are appropriate for the input type.
If you miss a handler, validate() may not be able to appropriately assign or remove the "invalid" class. Please refer to the following table:
| Field type | Appropriate handler(s) |
|---|---|
<input type="text"> |
onkeyup and onchange |
<input type="password"> |
onkeyup and onchange |
<input type="file"> |
onkeyup and onchange |
<input type="checkbox"> |
onclick |
<input type="radio"> |
onclick |
<textarea> |
onkeyup and onchange |
<select> |
onclick and onblur |
You can automatically copy functions to the necessary handlers when the page loads:
INPUT { oninit: if (this.onkeyup) this.onchange=this.onkeyup; this.onclick=this.onkeyup; !important }
TEXTAREA { oninit: if (this.onkeyup) this.onchange=this.onkeyup; !important }
SELECT { oninit: if (this.onclick) this.onblur=this.onclick; !important }
And trigger them to mark the invalid fields:
INPUT { oninit: if (this.onkeyup) this.onkeyup(); !important }
TEXTAREA { oninit: if (this.onkeyup) this.onkeyup(); !important }
SELECT { oninit: if (this.onclick) this.onclick(); !important }
Note: For check boxes and radio buttons, the regular expression is disregarded (any choice will validate). For drop-down boxes, the regular expression is checked against the value of the selected option.