views:

92

answers:

5

Hi...

Trying to add dynamic borders on my website top, left, and right sides... The pages on my site are dynamic... That is they change... I need to have a script that adapts a div to the webpage simply...

Anyone know this? I got this script from some guy on this forum, but I am trying to avoid jQuery (don't ask)...

<p class="bgr">Content content content</p>
<script type="text/javascript">
$('.bgr').each(function(i,el){
$('<div class="bgr_left"/>').height($(this).height()+'px').appendTo($(this));
// similar for top, right, and bottom
});
</script>
+4  A: 

Calculating dimensions in a cross-browser fashion (as the height() you're fetching and setting there) is an incredibly tedious task to do in plain JavaScript. That's, among other reasons, why libraries such as jQuery were built in the first place.

I'd strongly advise you NOT to do it without any framework - if you don't like jQuery, fine, but use another one.

Seb
+1 "for strongly advise you NOT to do it without any framework"
scunliffe
A: 

As many other people have said, you really shouldn't try to avoid jQuery. However, if you really want to, here's how to do it.


First, you'll need to find all of the elements that you want to add corners to. Your jQuery code is finding all elements with a className of bgr. You can't do that simply without third-party code. The simplest solution is to use a getElementsByClassName method.

Then, run the following code (where elems is an array of elements to add corners to):

for (var i = 0; i < elems.length; i++) {
    var outer = elems[i];

    var outerHeight = outer.offsetHeight, outerWidth = outer.offsetWidth;

    outer.innerHtml += '<div class="bgr_left" style="height:' + outerHeight + 'px" />'
        + '<div class="bgr_right" style="height:' + outerHeight + 'px" />'
        + //Etc...;
}

Note that this will re-create all of the elements inside the outer element (by resetting innerHtml); If you want to, you could use createElement and appendChild to avoid this.

SLaks
A: 

As SLaks mentioned you can use getElementsByClassName or you can use the Selector API, but you will need to get everything that has the class of interest.

http://webkit.org/blog/156/queryselector-and-queryselectorall/

For the loop, you can use a foreach function, look for it on this page: http://www.hunlock.com/blogs/Mastering_Javascript_Arrays

So you can have:

var list = document.querySelectorAll(".bgr");
list.foreach(function(i,el){
...
});

You will need a selector to find the div that you want to modify, and then you should set the height by setting style.height property, and appending the "px" to the end of the number is important.

Libraries abstract out the need to write these selectors, but you can write your own general purpose one. That is the main effort in your code.

For the foreach, the link I mentioned has code in case you are using this on a browser that doesn't support foreach.

James Black
+1  A: 

Without a JS framework, this will be mighty tedious.

Breaking it down, you are doing:

  • Find all elements with the CSS class "bgr" set
  • For each of them, append a div with the height set to the same rendered height of the item found.

1.) There is no standard getElementsByClass() function available in vanilla Javascript (newer browsers maybe).

2.) Obtaining the actual rendered height requires a mess of code because IE reports height differently than other browsers.

3.) Building and appending the new DIV isn't that hard, but is still much more complicated than the presented jQuery approach

<script>
  var matches = getElementsByClass('bgr');//you need to implement
  var match, CALCULATED_HEIGHT, newDiv;
  for(var i=0;i<matches.length;i++){
    match = matches[i];
    CALCULATED_HEIGHT = getRenderedHeight(match);//you need to implement
    newDiv = document.createElement('div');
    newDiv.setAttribute('className', 'bgr_left');//can't use 'class' due to IE bugs
    newDiv.style.height = CALCULATED_HEIGHT + 'px';//can't use setAttribute for 'style' due to IE bugs
    match.appendChild(newDiv);
  }
</script>
scunliffe
+1 for providing comments about IE bugs on top of everything else.
JamesEggers
@JamesEggers - no problem - it helps highlight why the JS frameworks are so helpful - they abstract the IE bug mess so that you don't need to know all the bugs/workarounds. That said, the more info passed around about the bugs, the more it helps those searching later trying to figure out why setAttribute() isn't working in IE. ;-)
scunliffe
Why are you using `setAttribute` in this example anyway? Why not just use the `className` property?
Tim Down
Generally speaking I like to use the DOM methods that are part of the ECMAScript specifications, since they *should* work universally for all attributes in all browsers. Its only IE's (up until IE8) inability to follow the specs that is the issue. In bigger applications I often have generic wrapper functions that build objects setting all kinds of attributes and events thus using a generic method like .setAttribute() is the ideal tool.
scunliffe
Using `setAttribute` on DOM elements in IE will cause you a lot more problems than using the equivalent properties. IE's implementation of `setAttribute` is broken (by design) and you can almost always avoid it.
Tim Down
Agreed. IE's implementation of setAttribute *was* horribly broken but in IE8 (Std's mode) it is all fixed (except for inline event handlers) thus they are moving towards standards (even if it is slow). My generic functions that use setAttribute therefore work in all browsers *except* IE6/7 - thus I have small tweaks to handle them. Otherwise my code is standards based, generic and will work for ages to come. Don't get me wrong, I know I could use things like obj.className but I'd rather not. Using a standard API for all attributes is far easier than having to "know" when to one vs. the other
scunliffe
I can't see the `className` property of DOM elements going away any time soon. I'd rather avoid the aggravation of detecting and maintaining a separate code path for a broken implementation of `setAttribute` when there's perfectly good alternatives that work consistently in all the mainstream browsers and are (and will remain) in widespread use.
Tim Down
A: 

Hopefully correct:

(function() {
    var elements = document.body.getElementsByTagName('*'),
        divLeft = document.createElement('div');

    divLeft.className = 'bgr_left';

    for(var i = elements.length; i--; ) {
        var current = elements[i];
        if(/(^|\s)bgr(\s|$)/.test(current.className)) {
            divLeft.style.height = current.offsetHeight + 'px';
            current.appendChild(divLeft.cloneNode(false));
        }
    }
})();

Check MDC and MSDN for further information on how to determine an elements dimensions.

Christoph