Prototype Tutorial #1:
HTML Element Selection and Higlighting
Author: Matt Howey
What is Prototype? According to the official Prototype Website:
"Prototype is a JavaScript Framework
that aims to ease development of dynamic web applications."
(see: http://www.prototypejs.org/)
Another explanation of Prototype would be that it is an extension of the JavaScript
programming language beyond it's native functions. Prototype provides a means to accomplish
otherwise ponderous programming tasks with elegance and speed. The tutorial below illustrates
this characteristic by comparing how to create a simple user interface widget in Prototype
versus written verbosely via standard JavaScript.
When would I not want to use Prototype? This one is easy. If you are trying
to create the lightweight of lightweight web applications and only need a limited
set of functionality, you may be better off scripting your own functions. Of course, as time
goes on and you wish you had access to all that Prototype has to offer, you may rethink this approach.
What's the overhead? As of this writing, the standard "prototype.js" file (the
only thing you need to work with Prototype!) is about ~96k. Of course, an externally
included JavaScript file is cached for subsequent loads, so this may not be much of
a concern - especially considering the adoption of ultra-broadband (cable, fiber, etc) services in recent
years.
Quick Start:
- Download the latest version of the script: http://www.prototypejs.org/download
- Save the "prototype.js" file that you downloaded where your web app will be able to access it.
- Make sure you include the "prototype.js" file in the head of your document like this:
INCLUDING PROTOTYPE.JS IN THE HEAD OF YOUR DOCUMENT
<head>
<title>Prototype Example Page</title>
<script type="JavaScript" src="prototype.js"></script>
</head>
And without further ado, here's the tutorial...
HTML Element Selection and Highlighting
Comparing Prototype to Standard JavaScript
The examples below will show how Prototype makes changing the className of
a particular HTML element much simpler by doing the heavy lifting for the
developer. By using the Prototype Framework, we can simplify the way we code
interactions with the DOM. This example addresses the challenge
of working with the className property - more specifically, how to deal
with manipulating the class attribute (i.e. class="classOne classTwo")
which MAY have multiple CSS classes assigned to it - as this is allowed in most
modern browsers. For this reason, we can't just re-set the className property because
we would risk overwriting classes that were already assigned to that element.
To Start: Let's look at the user interface component (see: "example widget" below)
that we will use in our comparison. Go ahead, try clicking both buttons.
The Example Widget: Below is the widget created with the HTML code shown below.
When you click either button, the text will highlight in yellow. When you
click either button again, it will be un-highlighted. This is done by replacing the
CSS class that is currently being used by the <DIV> that wraps the text. Take
note that there are two separate functions - one for each button - one using Prototype
specific methods, and the other using "custom" functions.
EXAMPLE WIDGET
The HTML: The code below is the raw HTML that will produce the simple user-interface
widget as shown in the box above. Although this widget is purely for demonstration purposes,
you can probably imagine many ways that a component like this could be useful in your
user-interface programming adventures. For instance, think of the way the Google
Toolbar highlights the text that you just searched for - they highlight it.
THE HTML CODE
<div id="myDiv" style="padding:10px;">
<b>Click the button below to highlight
and un-highlight this text.<b>
</div>
<input type="button"
onclick="highlight('myDiv');"
value="TOGGLE PROTOTYPE" />
<input type="button"
onclick="highlightStandard('myDiv');"
value="TOGGLE STANDARD" />
The CSS
CSS STYLES FOR "active" AND "notactive"
<style type="text/css">
.active { background:yellow; }
.notactive { background:none; }
</style>
Pseudo Code
PSEUDOCODE FOR TOGGLE HIGHLIGHTING FUNCTIONALITY
IF ELEMENT CLASS IS EMPTY
SET CLASS TO "ACTIVE"
ELSE IF ELEMENT CLASS CONTAINS "ACTIVE"
REMOVE CLASS "ACTIVE"
ADD CLASS "NOTACTIVE"
ELSE IF ELEMENT CLASS IS "NOTACTIVE"
REMOVE CLASS "NOTACTIVE"
ADD CLASS "ACTIVE"
ELSE IF ELEMENT CLASS DOESN'T CONTAIN "ACTIVE" OR "NOTACTIVE" AND ISN'T EMPTY
ADD CLASS "ACTIVE"
The Prototype Approach
Prototype simplifies the way we can approach this problem because it simplifies
the manipulation of a DOM element which has multiple classes assigned. Here is
an example of an element with 2 different classes assigned to it:
EXAMPLE: MULTIPLE CLASSES ON AN ELEMENT
<div class="classOne classTwo"><div>
In the function definition below we are using 4 particular functions of the Prototype
Framework to simplify the JavaScript that is necessary to achieve our objective with the
widget. These four methods are:
- the $() method
- the hasClassName() method
- the removeClassName() method
- the addClassName() method
THE PROTOTYPE APPROACH
function highlight(elementId) {
// NOTE:
// $(elementId) is equal to document.getElementById(elementId)
// $() is a Prototype specific method
var theElement = $(elementId);
if(theElement.hasClassName('active')) {
theElement.removeClassName('active');
theElement.addClassName('notactive');
} else if(theElement.hasClassName('notactive')) {
theElement.removeClassName('notactive');
theElement.addClassName('active');
} else {
theElement.addClassName('active');
}
}
The Standard JavaScript Approach
Although the above seems like a fairly simple task (especially when using
Prototype!), it's not nearly as simple when using standard JavaScript. Why? Because
in order to manipulate the class attribute, we would need to code additional functions for
dealing with a class attribute list by iterating through it manually in some manner and
altering it. Luckily, the Prototype Framework offers functions such as "addClassName"
and "removeClassName" which greatly simplify the process.
We will need 3 additional functions, on top of our main highlighting toggle function. to accomplish this task. Essentially,
we are re-creating functions that are already built into the Prototype
Framework. The "standard javascript approach" shown below is one of many ways
to achieve our desired outcome (highlighting and un-highlighting the test DIV).
Here are the procedures we need to accomplish...
- First, we have to check if the class "active" or "notactive" already
exists in the objects class attribute. For this we created the hasClass function - which
accomplishes the same thing as Prototype's hasClassName function. For
example, we're checking the class attribute for the word "active" using a
regular expression match: class="classOne classTwo active"
- Second, if the class we're looking for already exists in the object,
we need to remove it and replace it with the new class to change it's appearance.
For this we created the removeClass function - which
accomplishes the same task as Prototype's removeClassName function. For
example, if we had the class attribute as shown in #1, the new class definition
will look like this after removing the matched class: class="classOne classTwo"
- Finally, after removing the old class, we have to add the new class to
the objects' class attribute. For this we have created the addClass
function - which accomplishes the same thing as Prototype's addClassName
function. For example, the new class attribute for the object we are
manipulating would look like this: class="classOne classTwo notactive"
As you can see, we accomplish the same thing as with the Prototype approach,
but the amount of code needed, as well as the amount of time to code it, is
substantially increased. This is a good example of how Prototype makes coding
more enjoyable and faster! On top of that we protect against possible function
duplication
The example below is only one way in which we could accomplish the
task. For instance, instead of using regular expression matching, we could
read the class attributes into an array using the JavaScript
split() function (after all, the class attributes are just a space-delimited
list), then we can manipulate the array to build a new className
property that can be assigned to the element.
THE STANDARD JAVASCRIPT APPROACH
function hasClass(ele,cls) {
return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}
function addClass(ele,cls) {
if (!this.hasClass(ele,cls)) ele.className += " "+cls;
}
function removeClass(ele,cls) {
if (hasClass(ele,cls)) {
var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
ele.className=ele.className.replace(reg,' ');
}
}
function highlightStandard(elementId) {
var elementId = document.getElementById(elementId);
if(hasClass(elementId,'notactive')) {
removeClass(elementId,'notactive');
addClass(elementId,'active');
} else if(hasClass(elementId,'active')) {
removeClass(elementId,'active');
addClass(elementId,'notactive');
} else {
addClass(elementId,'active');
}
}
|