I'd like to post some functions that proved useful for me.
apply a function to a HTMLCollection (node-list)
note: a HTMLCollection* (or NodeList**) is the type of object you get when you call the function getElementsByNa me(), getElementsByTa gName(), getElementsByCl assName()
originating from MDC's Array.forEach() code
* the HTML interface of such an object (only works in (X)HTML files)
** the DOM interface of such an object (works also on XML files)
example usage
would produce:
Hamlet said «To die or not to die …».
assign an Event for each element of a node-list
note: the used addEvent() function is explained below, but you can use any addEvent() function you want (just change the call)
example usage:
converting addEvent(elemen t, …) to element.addEven t(…)
this is just for convenience to be able to call addEvent() in the same manner as addEventListene r().
a modification of addEvent() where you can pass parameters directly (needless to say that you can do this also with addEventForEach ())
one addEvent() function put into an object
(to prevent the pollution of the global scope with functions that should be treated private*)
* JavaScript (in contrast to PHP and other OOP capable languages) does not know the concept of private properties/methods
making extending an object (OOP) easy
create a new child element (if innerHTML should fail or you want to code standard compliant)
apply a function to a HTMLCollection (node-list)
note: a HTMLCollection* (or NodeList**) is the type of object you get when you call the function getElementsByNa me(), getElementsByTa gName(), getElementsByCl assName()
originating from MDC's Array.forEach() code
* the HTML interface of such an object (only works in (X)HTML files)
** the DOM interface of such an object (works also on XML files)
Code:
// Firefox does not allow prototyping into the NodeList or HTMLCollection interface
// so their parent object has to be used
Object.prototype.applyForEach = function(fn)
{
if (!(fn instanceof Function)) {
throw new TypeError("passed parameter is not a function.");
}
var args = Array.prototype.slice.call(arguments, 1);
for (var i = this.length; i--;) {
if (i in this) {
fn.apply(this[i], args);
}
}
}
Code:
// wrap a text in two given strings (just an example, it could be anything)
function foo(sign1, sign2)
{
this.textContent = sign1 + this.textContent + sign2;
}
// wrap all quotes in french quotation marks
document.getElementsByTagName("quote").applyForEach(foo, "«", "»");
Code:
<p>Hamlet said <quote>To die or not to die …</quote>.</p>
Hamlet said «To die or not to die …».
assign an Event for each element of a node-list
note: the used addEvent() function is explained below, but you can use any addEvent() function you want (just change the call)
Code:
Object.prototype.addEventForEach = function(type, fn, cpt)
{
if (!(fn instanceof Function))
throw new TypeError("passed parameter is not a function.");
}
for (var i = this.length; i--;) {
if (i in this) {
Events._addEvent(this[i], type, fn, cpt); // [I]use[/I] addEvent(this[i], type, fn, cpt); [I]for the generic addEvent() function[/I]
}
}
}
Code:
// again an example function, alert the elements title attribute
function show()
{
if (this.title) alert(this.title);
}
// trigger an alert by clicking on any table cell
document.getElementsByTagName("td").addEventForEach("click", show);
Code:
<table>
<tr>
<td title="english">green</td>
<td title="german">grün</td>
<td title="french">verde</td>
</tr>
</table>
converting addEvent(elemen t, …) to element.addEven t(…)
this is just for convenience to be able to call addEvent() in the same manner as addEventListene r().
Code:
HTMLElement.prototype.addEvent = function(type, fn, capture)
{
Events._addEvent(this, type, fn, capture);
}
Code:
Element.prototype.addEvent = function(type, fn, capture)
{
if (!(fn instanceof Function)) {
throw new TypeError("Function expected!");
}
if (arguments.length < 4) {
Events._addEvent(this, type, fn, capture);
} else {
var args = Array.prototype.slice.call(arguments, 3);
var tmpfn = function() {
fn.apply(this, args);
}
Events._addEvent(this, type, tmpfn, capture);
}
}
Code:
// calling foo("bar") on click
document.getElementById("test").addEvent("click", foo, false, "bar");
(to prevent the pollution of the global scope with functions that should be treated private*)
* JavaScript (in contrast to PHP and other OOP capable languages) does not know the concept of private properties/methods
Code:
/**
* Crossbrowser event handling functions.
*
* A set of functions to easily attach and detach event handlers to HTML elements.
* These functions work around the shortcomings of the traditional method ( element.onevent = function; )
* where only 1 handler could be attached for a certain event on the object, and mimic the DOM level 2
* event methods addEventListener and removeEventListener for browsers that do not support these
* methods (e.g. Internet Explorer) without resorting to propriety methods such as attachEvent and detachEvent
* that have a whole set of their own shortcomings.
* Created as an entry for the 'contest' at quirksmode.org:
* http://www.quirksmode.org/blog/archives/2005/09/addevent_recodi.html
*
* @author Tino Zijdel ( crisp@xs4all.nl )
* @version 1.2
* @date 2005-10-21
*/
Events = function() {
/**
* [private] array_search
*
* Searches the array for a given value and returns the (highest) corresponding key if successful, -1 if not found.
*
* @param val The value to search for.
* @param arr The array to search in.
* @return (mixed) array index of val.
*/
function array_search(val, arr)
{
var i = arr.length;
while (i--) {
if (arr[i] && arr[i] === val) break;
}
return i;
}
/**
* [private] IEEventHandler
*
* IE helper function to execute the attached handlers for events.
* Because of the way this helperfunction is attached to the object (using the DOM level 0 method)
* the 'this' keyword will correctely point to the element that the handler was defined on.
*
* @param e (optional) Event object, defaults to window.event object when not passed as argument (IE).
* @return (mixed)
*/
function IEEventHandler(e)
{
e = e || window.event;
var evTypeRef = '__' + e.type, retValue = true;
for (var i = 0, j = this[evTypeRef].length; i < j; i++) {
if (this[evTypeRef][i]) {
if (Function.call) {
retValue = this[evTypeRef][i].call(this, e) && retValue;
}
else {
this.__fn = this[evTypeRef][i];
retValue = this.__fn(e) && retValue;
}
}
}
if (this.__fn) {
try {
delete this.__fn;
}
catch(e) {
this.__fn = null;
}
}
return retValue;
}
return {
/**
* [public] addEvent
*
* Generic function to attach event listeners to HTML elements.
* This function does NOT use attachEvent but creates an own stack of function references
* in the DOM space of the element. This prevents closures and therefor possible memory leaks.
* Also because of the way the function references are stored they will get executed in the
* same order as they where attached - matching the behavior of addEventListener.
*
* @param obj The object to which the event should be attached.
* @param evType The eventtype, eg. 'click', 'mousemove' etcetera.
* @param fn The function to be executed when the event fires.
* @param useCapture (optional) Whether to use event capturing, or event bubbling (default).
* @return (void)
*/
_addEvent : function(obj, evType, fn, useCapture)
{
if (!useCapture) useCapture = false;
if (obj.addEventListener) {
obj.addEventListener(evType, fn, useCapture);
}
else {
if (useCapture) {
alert('This browser does not support event capturing!');
}
else {
var evTypeRef = '__' + evType;
if (obj[evTypeRef]) {
if (array_search(fn, obj[evTypeRef]) > -1) return;
}
else {
obj[evTypeRef] = [];
if (obj['on'+evType]) {
obj[evTypeRef][0] = obj['on'+evType];
}
obj['on'+evType] = IEEventHandler;
}
obj[evTypeRef][obj[evTypeRef].length] = fn;
}
}
},
/**
* [public] removeEvent
*
* Generic function to remove previously attached event listeners.
*
* @param obj The object to which the event listener was attached.
* @param evType The eventtype, eg. 'click', 'mousemove' etcetera.
* @param fn The listener function.
* @param useCapture (optional) Whether event capturing, or event bubbling (default) was used.
* @return (void)
*/
_removeEvent : function(obj, evType, fn, useCapture)
{
if (!useCapture) useCapture = false;
if (obj.removeEventListener) {
obj.removeEventListener(evType, fn, useCapture);
}
else {
var evTypeRef = '__' + evType;
if (obj[evTypeRef]) {
var i = array_search(fn, obj[evTypeRef]);
if (i > -1) {
try {
delete obj[evTypeRef][i];
}
catch(e) {
obj[evTypeRef][i] = null;
}
}
}
}
},
/**
* [public] loading
*
* simplifies the window.onload calls
*
* @param callback the function called onload
* @return (void)
*/
loading : function(callback)
{
Events._addEvent(window, "load", callback);
}
};
}();
Code:
// by Gavin Kistner
Function.prototype.extend = function(parentClassOrObject)
{
if (parentClassOrObject.constructor instanceof Function) {
//Normal Inheritance
this.prototype = new parentClassOrObject;
this.prototype.constructor = this;
this.prototype.parent = parentClassOrObject.prototype;
}
else {
//Pure Virtual Inheritance
this.prototype = parentClassOrObject;
this.prototype.constructor = this;
this.prototype.parent = parentClassOrObject;
}
return this;
}
Code:
// use like this
function theParent() { // code comes here }
function theChild() { // code comes here }
theChild.extend(theParent);
// now any instance of theChild can use the code from theParent
Code:
// uses DOM-level-1 for backward compatibility
HTMLElement.prototype.appendCustomElement = function(name, text, attr)
{
var CE = document.createElement(name);
var TN = document.createTextNode(text);
CE.appendChild(TN);
if (attr) {
for (var j in attr) {
// if you extended the Object interface:
if ("function" == typeof attr[j]) continue;
var CA = document.createAttribute(j);
CA.nodeValue = attr[j];
CE.setAttributeNode(CA);
}
}
this.appendChild(CE);
return CE;
}
Code:
// use like this
document.getElementById("test").appendCustomElement("a", "next page", {href: "next.html", class: "sidebar"});
// would result in
<div id="test">
<a href="next.html" class="sidebar">next page</a>
</div>