I'm a ex-barman that became a web developer. I like what I do, but what I really love is a good beer, portuguese food, my football (soccer for the US people) team, F.C.Porto, and of course, my biggest love, my son, Tiago.


Subscribe Now!

...with web-based news readers. Click your choice below:

addtomyyahoo4Subscribe in NewsGator OnlineAdd to My AOL
Subscribe in RojoSubscribe with BloglinesAdd to netvibes
Add to Google

...with other readers:

original feed View Feed XML

 

SEARCH

Google
This Blog:


NAVIGATION

  • Polls

    What do you think about the upcoming changes in Javascript?

    View Results

    Loading ... Loading ...
  •  

  • Mini Wiki - Click a word and view/add/edit a definition

     
  •  

     

  • Archives

  • Meta

2007 | Content: HRCerqueira’s Blog | Design: Julian Klewes | Licence: CC 3.0

         

 

Update: I re-wrote them (again). I can find the new methods here. I created a new post instead of just re-writing this for historical reasons. Sorry for the inconvinience.

I’ve just recently wrote a post called Javascript Tools Collection, where I revealed (I like this word, looks like that’s something secret ;-) ) my favourite javascript tools. Probably, the ones I use most are SACK (for ajax requests), and dom related functions. And I just started a new project heavily based on dom handling, so I decided to re-design my super ultra mega dom manipulation kit. My idea was that instead of having global functions to do the handling of the elements, I would complement the methods that are already there in the browser, prototyping some new methods, this way, I get a more elegant approach, and much more object oriented flavoured. I even made some rudimentary performance tests and found out that this way of doing things is between 5 to 10 % faster, depending on the cases. So, here’s wath I have now:

  • Event attacher
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    Object.prototype.addEvent = function(evtType, func) {
       if (this.addEventListener) { //gecko
          this.addEventListener(evtType, func, true);
       } else if (this.attachEvent) { //ie
          this.attachEvent('on' + evtType, func);
       } else { //all the others
          this['on' + evtType] = func;
       }
    }
  • Class handling
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    Object.prototype.hasClass = function(className) {
       var pattern = new RegExp('(^|\\s)' + className + '(\\s|$)'); //use this regexp
       return pattern.test(this.className); //to check for the class
    }
     
    Object.prototype.addClass = function(className) {
       if (!this.hasClass(className)) { //if the class isn't there already
          this.className += (' ' + className); //append it to the end of the class list
       }
    }
     
    Object.prototype.removeClass = function(className) {
       var pattern = new RegExp('(^|\\s)' + className + '(\\s|$)'); //use this regexp
       this.className = this.className.replace(pattern, ' '); //to make a search and replace by a blank space
    }
  • GetElementsByClass
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    
    Object.prototype.getElementsByClass = function (className, tag) {
       var returnArray = [];
       tag = tag || '*'; //if tag is defined, use that for a more specific search, otherwise search in all tags
     
       var els = this.getElementsByTagName(tag); //get the elements
     
       for (var i = 0; i < els.length; i++) { //run the elements
          if (els[i].hasClass(className)) { //if a element implements that class
             returnArray.push(els[i]); //append it to the return array
          }
       }
     
       return returnArray;
    }
  • Element attachers. Note that for simple appending there is already a function in javascript called appendChild, that does is job and is cross browser, so there’s no need to re-invent the well here.
    42
    43
    44
    45
    46
    47
    48
    49
    50
    
    Object.prototype.appendAfter = function(newElement) {
       //call insertBefore method on parent node to insert the new element before the element next to this
       this.parentNode.insertBefore(newElement, this.nextSibling);
    }
     
    Object.prototype.appendBefore = function(newElement) {
       //call insertBefore method on parent node to insert the new element before this
       this.parentNode.insertBefore(newElement, this);
    }

    For element replacements there is the function replaceChild(newElement, oldElement).

  • Element removal
    I know that for this job there is already a function called removeChild, but because our little friend memory leaking bug in IE, we need a little retouching.

    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    
    Object.prototype.removeElement = function(oldElement) {
       var childElements = oldElement.getElementsByTagName('*');
     
       for (var i = 0; i < childElements.length; i++) { //purge all elements contained in the element to remove
          purge(childElements[i]);
       }
     
       purge(oldElement); //purge the element to remove
       this.removeChild(oldElement); //remove it
     
       //function that came from Douglas Crockford site, that removes all the event handlers from de elements
       function purge(d) {
          var a = d.attributes, i, l, n;
          if (a) {
              l = a.length;
              for (i = 0; i < l; i += 1) {
                  n = a[i].name;
                  if (typeof d[n] === 'function') {
                      d[n] = null;
                  }
              }
          }
          a = d.childNodes;
          if (a) {
              l = a.length;
              for (i = 0; i < l; i += 1) {
                  purge(d.childNodes[i]);
              }
          }
       }
    }
  • Element creation
    For that, I still use the $new function I’ve showed in the other post, because unless we’re creating and appending an element at the same time, it’s not very logic to assign this task to elements (this sentence doesn’t sound very well on my head). But I had to make a small modification, because our prototype methods are going to be available in all objects, even if we do something like this var obj = {}, and the $new function has an object as an argument:

    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    
       function $new(eltype, attributes, content) {
           var newElement = document.createElement(eltype);
     
           if (typeof(attributes != 'undefined')) { 
               if (typeof(attributes) == 'object') {
                   for (name in attributes) {
                      if (typeof(attributes[name] == 'string')
                          newElement.setAttribute(name, attributes[name]);
                   }
     
                   if (typeof(content != 'undefined')) 
                      newElement.innerHTML = content;
               } else {
                   newElement.innerHTML = attributes;
               }
           } 
     
            return newElement;
       }

    I also still use the dollar sign ($) function to call for elements by his id.

  • Usually, developers tend to create functions that either accept a single element or an array of elements, or even just a element id. I think that in an extensive program this can become a bit confusing, so, if I want to remove a certain element and I only know it’s id and parent node, I use parentNode.removeElement($('elementId')), using the dollar sign function, instead of making the function check if the parameter is a string or an element and then act accordingly to that. For multi element handling, I like to use function mapping, using a function like this:

    1
    2
    3
    4
    5
    
    //call the function having each element of the array as parameter
    Array.prototype.map = function(f) {
      for (i = 0; i < this.length; i++)
        f(this[i]);
    }

    So, if I want to remove multiple elements in an array, I use theArray.map(parentNode.removeElement). This way, every time I look to the code and I see the removeElement method, I know if I’m removing a single element, a single element based on it’s id, or multiple elements in a array.

     

    I intend to make a post demonstrating these methods creating some kind of widget. So, stay tuned…

     

    Cheers,

     

    Hernâni




    Name (required)

    Email (required)

    Website

    XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>

    Feel free to leave a comment

#