DaveJays Blog

Flickr

Twitter

Authentic Jobs - Come in, we’re hiring

Full-time and freelance job opportunities

Post a job and reach web professionals everywhere.

image

Using Javascript to Add Extra Markup Around a Tag

I've been working on a CSS technique that requires a fair amount of presentational markup for it to work properly. Specifically, I need an IMG tag with a specific class name to be surrounded with a parent div, and four child divs inserted within it.

I hate presentational markup in my HTML if I can avoid it, but for the effect I want to achieve it's essential. Using Javascript to put the code in keeps the original HTML clean and accessible, but adds a layer of separation between the content and the presentation. Essentially all that CSS does.

So basically I need to get this:

  1. <div img src="somegraphic.jpg" alt="graphic" class="imgType" width="300" height="300" />

to look like this.

  1. <div class="parent">
  2. <div img src="somegraphic.jpg" alt="graphic" class="imgType" width="300" height="300" />
  3. <div class="child1"><div>
  4. <div class="child2"><div>
  5. <div class="child3"><div>
  6. <div class="child4"><div>
  7. </div>
  8. </div>

getElementsByClassName

So I need to go through the html document, find all the images with the class "imgType" and add the appropriate tags around it. First I need a method of cycling through all the elements with a particular class name - the getElementsByClassName function that javascript should have. I found one written by "lobo235" that seems to do the trick nicely.

  1. document.getElementsByClassName = function(clsName){
  2. var retVal = new Array();
  3. var elements = document.getElementsByTagName("*");
  4. for(var i = 0;i < elements.length;i++){
  5. if(elements[i].className.indexOf(" ") >= 0){
  6. var classes = elements[i].className.split(" ");
  7. for(var j = 0;j < classes.length;j++){
  8. if(classes[j] == clsName) retVal.push(elements[i]);
  9. }
  10. }
  11. else if(elements[i].className == clsName) retVal.push(elements[i]);
  12. }
  13. return retVal;
  14. }

This will find all the elements on the page marked with the specified class name and return them to you in the form of an array, which you can then cycle through.

addLoadEvent

I would also like this function to be performed whenever the page loads, but I don't want to have to call it with a body onload function. I just want it to run as soon as the page is finished loading. Simon Willison created a function which can do just that. You only need to tell it which function you'd like to call, in my case it's the insertFramingTags function.

  1. function addLoadEvent(func) {
  2. var oldonload = window.onload;
  3. if (typeof window.onload != 'function') {
  4. window.onload = func;
  5. } else {
  6. window.onload = function() {
  7. if (oldonload) {
  8. oldonload();
  9. }
  10. func();
  11. }
  12. }
  13. }
  14.  
  15. addLoadEvent(insertFramingTags);

Inserting the Extra Markup Elements

Now all I have to do is insert the needed markup. I'll do this by creating a copy (or clone) of the original element and then re-insert it into the parent element that it came from along with all the other markup.

  1. function insertFramingTags(){
  2. var images = document.getElementsByClassName(FRAME_NAME);
  3. for (var i=0; i<images.length; i++) {
  4.  
  5. if (images[i].tagName == "IMG"){
  6.  
  7. // Create a copy of the original image and style up the new one
  8. var imageOld = images[i];
  9. var imageNew = imageOld.cloneNode(true);
  10.  
  11. //Create a new container div for the element
  12. var divObjParent = document.createElement("div");
  13. divObjParent.className = FRAME_NAME;
  14.  
  15. var divObjUpperLeft = document.createElement("div");
  16. divObjUpperLeft.className = "upper_left";
  17.  
  18. var divObjUpperRight = document.createElement("div");
  19. divObjUpperRight.className = "upper_right";
  20.  
  21. var divObjLowerLeft = document.createElement("div");
  22. divObjLowerLeft.className = "lower_left";
  23.  
  24. var divObjLowerRight = document.createElement("div");
  25. divObjLowerRight.className = "lower_right";
  26.  
  27.  
  28. //add in the image and frame corners
  29. divObjParent.appendChild(imageNew);
  30. divObjParent.appendChild(divObjUpperLeft);
  31. divObjParent.appendChild(divObjUpperRight);
  32. divObjParent.appendChild(divObjLowerRight);
  33. divObjParent.appendChild(divObjLowerLeft);
  34.  
  35. //Remove the old image
  36. var imageOldParent = imageOld.parentNode;
  37. imageOldParent.removeChild(imageOld);
  38.  
  39. //Insert the new one in its place
  40. imageOldParent.insertBefore(divObjParent, null);
  41. }
  42. }
  43. }

There are a couple of weeknesses of this function. The first is that it waits until the page is completely and totally loaded before it fires. Unfortunately if it tries to fire any sooner you could end up calling some elements on the page that javascript doesn't know exist yet. The other weekness is more important, (depending on this script's application). It cannot take an image element and put it precisely back where it was to begin with. It can only put it back immediately before its parent element's closing tag. This is the result of using the insertBefore method. If there is a better way of doing this please let me know.

posted in: Development |

Sean • Mar 4th 2008 • 10:58 am

Check out jQuery... I found it perfect for adding extra markup to particular classes.






Blog | About | Contact

Copyright © 2008 Exit 42 Design