DOM Extensions

Last updated: October 15th, 2008

I regularly use JavaScript to manipulate the DOM. To that end, I've written a small library which extends DOM nodes with some handy methods, such as getElementsByClassName(), hasClass(), addClass(), deleteClass() and a few others. It also has a trim() method to trim white space off strings, and an each() method that passes all items in an array to a callback function.

This library was written for a small project where something like jQuery would be too much overkill. It will not work in Internet Explorer, any version. DOM nodes are not native objects in that browser, so they cannot be prototyped.

Source code

Below is the the source code of the library.

  1 /*
  2  * Some extensions to the Document Object Model + Array.each() + String.trim()
  3  *
  4  * Copyright (c) Colin Helvensteijn 2008
  5  */
  6 
  7 
  8 
  9 // figure out whether or not we're dealing wit IE
 10 var isIE =  /msie/.test(navigator.userAgent.toLowerCase()) && !/opera/.test(navigator.userAgent.toLowerCase());
 11 
 12 // IE doesn't understand most of what we're doing below
 13 if(!isIE)
 14 {
 15         // get DOM constructors
 16         var Document = document.constructor, HTMLElement = document.createElement("x").constructor;
 17 
 18         // if no native getElementsByClassName exists, implement our own
 19         if(!Document.prototype.getElementsByClassName)
 20         {
 21                 /*
 22                  * getElementsByClassName()
 23                  *
 24                  * Returns an array with all nodes in Document or HTMLElement with class searchClass
 25                  */
 26                 Document.prototype.getElementsByClassName = HTMLElement.prototype.getElementsByClassName = function(searchClass)
 27                 {
 28                         var elemList = this.getElementsByTagName('*'), ret = new Array();
 29 
 30                         for(var i = 0, x = 0, len = elemList.length; i < len; i++)
 31                                 if(elemList[i].hasClass(searchClass))
 32                                         ret[x++] = elemList[i];
 33 
 34                         return ret;
 35                 };
 36         }
 37         // if a native getElementsByClassName exits, convert its output to an array
 38         else
 39         {
 40                 // we don't want to overwrite the native implementation
 41                 Document.prototype._getElementsByClassName = Document.prototype.getElementsByClassName;
 42                 HTMLElement.prototype._getElementsByClassName = HTMLElement.prototype.getElementsByClassName;
 43 
 44                 /*
 45                  * getElementsByClassName()
 46                  *
 47                  * Converts the nodelist returned by the native implementation to an Array object
 48                  */
 49                 Document.prototype.getElementsByClassName = HTMLElement.prototype.getElementsByClassName = function(searchClass)
 50                 {
 51                         var nodeList = this._getElementsByClassName(searchClass), ret = new Array();
 52 
 53                         for(var i = 0, x = 0, len = nodeList.length; i < len; i++)
 54                                 ret[x++] = nodeList[i];
 55 
 56                         return ret;
 57                 }
 58         }
 59 
 60         if(!HTMLElement.prototype.hasClass)
 61         {
 62                 /*
 63                  * hasClass()
 64                  *
 65                  * Returns true if HTMLElement has class searchClass, false if not
 66                  */
 67                 HTMLElement.prototype.hasClass = function(searchClass)
 68                 {
 69                         if(this.className)
 70                         {
 71                                 var classList = this.className.split(' ');
 72 
 73                                 for(var i = 0, len = classList.length; i < len; i++)
 74                                         if(classList[i] == searchClass)
 75                                                 return true;
 76                         }
 77 
 78                         return false;
 79                 };
 80         }
 81 
 82         if(!HTMLElement.prototype.addClass)
 83         {
 84                 /*
 85                  * addClass()
 86                  *
 87                  * Adds class newClass to HTMLElement
 88                  */
 89                 HTMLElement.prototype.addClass = function(newClass)
 90                 {
 91                         this.className = (this.className) ? this.className + ' ' + newClass : newClass;
 92                 };
 93         }
 94 
 95         if(!HTMLElement.prototype.removeClass)
 96         {
 97                 /*
 98                  * removeClass()
 99                  *
100                  * Removes class oldClass from HTMLElement
101                  */
102                 HTMLElement.prototype.removeClass = function(oldClass)
103                 {
104                         if(this.className)
105                         {
106                                 var classList = this.className.split(' '), newClassName = new String();
107 
108                                 for(var i = 0, len = classList.length; i < len; i++)
109                                         if(classList[i] != oldClass)
110                                                 newClassName += classList[i] + ' ';
111 
112                                 this.className = newClassName.trim();
113                         }
114                 };
115         }
116 
117         if(!HTMLElement.prototype.toggleClass)
118         {
119                 /*
120                  * toggleClass()
121                  *
122                  * Toggles class searchClass on HTMLElement
123                  */
124                 HTMLElement.prototype.toggleClass = function(searchClass)
125                 {
126                         this.hasClass(searchClass) ? this.removeClass(searchClass) : this.addClass(searchClass);
127                 };
128         }
129 
130         if(!HTMLElement.prototype.empty)
131         {
132                 /*
133                  * empty()
134                  *
135                  * Empties the HTMLElement node
136                  */
137                 HTMLElement.prototype.empty = function()
138                 {
139                         while(this.firstChild)
140                                 this.removeChild(this.firstChild);
141                 };
142         }
143 
144         if(!HTMLElement.prototype.destroy)
145         {
146                 /*
147                  * destroy()
148                  *
149                  * Destroys the HTMLElement node
150                  */
151                 HTMLElement.prototype.destroy = function()
152                 {
153                         if(this.parentNode)
154                                 this.parentNode.removeChild(this);
155                 };
156         }
157 
158         if(!Array.prototype.each)
159         {
160                 /*
161                  * each()
162                  *
163                  * Calls function callback for each index in the array
164                  */
165                 Array.prototype.each = function(callback)
166                 {
167                         var thisObj = arguments[1];
168 
169                         if(typeof callback != "function")
170                                 throw new TypeError();
171 
172                         for(var i = 0, len = this.length; i < len; i++)
173                                 if(i in this)
174                                         callback.call(thisObj, this[i], i, this);
175                 };
176         }
177 
178         if(!String.prototype.trim)
179         {
180                 /*
181                  * trim()
182                  *
183                  * Trims any leading or trailing white space from a string
184                  */
185                 String.prototype.trim = function()
186                 {
187                         return this.replace(/^\s+|\s+$/, '');
188                 };
189         }
190 }
191 
192 /*
193  * $()
194  *
195  * Shortcut for getElementById()
196  */
197 if(window.$) var _$ = $;
198 var $ = function(searchId)
199 {
200         // if this is the window object, use document instead
201         return document.getElementById(searchId);
202 };
203 
204 /*
205  * $$()
206  *
207  * Shortcut for getElementsByClassName()
208  */
209 if(window.$$) var _$$ = $$;
210 var $$ = function(searchClass)
211 {
212         // if this is the window object, use document instead
213         return document.getElementsByClassName(searchClass);
214 };
215